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.5';
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 urlImage = 'https://www.mapillary.com/map/im/',
20799 urlThumb = 'https://d1cuyjsrcm0gby.cloudfront.net/',
20800 clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi',
20805 function loadSignStyles(context) {
20806 d3.select('head').selectAll('#traffico')
20810 .attr('id', 'traffico')
20811 .attr('rel', 'stylesheet')
20812 .attr('href', context.asset('traffico/stylesheets/traffico.css'));
20815 function loadSignDefs(context) {
20816 if (!iD.services.mapillary.sign_defs) {
20817 iD.services.mapillary.sign_defs = {};
20818 _.each(['au', 'br', 'ca', 'de', 'us'], function(region) {
20819 d3.json(context.asset('traffico/string-maps/' + region + '-map.json'), function(err, data) {
20821 if (region === 'de') region = 'eu';
20822 iD.services.mapillary.sign_defs[region] = data;
20828 function abortRequest(i) {
20832 function nearNullIsland(x, y, z) {
20834 var center = Math.pow(2, z - 1),
20835 width = Math.pow(2, z - 6),
20836 min = center - (width / 2),
20837 max = center + (width / 2) - 1;
20838 return x >= min && x <= max && y >= min && y <= max;
20843 function getTiles(projection, dimensions) {
20844 var s = projection.scale() * 2 * Math.PI,
20845 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
20846 ts = 256 * Math.pow(2, z - tileZoom),
20848 s / 2 - projection.translate()[0],
20849 s / 2 - projection.translate()[1]];
20851 return d3.geo.tile()
20852 .scaleExtent([tileZoom, tileZoom])
20855 .translate(projection.translate())()
20856 .map(function(tile) {
20857 var x = tile[0] * ts - origin[0],
20858 y = tile[1] * ts - origin[1];
20861 id: tile.toString(),
20862 extent: iD.geo.Extent(
20863 projection.invert([x, y + ts]),
20864 projection.invert([x + ts, y]))
20870 function loadTiles(which, url, projection, dimensions) {
20871 var tiles = getTiles(projection, dimensions).filter(function(t) {
20872 var xyz = t.id.split(',');
20873 return !nearNullIsland(xyz[0], xyz[1], xyz[2]);
20876 _.filter(which.inflight, function(v, k) {
20877 var wanted = _.find(tiles, function(tile) { return k === (tile.id + ',0'); });
20878 if (!wanted) delete which.inflight[k];
20880 }).map(abortRequest);
20882 tiles.forEach(function(tile) {
20883 loadTilePage(which, url, tile, 0);
20887 function loadTilePage(which, url, tile, page) {
20888 var cache = iD.services.mapillary.cache[which],
20889 id = tile.id + ',' + String(page),
20890 rect = tile.extent.rectangle();
20892 if (cache.loaded[id] || cache.inflight[id]) return;
20894 cache.inflight[id] = d3.json(url +
20899 client_id: clientId,
20904 }), function(err, data) {
20905 cache.loaded[id] = true;
20906 delete cache.inflight[id];
20907 if (err || !data.features || !data.features.length) return;
20912 for (var i = 0; i < data.features.length; i++) {
20913 feature = data.features[i];
20914 loc = feature.geometry.coordinates;
20915 d = { key: feature.properties.key, loc: loc };
20916 if (which === 'images') d.ca = feature.properties.ca;
20917 if (which === 'signs') d.signs = feature.properties.rects;
20919 features.push([loc[0], loc[1], loc[0], loc[1], d]);
20922 cache.rtree.load(features);
20924 if (which === 'images') dispatch.loadedImages();
20925 if (which === 'signs') dispatch.loadedSigns();
20927 if (data.features.length === maxResults) {
20928 loadTilePage(which, url, tile, ++page);
20934 mapillary.loadImages = function(projection, dimensions) {
20935 var url = apibase + 'search/im/geojson?';
20936 loadTiles('images', url, projection, dimensions);
20939 mapillary.loadSigns = function(context, projection, dimensions) {
20940 var url = apibase + 'search/im/geojson/or?';
20941 loadSignStyles(context);
20942 loadSignDefs(context);
20943 loadTiles('signs', url, projection, dimensions);
20947 // partition viewport into `psize` x `psize` regions
20948 function partitionViewport(psize, projection, dimensions) {
20949 psize = psize || 16;
20950 var cols = d3.range(0, dimensions[0], psize),
20951 rows = d3.range(0, dimensions[1], psize),
20954 rows.forEach(function(y) {
20955 cols.forEach(function(x) {
20956 var min = [x, y + psize],
20957 max = [x + psize, y];
20959 iD.geo.Extent(projection.invert(min), projection.invert(max)));
20966 // no more than `limit` results per partition.
20967 function searchLimited(psize, limit, projection, dimensions, rtree) {
20968 limit = limit || 3;
20970 var partitions = partitionViewport(psize, projection, dimensions);
20971 return _.flatten(_.compact(_.map(partitions, function(extent) {
20972 return rtree.search(extent.rectangle())
20974 .map(function(d) { return d[4]; });
20978 mapillary.images = function(projection, dimensions) {
20979 var psize = 16, limit = 3;
20980 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.images.rtree);
20983 mapillary.signs = function(projection, dimensions) {
20984 var psize = 32, limit = 3;
20985 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.signs.rtree);
20988 mapillary.signsSupported = function() {
20989 var detected = iD.detect();
20990 return (!(detected.ie || detected.browser.toLowerCase() === 'safari'));
20993 mapillary.signHTML = function(d) {
20994 if (!iD.services.mapillary.sign_defs) return;
20996 var detectionPackage = d.signs[0].package,
20997 type = d.signs[0].type,
20998 country = detectionPackage.split('_')[1];
20999 return iD.services.mapillary.sign_defs[country][type];
21002 mapillary.showThumbnail = function(imageKey, position) {
21003 if (!imageKey) return;
21005 var positionClass = {
21006 'ar': (position !== 'left'),
21007 'al': (position === 'left')
21010 var thumbnail = d3.select('#content').selectAll('.mapillary-image')
21014 var enter = thumbnail.enter().append('div')
21015 .attr('class', 'mapillary-image ar');
21017 enter.append('button')
21018 .on('click', function () {
21019 mapillary.hideThumbnail();
21022 .call(iD.svg.Icon('#icon-close'));
21024 enter.append('img');
21027 .attr('class', 'link ar')
21028 .attr('target', '_blank')
21029 .call(iD.svg.Icon('#icon-out-link', 'inline'))
21031 .text(t('mapillary.view_on_mapillary'));
21034 thumbnail.selectAll('img')
21035 .attr('src', urlThumb + imageKey + '/thumb-320.jpg');
21037 var link = thumbnail.selectAll('a')
21038 .attr('href', urlImage + imageKey);
21041 thumbnail.classed(positionClass);
21042 link.classed(positionClass);
21048 .style('opacity', 1);
21051 mapillary.hideThumbnail = function() {
21052 if (iD.services.mapillary) {
21053 iD.services.mapillary.thumb = null;
21055 d3.select('#content').selectAll('.mapillary-image')
21058 .style('opacity', 0)
21062 mapillary.selectedThumbnail = function(d) {
21063 if (!iD.services.mapillary) return null;
21064 if (!arguments.length) return iD.services.mapillary.thumb;
21065 iD.services.mapillary.thumb = d;
21068 mapillary.reset = function() {
21069 var cache = iD.services.mapillary.cache;
21072 _.forEach(cache.images.inflight, abortRequest);
21073 _.forEach(cache.signs.inflight, abortRequest);
21076 iD.services.mapillary.cache = {
21077 images: { inflight: {}, loaded: {}, rtree: rbush() },
21078 signs: { inflight: {}, loaded: {}, rtree: rbush() }
21081 iD.services.mapillary.thumb = null;
21087 if (!iD.services.mapillary.cache) {
21091 return d3.rebind(mapillary, dispatch, 'on');
21093 iD.services.nominatim = function() {
21094 var nominatim = {},
21095 endpoint = 'https://nominatim.openstreetmap.org/reverse?';
21098 nominatim.countryCode = function(location, callback) {
21099 var cache = iD.services.nominatim.cache,
21100 countryCodes = cache.search([location[0], location[1], location[0], location[1]]);
21102 if (countryCodes.length > 0)
21103 return callback(null, countryCodes[0][4]);
21111 }), function(err, result) {
21113 return callback(err);
21114 else if (result && result.error)
21115 return callback(result.error);
21117 var extent = iD.geo.Extent(location).padByMeters(1000);
21119 cache.insert(extent.rectangle().concat(result.address.country_code));
21121 callback(null, result.address.country_code);
21125 nominatim.reset = function() {
21126 iD.services.nominatim.cache = rbush();
21131 if (!iD.services.nominatim.cache) {
21137 iD.services.taginfo = function() {
21139 endpoint = 'https://taginfo.openstreetmap.org/api/4/',
21141 point: 'count_nodes',
21142 vertex: 'count_nodes',
21143 area: 'count_ways',
21154 function sets(parameters, n, o) {
21155 if (parameters.geometry && o[parameters.geometry]) {
21156 parameters[n] = o[parameters.geometry];
21161 function setFilter(parameters) {
21162 return sets(parameters, 'filter', tag_filters);
21165 function setSort(parameters) {
21166 return sets(parameters, 'sortname', tag_sorts);
21169 function clean(parameters) {
21170 return _.omit(parameters, 'geometry', 'debounce');
21173 function filterKeys(type) {
21174 var count_type = type ? 'count_' + type : 'count_all';
21175 return function(d) {
21176 return parseFloat(d[count_type]) > 2500 || d.in_wiki;
21180 function filterMultikeys() {
21181 return function(d) {
21182 return (d.key.match(/:/g) || []).length === 1; // exactly one ':'
21186 function filterValues() {
21187 return function(d) {
21188 if (d.value.match(/[A-Z*;,]/) !== null) return false; // exclude some punctuation, uppercase letters
21189 return parseFloat(d.fraction) > 0.0 || d.in_wiki;
21193 function valKey(d) {
21200 function valKeyDescription(d) {
21203 title: d.description || d.value
21207 // sort keys with ':' lower than keys without ':'
21208 function sortKeys(a, b) {
21209 return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
21210 : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
21214 var debounced = _.debounce(d3.json, 100, true);
21216 function request(url, debounce, callback) {
21217 var cache = iD.services.taginfo.cache;
21220 callback(null, cache[url]);
21221 } else if (debounce) {
21222 debounced(url, done);
21224 d3.json(url, done);
21227 function done(err, data) {
21228 if (!err) cache[url] = data;
21229 callback(err, data);
21233 taginfo.keys = function(parameters, callback) {
21234 var debounce = parameters.debounce;
21235 parameters = clean(setSort(parameters));
21236 request(endpoint + 'keys/all?' +
21237 iD.util.qsString(_.extend({
21239 sortname: 'count_all',
21242 }, parameters)), debounce, function(err, d) {
21243 if (err) return callback(err);
21244 var f = filterKeys(parameters.filter);
21245 callback(null, d.data.filter(f).sort(sortKeys).map(valKey));
21249 taginfo.multikeys = function(parameters, callback) {
21250 var debounce = parameters.debounce;
21251 parameters = clean(setSort(parameters));
21252 request(endpoint + 'keys/all?' +
21253 iD.util.qsString(_.extend({
21255 sortname: 'count_all',
21258 }, parameters)), debounce, function(err, d) {
21259 if (err) return callback(err);
21260 var f = filterMultikeys();
21261 callback(null, d.data.filter(f).map(valKey));
21265 taginfo.values = function(parameters, callback) {
21266 var debounce = parameters.debounce;
21267 parameters = clean(setSort(setFilter(parameters)));
21268 request(endpoint + 'key/values?' +
21269 iD.util.qsString(_.extend({
21271 sortname: 'count_all',
21274 }, parameters)), debounce, function(err, d) {
21275 if (err) return callback(err);
21276 var f = filterValues();
21277 callback(null, d.data.filter(f).map(valKeyDescription));
21281 taginfo.docs = function(parameters, callback) {
21282 var debounce = parameters.debounce;
21283 parameters = clean(setSort(parameters));
21285 var path = 'key/wiki_pages?';
21286 if (parameters.value) path = 'tag/wiki_pages?';
21287 else if (parameters.rtype) path = 'relation/wiki_pages?';
21289 request(endpoint + path + iD.util.qsString(parameters), debounce, function(err, d) {
21290 if (err) return callback(err);
21291 callback(null, d.data);
21295 taginfo.endpoint = function(_) {
21296 if (!arguments.length) return endpoint;
21301 taginfo.reset = function() {
21302 iD.services.taginfo.cache = {};
21307 if (!iD.services.taginfo.cache) {
21313 iD.services.wikipedia = function() {
21315 endpoint = 'https://en.wikipedia.org/w/api.php?';
21317 wiki.search = function(lang, query, callback) {
21318 lang = lang || 'en';
21319 d3.jsonp(endpoint.replace('en', lang) +
21324 srinfo: 'suggestion',
21326 callback: '{callback}',
21328 }), function(data) {
21329 if (!data.query) return;
21330 callback(query, data.query.search.map(function(d) {
21336 wiki.suggestions = function(lang, query, callback) {
21337 lang = lang || 'en';
21338 d3.jsonp(endpoint.replace('en', lang) +
21340 action: 'opensearch',
21344 callback: '{callback}',
21347 callback(d[0], d[1]);
21351 wiki.translations = function(lang, title, callback) {
21352 d3.jsonp(endpoint.replace('en', lang) +
21357 callback: '{callback}',
21361 var list = d.query.pages[Object.keys(d.query.pages)[0]],
21363 if (list && list.langlinks) {
21364 list.langlinks.forEach(function(d) {
21365 translations[d.lang] = d['*'];
21367 callback(translations);
21376 iD.util.tagText = function(entity) {
21377 return d3.entries(entity.tags).map(function(e) {
21378 return e.key + '=' + e.value;
21382 iD.util.entitySelector = function(ids) {
21383 return ids.length ? '.' + ids.join(',.') : 'nothing';
21386 iD.util.entityOrMemberSelector = function(ids, graph) {
21387 var s = iD.util.entitySelector(ids);
21389 ids.forEach(function(id) {
21390 var entity = graph.hasEntity(id);
21391 if (entity && entity.type === 'relation') {
21392 entity.members.forEach(function(member) {
21393 s += ',.' + member.id;
21401 iD.util.displayName = function(entity) {
21402 var localeName = 'name:' + iD.detect().locale.toLowerCase().split('-')[0];
21403 return entity.tags[localeName] || entity.tags.name || entity.tags.ref;
21406 iD.util.displayType = function(id) {
21408 n: t('inspector.node'),
21409 w: t('inspector.way'),
21410 r: t('inspector.relation')
21414 iD.util.stringQs = function(str) {
21415 return str.split('&').reduce(function(obj, pair){
21416 var parts = pair.split('=');
21417 if (parts.length === 2) {
21418 obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
21424 iD.util.qsString = function(obj, noencode) {
21425 function softEncode(s) {
21426 // encode everything except special characters used in certain hash parameters:
21427 // "/" in map states, ":", ",", {" and "}" in background
21428 return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
21430 return Object.keys(obj).sort().map(function(key) {
21431 return encodeURIComponent(key) + '=' + (
21432 noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
21436 iD.util.prefixDOMProperty = function(property) {
21437 var prefixes = ['webkit', 'ms', 'moz', 'o'],
21439 n = prefixes.length,
21445 property = property.substr(0, 1).toUpperCase() + property.substr(1);
21448 if (prefixes[i] + property in s)
21449 return prefixes[i] + property;
21454 iD.util.prefixCSSProperty = function(property) {
21455 var prefixes = ['webkit', 'ms', 'Moz', 'O'],
21457 n = prefixes.length,
21458 s = document.body.style;
21460 if (property.toLowerCase() in s)
21461 return property.toLowerCase();
21464 if (prefixes[i] + property in s)
21465 return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
21471 iD.util.setTransform = function(el, x, y, scale) {
21472 var prop = iD.util.transformProperty = iD.util.transformProperty || iD.util.prefixCSSProperty('Transform'),
21473 translate = iD.detect().opera ?
21474 'translate(' + x + 'px,' + y + 'px)' :
21475 'translate3d(' + x + 'px,' + y + 'px,0)';
21476 return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
21479 iD.util.getStyle = function(selector) {
21480 for (var i = 0; i < document.styleSheets.length; i++) {
21481 var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules || [];
21482 for (var k = 0; k < rules.length; k++) {
21483 var selectorText = rules[k].selectorText && rules[k].selectorText.split(', ');
21484 if (_.includes(selectorText, selector)) {
21491 iD.util.editDistance = function(a, b) {
21492 if (a.length === 0) return b.length;
21493 if (b.length === 0) return a.length;
21495 for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
21496 for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
21497 for (i = 1; i <= b.length; i++) {
21498 for (j = 1; j <= a.length; j++) {
21499 if (b.charAt(i-1) === a.charAt(j-1)) {
21500 matrix[i][j] = matrix[i-1][j-1];
21502 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
21503 Math.min(matrix[i][j-1] + 1, // insertion
21504 matrix[i-1][j] + 1)); // deletion
21508 return matrix[b.length][a.length];
21511 // a d3.mouse-alike which
21512 // 1. Only works on HTML elements, not SVG
21513 // 2. Does not cause style recalculation
21514 iD.util.fastMouse = function(container) {
21515 var rect = container.getBoundingClientRect(),
21516 rectLeft = rect.left,
21517 rectTop = rect.top,
21518 clientLeft = +container.clientLeft,
21519 clientTop = +container.clientTop;
21520 return function(e) {
21522 e.clientX - rectLeft - clientLeft,
21523 e.clientY - rectTop - clientTop];
21527 /* eslint-disable no-proto */
21528 iD.util.getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
21529 /* eslint-enable no-proto */
21531 iD.util.asyncMap = function(inputs, func, callback) {
21532 var remaining = inputs.length,
21536 inputs.forEach(function(d, i) {
21537 func(d, function done(err, data) {
21541 if (!remaining) callback(errors, results);
21546 // wraps an index to an interval [0..length-1]
21547 iD.util.wrap = function(index, length) {
21549 index += Math.ceil(-index/length)*length;
21550 return index % length;
21552 // A per-domain session mutex backed by a cookie and dead man's
21553 // switch. If the session crashes, the mutex will auto-release
21554 // after 5 seconds.
21556 iD.util.SessionMutex = function(name) {
21561 var expires = new Date();
21562 expires.setSeconds(expires.getSeconds() + 5);
21563 document.cookie = name + '=1; expires=' + expires.toUTCString();
21566 mutex.lock = function() {
21567 if (intervalID) return true;
21568 var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
21569 if (cookie) return false;
21571 intervalID = window.setInterval(renew, 4000);
21575 mutex.unlock = function() {
21576 if (!intervalID) return;
21577 document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
21578 clearInterval(intervalID);
21582 mutex.locked = function() {
21583 return !!intervalID;
21588 iD.util.SuggestNames = function(preset, suggestions) {
21589 preset = preset.id.split('/', 2);
21593 return function(value, callback) {
21595 if (value && value.length > 2) {
21596 if (suggestions[k] && suggestions[k][v]) {
21597 for (var sugg in suggestions[k][v]) {
21598 var dist = iD.util.editDistance(value, sugg.substring(0, value.length));
21608 result.sort(function(a, b) {
21609 return a.dist - b.dist;
21612 result = result.slice(0,3);
21618 iD.geo.roundCoords = function(c) {
21619 return [Math.floor(c[0]), Math.floor(c[1])];
21622 iD.geo.interp = function(p1, p2, t) {
21623 return [p1[0] + (p2[0] - p1[0]) * t,
21624 p1[1] + (p2[1] - p1[1]) * t];
21627 // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
21628 // Returns a positive value, if OAB makes a counter-clockwise turn,
21629 // negative for clockwise turn, and zero if the points are collinear.
21630 iD.geo.cross = function(o, a, b) {
21631 return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
21634 // http://jsperf.com/id-dist-optimization
21635 iD.geo.euclideanDistance = function(a, b) {
21636 var x = a[0] - b[0], y = a[1] - b[1];
21637 return Math.sqrt((x * x) + (y * y));
21640 // using WGS84 polar radius (6356752.314245179 m)
21641 // const = 2 * PI * r / 360
21642 iD.geo.latToMeters = function(dLat) {
21643 return dLat * 110946.257617;
21646 // using WGS84 equatorial radius (6378137.0 m)
21647 // const = 2 * PI * r / 360
21648 iD.geo.lonToMeters = function(dLon, atLat) {
21649 return Math.abs(atLat) >= 90 ? 0 :
21650 dLon * 111319.490793 * Math.abs(Math.cos(atLat * (Math.PI/180)));
21653 // using WGS84 polar radius (6356752.314245179 m)
21654 // const = 2 * PI * r / 360
21655 iD.geo.metersToLat = function(m) {
21656 return m / 110946.257617;
21659 // using WGS84 equatorial radius (6378137.0 m)
21660 // const = 2 * PI * r / 360
21661 iD.geo.metersToLon = function(m, atLat) {
21662 return Math.abs(atLat) >= 90 ? 0 :
21663 m / 111319.490793 / Math.abs(Math.cos(atLat * (Math.PI/180)));
21666 iD.geo.offsetToMeters = function(offset) {
21667 var equatRadius = 6356752.314245179,
21668 polarRadius = 6378137.0,
21672 offset[0] * 2 * Math.PI * equatRadius / tileSize,
21673 -offset[1] * 2 * Math.PI * polarRadius / tileSize
21677 iD.geo.metersToOffset = function(meters) {
21678 var equatRadius = 6356752.314245179,
21679 polarRadius = 6378137.0,
21683 meters[0] * tileSize / (2 * Math.PI * equatRadius),
21684 -meters[1] * tileSize / (2 * Math.PI * polarRadius)
21688 // Equirectangular approximation of spherical distances on Earth
21689 iD.geo.sphericalDistance = function(a, b) {
21690 var x = iD.geo.lonToMeters(a[0] - b[0], (a[1] + b[1]) / 2),
21691 y = iD.geo.latToMeters(a[1] - b[1]);
21692 return Math.sqrt((x * x) + (y * y));
21695 iD.geo.edgeEqual = function(a, b) {
21696 return (a[0] === b[0] && a[1] === b[1]) ||
21697 (a[0] === b[1] && a[1] === b[0]);
21700 // Return the counterclockwise angle in the range (-pi, pi)
21701 // between the positive X axis and the line intersecting a and b.
21702 iD.geo.angle = function(a, b, projection) {
21703 a = projection(a.loc);
21704 b = projection(b.loc);
21705 return Math.atan2(b[1] - a[1], b[0] - a[0]);
21708 // Choose the edge with the minimal distance from `point` to its orthogonal
21709 // projection onto that edge, if such a projection exists, or the distance to
21710 // the closest vertex on that edge. Returns an object with the `index` of the
21711 // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
21712 iD.geo.chooseEdge = function(nodes, point, projection) {
21713 var dist = iD.geo.euclideanDistance,
21714 points = nodes.map(function(n) { return projection(n.loc); }),
21718 function dot(p, q) {
21719 return p[0] * q[0] + p[1] * q[1];
21722 for (var i = 0; i < points.length - 1; i++) {
21724 s = [points[i + 1][0] - o[0],
21725 points[i + 1][1] - o[1]],
21726 v = [point[0] - o[0],
21728 proj = dot(v, s) / dot(s, s),
21733 } else if (proj > 1) {
21736 p = [o[0] + proj * s[0], o[1] + proj * s[1]];
21739 var d = dist(p, point);
21743 loc = projection.invert(p);
21754 // Return the intersection point of 2 line segments.
21755 // From https://github.com/pgkelley4/line-segments-intersect
21756 // This uses the vector cross product approach described below:
21757 // http://stackoverflow.com/a/565282/786339
21758 iD.geo.lineIntersection = function(a, b) {
21759 function subtractPoints(point1, point2) {
21760 return [point1[0] - point2[0], point1[1] - point2[1]];
21762 function crossProduct(point1, point2) {
21763 return point1[0] * point2[1] - point1[1] * point2[0];
21766 var p = [a[0][0], a[0][1]],
21767 p2 = [a[1][0], a[1][1]],
21768 q = [b[0][0], b[0][1]],
21769 q2 = [b[1][0], b[1][1]],
21770 r = subtractPoints(p2, p),
21771 s = subtractPoints(q2, q),
21772 uNumerator = crossProduct(subtractPoints(q, p), r),
21773 denominator = crossProduct(r, s);
21775 if (uNumerator && denominator) {
21776 var u = uNumerator / denominator,
21777 t = crossProduct(subtractPoints(q, p), s) / denominator;
21779 if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
21780 return iD.geo.interp(p, p2, t);
21787 iD.geo.pathIntersections = function(path1, path2) {
21788 var intersections = [];
21789 for (var i = 0; i < path1.length - 1; i++) {
21790 for (var j = 0; j < path2.length - 1; j++) {
21791 var a = [ path1[i], path1[i+1] ],
21792 b = [ path2[j], path2[j+1] ],
21793 hit = iD.geo.lineIntersection(a, b);
21794 if (hit) intersections.push(hit);
21797 return intersections;
21800 // Return whether point is contained in polygon.
21802 // `point` should be a 2-item array of coordinates.
21803 // `polygon` should be an array of 2-item arrays of coordinates.
21805 // From https://github.com/substack/point-in-polygon.
21806 // ray-casting algorithm based on
21807 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
21809 iD.geo.pointInPolygon = function(point, polygon) {
21814 for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
21815 var xi = polygon[i][0], yi = polygon[i][1];
21816 var xj = polygon[j][0], yj = polygon[j][1];
21818 var intersect = ((yi > y) !== (yj > y)) &&
21819 (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
21820 if (intersect) inside = !inside;
21826 iD.geo.polygonContainsPolygon = function(outer, inner) {
21827 return _.every(inner, function(point) {
21828 return iD.geo.pointInPolygon(point, outer);
21832 iD.geo.polygonIntersectsPolygon = function(outer, inner, checkSegments) {
21833 function testSegments(outer, inner) {
21834 for (var i = 0; i < outer.length - 1; i++) {
21835 for (var j = 0; j < inner.length - 1; j++) {
21836 var a = [ outer[i], outer[i+1] ],
21837 b = [ inner[j], inner[j+1] ];
21838 if (iD.geo.lineIntersection(a, b)) return true;
21844 function testPoints(outer, inner) {
21845 return _.some(inner, function(point) {
21846 return iD.geo.pointInPolygon(point, outer);
21850 return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
21853 iD.geo.pathLength = function(path) {
21856 for (var i = 0; i < path.length - 1; i++) {
21857 dx = path[i][0] - path[i + 1][0];
21858 dy = path[i][1] - path[i + 1][1];
21859 length += Math.sqrt(dx * dx + dy * dy);
21863 iD.geo.Extent = function geoExtent(min, max) {
21864 if (!(this instanceof iD.geo.Extent)) return new iD.geo.Extent(min, max);
21865 if (min instanceof iD.geo.Extent) {
21867 } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
21871 this[0] = min || [ Infinity, Infinity];
21872 this[1] = max || min || [-Infinity, -Infinity];
21876 iD.geo.Extent.prototype = new Array(2);
21878 _.extend(iD.geo.Extent.prototype, {
21879 equals: function (obj) {
21880 return this[0][0] === obj[0][0] &&
21881 this[0][1] === obj[0][1] &&
21882 this[1][0] === obj[1][0] &&
21883 this[1][1] === obj[1][1];
21886 extend: function(obj) {
21887 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
21888 return iD.geo.Extent([Math.min(obj[0][0], this[0][0]),
21889 Math.min(obj[0][1], this[0][1])],
21890 [Math.max(obj[1][0], this[1][0]),
21891 Math.max(obj[1][1], this[1][1])]);
21894 _extend: function(extent) {
21895 this[0][0] = Math.min(extent[0][0], this[0][0]);
21896 this[0][1] = Math.min(extent[0][1], this[0][1]);
21897 this[1][0] = Math.max(extent[1][0], this[1][0]);
21898 this[1][1] = Math.max(extent[1][1], this[1][1]);
21902 return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
21905 center: function() {
21906 return [(this[0][0] + this[1][0]) / 2,
21907 (this[0][1] + this[1][1]) / 2];
21910 rectangle: function() {
21911 return [this[0][0], this[0][1], this[1][0], this[1][1]];
21914 polygon: function() {
21916 [this[0][0], this[0][1]],
21917 [this[0][0], this[1][1]],
21918 [this[1][0], this[1][1]],
21919 [this[1][0], this[0][1]],
21920 [this[0][0], this[0][1]]
21924 contains: function(obj) {
21925 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
21926 return obj[0][0] >= this[0][0] &&
21927 obj[0][1] >= this[0][1] &&
21928 obj[1][0] <= this[1][0] &&
21929 obj[1][1] <= this[1][1];
21932 intersects: function(obj) {
21933 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
21934 return obj[0][0] <= this[1][0] &&
21935 obj[0][1] <= this[1][1] &&
21936 obj[1][0] >= this[0][0] &&
21937 obj[1][1] >= this[0][1];
21940 intersection: function(obj) {
21941 if (!this.intersects(obj)) return new iD.geo.Extent();
21942 return new iD.geo.Extent([Math.max(obj[0][0], this[0][0]),
21943 Math.max(obj[0][1], this[0][1])],
21944 [Math.min(obj[1][0], this[1][0]),
21945 Math.min(obj[1][1], this[1][1])]);
21948 percentContainedIn: function(obj) {
21949 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
21950 var a1 = this.intersection(obj).area(),
21953 if (a1 === Infinity || a2 === Infinity || a1 === 0 || a2 === 0) {
21960 padByMeters: function(meters) {
21961 var dLat = iD.geo.metersToLat(meters),
21962 dLon = iD.geo.metersToLon(meters, this.center()[1]);
21963 return iD.geo.Extent(
21964 [this[0][0] - dLon, this[0][1] - dLat],
21965 [this[1][0] + dLon, this[1][1] + dLat]);
21968 toParam: function() {
21969 return this.rectangle().join(',');
21973 iD.geo.Turn = function(turn) {
21974 if (!(this instanceof iD.geo.Turn))
21975 return new iD.geo.Turn(turn);
21976 _.extend(this, turn);
21979 iD.geo.Intersection = function(graph, vertexId) {
21980 var vertex = graph.entity(vertexId),
21981 parentWays = graph.parentWays(vertex),
21985 function addHighway(way, adjacentNodeId) {
21986 if (highways[adjacentNodeId]) {
21987 coincident.push(adjacentNodeId);
21989 highways[adjacentNodeId] = way;
21993 // Pre-split ways that would need to be split in
21994 // order to add a restriction. The real split will
21995 // happen when the restriction is added.
21996 parentWays.forEach(function(way) {
21997 if (!way.tags.highway || way.isArea() || way.isDegenerate())
22000 var isFirst = (vertexId === way.first()),
22001 isLast = (vertexId === way.last()),
22002 isAffix = (isFirst || isLast),
22003 isClosingNode = (isFirst && isLast);
22005 if (isAffix && !isClosingNode) {
22006 var index = (isFirst ? 1 : way.nodes.length - 2);
22007 addHighway(way, way.nodes[index]);
22010 var splitIndex, wayA, wayB, indexA, indexB;
22011 if (isClosingNode) {
22012 splitIndex = Math.ceil(way.nodes.length / 2); // split at midpoint
22013 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
22014 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
22016 indexB = way.nodes.length - 2;
22018 splitIndex = _.indexOf(way.nodes, vertex.id, 1); // split at vertexid
22019 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
22020 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
22021 indexA = splitIndex - 1;
22022 indexB = splitIndex + 1;
22024 graph = graph.replace(wayA).replace(wayB);
22025 addHighway(wayA, way.nodes[indexA]);
22026 addHighway(wayB, way.nodes[indexB]);
22030 // remove any ways from this intersection that are coincident
22031 // (i.e. any adjacent node used by more than one intersecting way)
22032 coincident.forEach(function (n) {
22033 delete highways[n];
22037 var intersection = {
22038 highways: highways,
22039 ways: _.values(highways),
22043 intersection.adjacentNodeId = function(fromWayId) {
22044 return _.find(_.keys(highways), function(k) {
22045 return highways[k].id === fromWayId;
22049 intersection.turns = function(fromNodeId) {
22050 var start = highways[fromNodeId];
22054 if (start.first() === vertex.id && start.tags.oneway === 'yes')
22056 if (start.last() === vertex.id && start.tags.oneway === '-1')
22059 function withRestriction(turn) {
22060 graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
22061 if (relation.tags.type !== 'restriction')
22064 var f = relation.memberByRole('from'),
22065 t = relation.memberByRole('to'),
22066 v = relation.memberByRole('via');
22068 if (f && f.id === turn.from.way &&
22069 v && v.id === turn.via.node &&
22070 t && t.id === turn.to.way) {
22071 turn.restriction = relation.id;
22072 } else if (/^only_/.test(relation.tags.restriction) &&
22073 f && f.id === turn.from.way &&
22074 v && v.id === turn.via.node &&
22075 t && t.id !== turn.to.way) {
22076 turn.restriction = relation.id;
22077 turn.indirect_restriction = true;
22081 return iD.geo.Turn(turn);
22086 way: start.id.split(/-(a|b)/)[0]
22088 via = { node: vertex.id },
22091 _.each(highways, function(end, adjacentNodeId) {
22096 if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
22097 turns.push(withRestriction({
22101 node: adjacentNodeId,
22102 way: end.id.split(/-(a|b)/)[0]
22108 if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
22109 turns.push(withRestriction({
22113 node: adjacentNodeId,
22114 way: end.id.split(/-(a|b)/)[0]
22122 if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
22123 turns.push(withRestriction({
22134 return intersection;
22138 iD.geo.inferRestriction = function(graph, from, via, to, projection) {
22139 var fromWay = graph.entity(from.way),
22140 fromNode = graph.entity(from.node),
22141 toWay = graph.entity(to.way),
22142 toNode = graph.entity(to.node),
22143 viaNode = graph.entity(via.node),
22144 fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
22145 (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
22146 toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
22147 (toWay.tags.oneway === '-1' && toWay.last() === via.node),
22148 angle = iD.geo.angle(viaNode, fromNode, projection) -
22149 iD.geo.angle(viaNode, toNode, projection);
22151 angle = angle * 180 / Math.PI;
22156 if (fromNode === toNode)
22157 return 'no_u_turn';
22158 if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
22159 return 'no_u_turn';
22161 return 'no_right_turn';
22163 return 'no_left_turn';
22165 return 'no_straight_on';
22167 // For fixing up rendering of multipolygons with tags on the outer member.
22168 // https://github.com/openstreetmap/iD/issues/613
22169 iD.geo.isSimpleMultipolygonOuterMember = function(entity, graph) {
22170 if (entity.type !== 'way')
22173 var parents = graph.parentRelations(entity);
22174 if (parents.length !== 1)
22177 var parent = parents[0];
22178 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
22181 var members = parent.members, member;
22182 for (var i = 0; i < members.length; i++) {
22183 member = members[i];
22184 if (member.id === entity.id && member.role && member.role !== 'outer')
22185 return false; // Not outer member
22186 if (member.id !== entity.id && (!member.role || member.role === 'outer'))
22187 return false; // Not a simple multipolygon
22193 iD.geo.simpleMultipolygonOuterMember = function(entity, graph) {
22194 if (entity.type !== 'way')
22197 var parents = graph.parentRelations(entity);
22198 if (parents.length !== 1)
22201 var parent = parents[0];
22202 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
22205 var members = parent.members, member, outerMember;
22206 for (var i = 0; i < members.length; i++) {
22207 member = members[i];
22208 if (!member.role || member.role === 'outer') {
22210 return false; // Not a simple multipolygon
22211 outerMember = member;
22215 return outerMember && graph.hasEntity(outerMember.id);
22218 // Join `array` into sequences of connecting ways.
22220 // Segments which share identical start/end nodes will, as much as possible,
22221 // be connected with each other.
22223 // The return value is a nested array. Each constituent array contains elements
22224 // of `array` which have been determined to connect. Each consitituent array
22225 // also has a `nodes` property whose value is an ordered array of member nodes,
22226 // with appropriate order reversal and start/end coordinate de-duplication.
22228 // Members of `array` must have, at minimum, `type` and `id` properties.
22229 // Thus either an array of `iD.Way`s or a relation member array may be
22232 // If an member has a `tags` property, its tags will be reversed via
22233 // `iD.actions.Reverse` in the output.
22235 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
22236 // false) and non-way members are ignored.
22238 iD.geo.joinWays = function(array, graph) {
22239 var joined = [], member, current, nodes, first, last, i, how, what;
22241 array = array.filter(function(member) {
22242 return member.type === 'way' && graph.hasEntity(member.id);
22245 function resolve(member) {
22246 return graph.childNodes(graph.entity(member.id));
22249 function reverse(member) {
22250 return member.tags ? iD.actions.Reverse(member.id, {reverseOneway: true})(graph).entity(member.id) : member;
22253 while (array.length) {
22254 member = array.shift();
22255 current = [member];
22256 current.nodes = nodes = resolve(member).slice();
22257 joined.push(current);
22259 while (array.length && _.first(nodes) !== _.last(nodes)) {
22260 first = _.first(nodes);
22261 last = _.last(nodes);
22263 for (i = 0; i < array.length; i++) {
22265 what = resolve(member);
22267 if (last === _.first(what)) {
22269 what = what.slice(1);
22271 } else if (last === _.last(what)) {
22273 what = what.slice(0, -1).reverse();
22274 member = reverse(member);
22276 } else if (first === _.last(what)) {
22277 how = nodes.unshift;
22278 what = what.slice(0, -1);
22280 } else if (first === _.first(what)) {
22281 how = nodes.unshift;
22282 what = what.slice(1).reverse();
22283 member = reverse(member);
22291 break; // No more joinable ways.
22293 how.apply(current, [member]);
22294 how.apply(nodes, what);
22296 array.splice(i, 1);
22303 Bypasses features of D3's default projection stream pipeline that are unnecessary:
22304 * Antimeridian clipping
22305 * Spherical rotation
22308 iD.geo.RawMercator = function () {
22309 var project = d3.geo.mercator.raw,
22310 k = 512 / Math.PI, // scale
22311 x = 0, y = 0, // translate
22312 clipExtent = [[0, 0], [0, 0]];
22314 function projection(point) {
22315 point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
22316 return [point[0] * k + x, y - point[1] * k];
22319 projection.invert = function(point) {
22320 point = project.invert((point[0] - x) / k, (y - point[1]) / k);
22321 return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
22324 projection.scale = function(_) {
22325 if (!arguments.length) return k;
22330 projection.translate = function(_) {
22331 if (!arguments.length) return [x, y];
22337 projection.clipExtent = function(_) {
22338 if (!arguments.length) return clipExtent;
22343 projection.stream = d3.geo.transform({
22344 point: function(x, y) {
22345 x = projection([x, y]);
22346 this.stream.point(x[0], x[1]);
22353 iD.actions.AddEntity = function(way) {
22354 return function(graph) {
22355 return graph.replace(way);
22358 iD.actions.AddMember = function(relationId, member, memberIndex) {
22359 return function(graph) {
22360 var relation = graph.entity(relationId);
22362 if (isNaN(memberIndex) && member.type === 'way') {
22363 var members = relation.indexedMembers();
22364 members.push(member);
22366 var joined = iD.geo.joinWays(members, graph);
22367 for (var i = 0; i < joined.length; i++) {
22368 var segment = joined[i];
22369 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
22370 if (segment[j] !== member)
22374 memberIndex = segment[j + 1].index;
22375 } else if (j === segment.length - 1) {
22376 memberIndex = segment[j - 1].index + 1;
22378 memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
22384 return graph.replace(relation.addMember(member, memberIndex));
22387 iD.actions.AddMidpoint = function(midpoint, node) {
22388 return function(graph) {
22389 graph = graph.replace(node.move(midpoint.loc));
22391 var parents = _.intersection(
22392 graph.parentWays(graph.entity(midpoint.edge[0])),
22393 graph.parentWays(graph.entity(midpoint.edge[1])));
22395 parents.forEach(function(way) {
22396 for (var i = 0; i < way.nodes.length - 1; i++) {
22397 if (iD.geo.edgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
22398 graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
22400 // Add only one midpoint on doubled-back segments,
22401 // turning them into self-intersections.
22410 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
22411 iD.actions.AddVertex = function(wayId, nodeId, index) {
22412 return function(graph) {
22413 return graph.replace(graph.entity(wayId).addNode(nodeId, index));
22416 iD.actions.ChangeMember = function(relationId, member, memberIndex) {
22417 return function(graph) {
22418 return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
22421 iD.actions.ChangePreset = function(entityId, oldPreset, newPreset) {
22422 return function(graph) {
22423 var entity = graph.entity(entityId),
22424 geometry = entity.geometry(graph),
22425 tags = entity.tags;
22427 if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
22428 if (newPreset) tags = newPreset.applyTags(tags, geometry);
22430 return graph.replace(entity.update({tags: tags}));
22433 iD.actions.ChangeTags = function(entityId, tags) {
22434 return function(graph) {
22435 var entity = graph.entity(entityId);
22436 return graph.replace(entity.update({tags: tags}));
22439 iD.actions.Circularize = function(wayId, projection, maxAngle) {
22440 maxAngle = (maxAngle || 20) * Math.PI / 180;
22442 var action = function(graph) {
22443 var way = graph.entity(wayId);
22445 if (!way.isConvex(graph)) {
22446 graph = action.makeConvex(graph);
22449 var nodes = _.uniq(graph.childNodes(way)),
22450 keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
22451 points = nodes.map(function(n) { return projection(n.loc); }),
22452 keyPoints = keyNodes.map(function(n) { return projection(n.loc); }),
22453 centroid = (points.length === 2) ? iD.geo.interp(points[0], points[1], 0.5) : d3.geom.polygon(points).centroid(),
22454 radius = d3.median(points, function(p) { return iD.geo.euclideanDistance(centroid, p); }),
22455 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
22458 // we need atleast two key nodes for the algorithm to work
22459 if (!keyNodes.length) {
22460 keyNodes = [nodes[0]];
22461 keyPoints = [points[0]];
22464 if (keyNodes.length === 1) {
22465 var index = nodes.indexOf(keyNodes[0]),
22466 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
22468 keyNodes.push(nodes[oppositeIndex]);
22469 keyPoints.push(points[oppositeIndex]);
22472 // key points and nodes are those connected to the ways,
22473 // they are projected onto the circle, inbetween nodes are moved
22474 // to constant intervals between key nodes, extra inbetween nodes are
22475 // added if necessary.
22476 for (var i = 0; i < keyPoints.length; i++) {
22477 var nextKeyNodeIndex = (i + 1) % keyNodes.length,
22478 startNode = keyNodes[i],
22479 endNode = keyNodes[nextKeyNodeIndex],
22480 startNodeIndex = nodes.indexOf(startNode),
22481 endNodeIndex = nodes.indexOf(endNode),
22482 numberNewPoints = -1,
22483 indexRange = endNodeIndex - startNodeIndex,
22484 distance, totalAngle, eachAngle, startAngle, endAngle,
22485 angle, loc, node, j,
22486 inBetweenNodes = [];
22488 if (indexRange < 0) {
22489 indexRange += nodes.length;
22492 // position this key node
22493 distance = iD.geo.euclideanDistance(centroid, keyPoints[i]);
22494 if (distance === 0) { distance = 1e-4; }
22496 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius,
22497 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
22498 graph = graph.replace(keyNodes[i].move(projection.invert(keyPoints[i])));
22500 // figure out the between delta angle we want to match to
22501 startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
22502 endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
22503 totalAngle = endAngle - startAngle;
22505 // detects looping around -pi/pi
22506 if (totalAngle * sign > 0) {
22507 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
22512 eachAngle = totalAngle / (indexRange + numberNewPoints);
22513 } while (Math.abs(eachAngle) > maxAngle);
22515 // move existing points
22516 for (j = 1; j < indexRange; j++) {
22517 angle = startAngle + j * eachAngle;
22518 loc = projection.invert([
22519 centroid[0] + Math.cos(angle)*radius,
22520 centroid[1] + Math.sin(angle)*radius]);
22522 node = nodes[(j + startNodeIndex) % nodes.length].move(loc);
22523 graph = graph.replace(node);
22526 // add new inbetween nodes if necessary
22527 for (j = 0; j < numberNewPoints; j++) {
22528 angle = startAngle + (indexRange + j) * eachAngle;
22529 loc = projection.invert([
22530 centroid[0] + Math.cos(angle) * radius,
22531 centroid[1] + Math.sin(angle) * radius]);
22533 node = iD.Node({loc: loc});
22534 graph = graph.replace(node);
22536 nodes.splice(endNodeIndex + j, 0, node);
22537 inBetweenNodes.push(node.id);
22540 // Check for other ways that share these keyNodes..
22541 // If keyNodes are adjacent in both ways,
22542 // we can add inBetween nodes to that shared way too..
22543 if (indexRange === 1 && inBetweenNodes.length) {
22544 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
22545 endIndex1 = way.nodes.lastIndexOf(endNode.id),
22546 wayDirection1 = (endIndex1 - startIndex1);
22547 if (wayDirection1 < -1) { wayDirection1 = 1; }
22549 /* eslint-disable no-loop-func */
22550 _.each(_.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
22551 if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
22552 var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
22553 endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
22554 wayDirection2 = (endIndex2 - startIndex2),
22555 insertAt = endIndex2;
22556 if (wayDirection2 < -1) { wayDirection2 = 1; }
22558 if (wayDirection1 !== wayDirection2) {
22559 inBetweenNodes.reverse();
22560 insertAt = startIndex2;
22562 for (j = 0; j < inBetweenNodes.length; j++) {
22563 sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
22565 graph = graph.replace(sharedWay);
22568 /* eslint-enable no-loop-func */
22573 // update the way to have all the new nodes
22574 ids = nodes.map(function(n) { return n.id; });
22577 way = way.update({nodes: ids});
22578 graph = graph.replace(way);
22583 action.makeConvex = function(graph) {
22584 var way = graph.entity(wayId),
22585 nodes = _.uniq(graph.childNodes(way)),
22586 points = nodes.map(function(n) { return projection(n.loc); }),
22587 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
22588 hull = d3.geom.hull(points);
22590 // D3 convex hulls go counterclockwise..
22596 for (var i = 0; i < hull.length - 1; i++) {
22597 var startIndex = points.indexOf(hull[i]),
22598 endIndex = points.indexOf(hull[i+1]),
22599 indexRange = (endIndex - startIndex);
22601 if (indexRange < 0) {
22602 indexRange += nodes.length;
22605 // move interior nodes to the surface of the convex hull..
22606 for (var j = 1; j < indexRange; j++) {
22607 var point = iD.geo.interp(hull[i], hull[i+1], j / indexRange),
22608 node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
22609 graph = graph.replace(node);
22615 action.disabled = function(graph) {
22616 if (!graph.entity(wayId).isClosed())
22617 return 'not_closed';
22622 // Connect the ways at the given nodes.
22624 // The last node will survive. All other nodes will be replaced with
22625 // the surviving node in parent ways, and then removed.
22627 // Tags and relation memberships of of non-surviving nodes are merged
22628 // to the survivor.
22630 // This is the inverse of `iD.actions.Disconnect`.
22633 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
22634 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
22636 iD.actions.Connect = function(nodeIds) {
22637 return function(graph) {
22638 var survivor = graph.entity(_.last(nodeIds));
22640 for (var i = 0; i < nodeIds.length - 1; i++) {
22641 var node = graph.entity(nodeIds[i]);
22643 /* eslint-disable no-loop-func */
22644 graph.parentWays(node).forEach(function(parent) {
22645 if (!parent.areAdjacent(node.id, survivor.id)) {
22646 graph = graph.replace(parent.replaceNode(node.id, survivor.id));
22650 graph.parentRelations(node).forEach(function(parent) {
22651 graph = graph.replace(parent.replaceMember(node, survivor));
22653 /* eslint-enable no-loop-func */
22655 survivor = survivor.mergeTags(node.tags);
22656 graph = iD.actions.DeleteNode(node.id)(graph);
22659 graph = graph.replace(survivor);
22664 iD.actions.CopyEntities = function(ids, fromGraph) {
22667 var action = function(graph) {
22668 ids.forEach(function(id) {
22669 fromGraph.entity(id).copy(fromGraph, copies);
22672 for (var id in copies) {
22673 graph = graph.replace(copies[id]);
22679 action.copies = function() {
22685 iD.actions.DeleteMember = function(relationId, memberIndex) {
22686 return function(graph) {
22687 var relation = graph.entity(relationId)
22688 .removeMember(memberIndex);
22690 graph = graph.replace(relation);
22692 if (relation.isDegenerate())
22693 graph = iD.actions.DeleteRelation(relation.id)(graph);
22698 iD.actions.DeleteMultiple = function(ids) {
22700 way: iD.actions.DeleteWay,
22701 node: iD.actions.DeleteNode,
22702 relation: iD.actions.DeleteRelation
22705 var action = function(graph) {
22706 ids.forEach(function(id) {
22707 if (graph.hasEntity(id)) { // It may have been deleted aready.
22708 graph = actions[graph.entity(id).type](id)(graph);
22715 action.disabled = function(graph) {
22716 for (var i = 0; i < ids.length; i++) {
22718 disabled = actions[graph.entity(id).type](id).disabled(graph);
22719 if (disabled) return disabled;
22725 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
22726 iD.actions.DeleteNode = function(nodeId) {
22727 var action = function(graph) {
22728 var node = graph.entity(nodeId);
22730 graph.parentWays(node)
22731 .forEach(function(parent) {
22732 parent = parent.removeNode(nodeId);
22733 graph = graph.replace(parent);
22735 if (parent.isDegenerate()) {
22736 graph = iD.actions.DeleteWay(parent.id)(graph);
22740 graph.parentRelations(node)
22741 .forEach(function(parent) {
22742 parent = parent.removeMembersWithID(nodeId);
22743 graph = graph.replace(parent);
22745 if (parent.isDegenerate()) {
22746 graph = iD.actions.DeleteRelation(parent.id)(graph);
22750 return graph.remove(node);
22753 action.disabled = function() {
22759 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
22760 iD.actions.DeleteRelation = function(relationId) {
22761 function deleteEntity(entity, graph) {
22762 return !graph.parentWays(entity).length &&
22763 !graph.parentRelations(entity).length &&
22764 !entity.hasInterestingTags();
22767 var action = function(graph) {
22768 var relation = graph.entity(relationId);
22770 graph.parentRelations(relation)
22771 .forEach(function(parent) {
22772 parent = parent.removeMembersWithID(relationId);
22773 graph = graph.replace(parent);
22775 if (parent.isDegenerate()) {
22776 graph = iD.actions.DeleteRelation(parent.id)(graph);
22780 _.uniq(_.map(relation.members, 'id')).forEach(function(memberId) {
22781 graph = graph.replace(relation.removeMembersWithID(memberId));
22783 var entity = graph.entity(memberId);
22784 if (deleteEntity(entity, graph)) {
22785 graph = iD.actions.DeleteMultiple([memberId])(graph);
22789 return graph.remove(relation);
22792 action.disabled = function(graph) {
22793 if (!graph.entity(relationId).isComplete(graph))
22794 return 'incomplete_relation';
22799 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
22800 iD.actions.DeleteWay = function(wayId) {
22801 function deleteNode(node, graph) {
22802 return !graph.parentWays(node).length &&
22803 !graph.parentRelations(node).length &&
22804 !node.hasInterestingTags();
22807 var action = function(graph) {
22808 var way = graph.entity(wayId);
22810 graph.parentRelations(way)
22811 .forEach(function(parent) {
22812 parent = parent.removeMembersWithID(wayId);
22813 graph = graph.replace(parent);
22815 if (parent.isDegenerate()) {
22816 graph = iD.actions.DeleteRelation(parent.id)(graph);
22820 _.uniq(way.nodes).forEach(function(nodeId) {
22821 graph = graph.replace(way.removeNode(nodeId));
22823 var node = graph.entity(nodeId);
22824 if (deleteNode(node, graph)) {
22825 graph = graph.remove(node);
22829 return graph.remove(way);
22832 action.disabled = function(graph) {
22833 var disabled = false;
22835 graph.parentRelations(graph.entity(wayId)).forEach(function(parent) {
22836 var type = parent.tags.type,
22837 role = parent.memberById(wayId).role || 'outer';
22838 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
22839 disabled = 'part_of_relation';
22848 iD.actions.DeprecateTags = function(entityId) {
22849 return function(graph) {
22850 var entity = graph.entity(entityId),
22851 newtags = _.clone(entity.tags),
22855 // This handles deprecated tags with a single condition
22856 for (var i = 0; i < iD.data.deprecated.length; i++) {
22858 rule = iD.data.deprecated[i];
22859 var match = _.toPairs(rule.old)[0],
22860 replacements = rule.replace ? _.toPairs(rule.replace) : null;
22862 if (entity.tags[match[0]] && match[1] === '*') {
22864 var value = entity.tags[match[0]];
22865 if (replacements && !newtags[replacements[0][0]]) {
22866 newtags[replacements[0][0]] = value;
22868 delete newtags[match[0]];
22871 } else if (entity.tags[match[0]] === match[1]) {
22872 newtags = _.assign({}, rule.replace || {}, _.omit(newtags, match[0]));
22878 return graph.replace(entity.update({tags: newtags}));
22884 iD.actions.DiscardTags = function(difference) {
22885 return function(graph) {
22886 function discardTags(entity) {
22887 if (!_.isEmpty(entity.tags)) {
22889 _.each(entity.tags, function(v, k) {
22890 if (v) tags[k] = v;
22893 graph = graph.replace(entity.update({
22894 tags: _.omit(tags, iD.data.discarded)
22899 difference.modified().forEach(discardTags);
22900 difference.created().forEach(discardTags);
22905 // Disconect the ways at the given node.
22907 // Optionally, disconnect only the given ways.
22909 // For testing convenience, accepts an ID to assign to the (first) new node.
22910 // Normally, this will be undefined and the way will automatically
22911 // be assigned a new ID.
22913 // This is the inverse of `iD.actions.Connect`.
22916 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
22917 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
22919 iD.actions.Disconnect = function(nodeId, newNodeId) {
22922 var action = function(graph) {
22923 var node = graph.entity(nodeId),
22924 connections = action.connections(graph);
22926 connections.forEach(function(connection) {
22927 var way = graph.entity(connection.wayID),
22928 newNode = iD.Node({id: newNodeId, loc: node.loc, tags: node.tags});
22930 graph = graph.replace(newNode);
22931 if (connection.index === 0 && way.isArea()) {
22932 // replace shared node with shared node..
22933 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
22935 // replace shared node with multiple new nodes..
22936 graph = graph.replace(way.updateNode(newNode.id, connection.index));
22943 action.connections = function(graph) {
22944 var candidates = [],
22946 parentWays = graph.parentWays(graph.entity(nodeId));
22948 parentWays.forEach(function(way) {
22949 if (wayIds && wayIds.indexOf(way.id) === -1) {
22953 if (way.isArea() && (way.nodes[0] === nodeId)) {
22954 candidates.push({wayID: way.id, index: 0});
22956 way.nodes.forEach(function(waynode, index) {
22957 if (waynode === nodeId) {
22958 candidates.push({wayID: way.id, index: index});
22964 return keeping ? candidates : candidates.slice(1);
22967 action.disabled = function(graph) {
22968 var connections = action.connections(graph);
22969 if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
22970 return 'not_connected';
22972 var parentWays = graph.parentWays(graph.entity(nodeId)),
22973 seenRelationIds = {},
22976 parentWays.forEach(function(way) {
22977 if (wayIds && wayIds.indexOf(way.id) === -1)
22980 var relations = graph.parentRelations(way);
22981 relations.forEach(function(relation) {
22982 if (relation.id in seenRelationIds) {
22983 sharedRelation = relation;
22985 seenRelationIds[relation.id] = true;
22990 if (sharedRelation)
22994 action.limitWays = function(_) {
22995 if (!arguments.length) return wayIds;
23002 // Join ways at the end node they share.
23004 // This is the inverse of `iD.actions.Split`.
23007 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
23008 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
23010 iD.actions.Join = function(ids) {
23012 function groupEntitiesByGeometry(graph) {
23013 var entities = ids.map(function(id) { return graph.entity(id); });
23014 return _.extend({line: []}, _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
23017 var action = function(graph) {
23018 var ways = ids.map(graph.entity, graph),
23019 survivor = ways[0];
23021 // Prefer to keep an existing way.
23022 for (var i = 0; i < ways.length; i++) {
23023 if (!ways[i].isNew()) {
23024 survivor = ways[i];
23029 var joined = iD.geo.joinWays(ways, graph)[0];
23031 survivor = survivor.update({nodes: _.map(joined.nodes, 'id')});
23032 graph = graph.replace(survivor);
23034 joined.forEach(function(way) {
23035 if (way.id === survivor.id)
23038 graph.parentRelations(way).forEach(function(parent) {
23039 graph = graph.replace(parent.replaceMember(way, survivor));
23042 survivor = survivor.mergeTags(way.tags);
23044 graph = graph.replace(survivor);
23045 graph = iD.actions.DeleteWay(way.id)(graph);
23051 action.disabled = function(graph) {
23052 var geometries = groupEntitiesByGeometry(graph);
23053 if (ids.length < 2 || ids.length !== geometries.line.length)
23054 return 'not_eligible';
23056 var joined = iD.geo.joinWays(ids.map(graph.entity, graph), graph);
23057 if (joined.length > 1)
23058 return 'not_adjacent';
23060 var nodeIds = _.map(joined[0].nodes, 'id').slice(1, -1),
23063 conflicting = false;
23065 joined[0].forEach(function(way) {
23066 var parents = graph.parentRelations(way);
23067 parents.forEach(function(parent) {
23068 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
23072 for (var k in way.tags) {
23073 if (!(k in tags)) {
23074 tags[k] = way.tags[k];
23075 } else if (tags[k] && iD.interestingTag(k) && tags[k] !== way.tags[k]) {
23076 conflicting = true;
23082 return 'restriction';
23085 return 'conflicting_tags';
23090 iD.actions.Merge = function(ids) {
23091 function groupEntitiesByGeometry(graph) {
23092 var entities = ids.map(function(id) { return graph.entity(id); });
23093 return _.extend({point: [], area: [], line: [], relation: []},
23094 _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
23097 var action = function(graph) {
23098 var geometries = groupEntitiesByGeometry(graph),
23099 target = geometries.area[0] || geometries.line[0],
23100 points = geometries.point;
23102 points.forEach(function(point) {
23103 target = target.mergeTags(point.tags);
23105 graph.parentRelations(point).forEach(function(parent) {
23106 graph = graph.replace(parent.replaceMember(point, target));
23109 graph = graph.remove(point);
23112 graph = graph.replace(target);
23117 action.disabled = function(graph) {
23118 var geometries = groupEntitiesByGeometry(graph);
23119 if (geometries.point.length === 0 ||
23120 (geometries.area.length + geometries.line.length) !== 1 ||
23121 geometries.relation.length !== 0)
23122 return 'not_eligible';
23127 iD.actions.MergePolygon = function(ids, newRelationId) {
23129 function groupEntities(graph) {
23130 var entities = ids.map(function (id) { return graph.entity(id); });
23135 }, _.groupBy(entities, function(entity) {
23136 if (entity.type === 'way' && entity.isClosed()) {
23137 return 'closedWay';
23138 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
23139 return 'multipolygon';
23146 var action = function(graph) {
23147 var entities = groupEntities(graph);
23149 // An array representing all the polygons that are part of the multipolygon.
23151 // Each element is itself an array of objects with an id property, and has a
23152 // locs property which is an array of the locations forming the polygon.
23153 var polygons = entities.multipolygon.reduce(function(polygons, m) {
23154 return polygons.concat(iD.geo.joinWays(m.members, graph));
23155 }, []).concat(entities.closedWay.map(function(d) {
23156 var member = [{id: d.id}];
23157 member.nodes = graph.childNodes(d);
23161 // contained is an array of arrays of boolean values,
23162 // where contained[j][k] is true iff the jth way is
23163 // contained by the kth way.
23164 var contained = polygons.map(function(w, i) {
23165 return polygons.map(function(d, n) {
23166 if (i === n) return null;
23167 return iD.geo.polygonContainsPolygon(
23168 _.map(d.nodes, 'loc'),
23169 _.map(w.nodes, 'loc'));
23173 // Sort all polygons as either outer or inner ways
23177 while (polygons.length) {
23178 extractUncontained(polygons);
23179 polygons = polygons.filter(isContained);
23180 contained = contained.filter(isContained).map(filterContained);
23183 function isContained(d, i) {
23184 return _.some(contained[i]);
23187 function filterContained(d) {
23188 return d.filter(isContained);
23191 function extractUncontained(polygons) {
23192 polygons.forEach(function(d, i) {
23193 if (!isContained(d, i)) {
23194 d.forEach(function(member) {
23198 role: outer ? 'outer' : 'inner'
23206 // Move all tags to one relation
23207 var relation = entities.multipolygon[0] ||
23208 iD.Relation({ id: newRelationId, tags: { type: 'multipolygon' }});
23210 entities.multipolygon.slice(1).forEach(function(m) {
23211 relation = relation.mergeTags(m.tags);
23212 graph = graph.remove(m);
23215 entities.closedWay.forEach(function(way) {
23216 function isThisOuter(m) {
23217 return m.id === way.id && m.role !== 'inner';
23219 if (members.some(isThisOuter)) {
23220 relation = relation.mergeTags(way.tags);
23221 graph = graph.replace(way.update({ tags: {} }));
23225 return graph.replace(relation.update({
23227 tags: _.omit(relation.tags, 'area')
23231 action.disabled = function(graph) {
23232 var entities = groupEntities(graph);
23233 if (entities.other.length > 0 ||
23234 entities.closedWay.length + entities.multipolygon.length < 2)
23235 return 'not_eligible';
23236 if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
23237 return 'incomplete_relation';
23242 iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser) {
23243 var option = 'safe', // 'safe', 'force_local', 'force_remote'
23247 return _.isFunction(formatUser) ? formatUser(d) : d;
23251 function mergeLocation(remote, target) {
23252 function pointEqual(a, b) {
23253 var epsilon = 1e-6;
23254 return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
23257 if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
23260 if (option === 'force_remote') {
23261 return target.update({loc: remote.loc});
23264 conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
23269 function mergeNodes(base, remote, target) {
23270 if (option === 'force_local' || _.isEqual(target.nodes, remote.nodes)) {
23273 if (option === 'force_remote') {
23274 return target.update({nodes: remote.nodes});
23277 var ccount = conflicts.length,
23278 o = base.nodes || [],
23279 a = target.nodes || [],
23280 b = remote.nodes || [],
23282 hunks = Diff3.diff3_merge(a, o, b, true);
23284 for (var i = 0; i < hunks.length; i++) {
23285 var hunk = hunks[i];
23287 nodes.push.apply(nodes, hunk.ok);
23289 // for all conflicts, we can assume c.a !== c.b
23290 // because `diff3_merge` called with `true` option to exclude false conflicts..
23291 var c = hunk.conflict;
23292 if (_.isEqual(c.o, c.a)) { // only changed remotely
23293 nodes.push.apply(nodes, c.b);
23294 } else if (_.isEqual(c.o, c.b)) { // only changed locally
23295 nodes.push.apply(nodes, c.a);
23296 } else { // changed both locally and remotely
23297 conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
23303 return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
23307 function mergeChildren(targetWay, children, updates, graph) {
23308 function isUsed(node, targetWay) {
23309 var parentWays = _.map(graph.parentWays(node), 'id');
23310 return node.hasInterestingTags() ||
23311 _.without(parentWays, targetWay.id).length > 0 ||
23312 graph.parentRelations(node).length > 0;
23315 var ccount = conflicts.length;
23317 for (var i = 0; i < children.length; i++) {
23318 var id = children[i],
23319 node = graph.hasEntity(id);
23321 // remove unused childNodes..
23322 if (targetWay.nodes.indexOf(id) === -1) {
23323 if (node && !isUsed(node, targetWay)) {
23324 updates.removeIds.push(id);
23329 // restore used childNodes..
23330 var local = localGraph.hasEntity(id),
23331 remote = remoteGraph.hasEntity(id),
23334 if (option === 'force_remote' && remote && remote.visible) {
23335 updates.replacements.push(remote);
23337 } else if (option === 'force_local' && local) {
23338 target = iD.Entity(local);
23340 target = target.update({ version: remote.version });
23342 updates.replacements.push(target);
23344 } else if (option === 'safe' && local && remote && local.version !== remote.version) {
23345 target = iD.Entity(local, { version: remote.version });
23346 if (remote.visible) {
23347 target = mergeLocation(remote, target);
23349 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
23352 if (conflicts.length !== ccount) break;
23353 updates.replacements.push(target);
23361 function updateChildren(updates, graph) {
23362 for (var i = 0; i < updates.replacements.length; i++) {
23363 graph = graph.replace(updates.replacements[i]);
23365 if (updates.removeIds.length) {
23366 graph = iD.actions.DeleteMultiple(updates.removeIds)(graph);
23372 function mergeMembers(remote, target) {
23373 if (option === 'force_local' || _.isEqual(target.members, remote.members)) {
23376 if (option === 'force_remote') {
23377 return target.update({members: remote.members});
23380 conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
23385 function mergeTags(base, remote, target) {
23386 function ignoreKey(k) {
23387 return _.includes(iD.data.discarded, k);
23390 if (option === 'force_local' || _.isEqual(target.tags, remote.tags)) {
23393 if (option === 'force_remote') {
23394 return target.update({tags: remote.tags});
23397 var ccount = conflicts.length,
23398 o = base.tags || {},
23399 a = target.tags || {},
23400 b = remote.tags || {},
23401 keys = _.reject(_.union(_.keys(o), _.keys(a), _.keys(b)), ignoreKey),
23405 for (var i = 0; i < keys.length; i++) {
23408 if (o[k] !== b[k] && a[k] !== b[k]) { // changed remotely..
23409 if (o[k] !== a[k]) { // changed locally..
23410 conflicts.push(t('merge_remote_changes.conflict.tags',
23411 { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
23413 } else { // unchanged locally, accept remote change..
23414 if (b.hasOwnProperty(k)) {
23424 return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
23428 // `graph.base()` is the common ancestor of the two graphs.
23429 // `localGraph` contains user's edits up to saving
23430 // `remoteGraph` contains remote edits to modified nodes
23431 // `graph` must be a descendent of `localGraph` and may include
23432 // some conflict resolution actions performed on it.
23434 // --- ... --- `localGraph` -- ... -- `graph`
23436 // `graph.base()` --- ... --- `remoteGraph`
23438 var action = function(graph) {
23439 var updates = { replacements: [], removeIds: [] },
23440 base = graph.base().entities[id],
23441 local = localGraph.entity(id),
23442 remote = remoteGraph.entity(id),
23443 target = iD.Entity(local, { version: remote.version });
23446 if (!remote.visible) {
23447 if (option === 'force_remote') {
23448 return iD.actions.DeleteMultiple([id])(graph);
23450 } else if (option === 'force_local') {
23451 if (target.type === 'way') {
23452 target = mergeChildren(target, _.uniq(local.nodes), updates, graph);
23453 graph = updateChildren(updates, graph);
23455 return graph.replace(target);
23458 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
23459 return graph; // do nothing
23464 if (target.type === 'node') {
23465 target = mergeLocation(remote, target);
23467 } else if (target.type === 'way') {
23468 // pull in any child nodes that may not be present locally..
23469 graph.rebase(remoteGraph.childNodes(remote), [graph], false);
23470 target = mergeNodes(base, remote, target);
23471 target = mergeChildren(target, _.union(local.nodes, remote.nodes), updates, graph);
23473 } else if (target.type === 'relation') {
23474 target = mergeMembers(remote, target);
23477 target = mergeTags(base, remote, target);
23479 if (!conflicts.length) {
23480 graph = updateChildren(updates, graph).replace(target);
23486 action.withOption = function(opt) {
23491 action.conflicts = function() {
23497 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
23498 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
23499 iD.actions.Move = function(moveIds, tryDelta, projection, cache) {
23500 var delta = tryDelta;
23502 function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
23503 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
23505 function setupCache(graph) {
23506 function canMove(nodeId) {
23507 var parents = _.map(graph.parentWays(graph.entity(nodeId)), 'id');
23508 if (parents.length < 3) return true;
23510 // Don't move a vertex where >2 ways meet, unless all parentWays are moving too..
23511 var parentsMoving = _.all(parents, function(id) { return cache.moving[id]; });
23512 if (!parentsMoving) delete cache.moving[nodeId];
23514 return parentsMoving;
23517 function cacheEntities(ids) {
23518 _.each(ids, function(id) {
23519 if (cache.moving[id]) return;
23520 cache.moving[id] = true;
23522 var entity = graph.hasEntity(id);
23523 if (!entity) return;
23525 if (entity.type === 'node') {
23526 cache.nodes.push(id);
23527 cache.startLoc[id] = entity.loc;
23528 } else if (entity.type === 'way') {
23529 cache.ways.push(id);
23530 cacheEntities(entity.nodes);
23532 cacheEntities(_.map(entity.members, 'id'));
23537 function cacheIntersections(ids) {
23538 function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
23540 _.each(ids, function(id) {
23541 // consider only intersections with 1 moved and 1 unmoved way.
23542 _.each(graph.childNodes(graph.entity(id)), function(node) {
23543 var parents = graph.parentWays(node);
23544 if (parents.length !== 2) return;
23546 var moved = graph.entity(id),
23547 unmoved = _.find(parents, function(way) { return !cache.moving[way.id]; });
23548 if (!unmoved) return;
23550 // exclude ways that are overly connected..
23551 if (_.intersection(moved.nodes, unmoved.nodes).length > 2) return;
23553 if (moved.isArea() || unmoved.isArea()) return;
23555 cache.intersection[node.id] = {
23558 unmovedId: unmoved.id,
23559 movedIsEP: isEndpoint(moved, node.id),
23560 unmovedIsEP: isEndpoint(unmoved, node.id)
23572 cache.intersection = {};
23573 cache.replacedVertex = {};
23574 cache.startLoc = {};
23578 cacheEntities(moveIds);
23579 cacheIntersections(cache.ways);
23580 cache.nodes = _.filter(cache.nodes, canMove);
23587 // Place a vertex where the moved vertex used to be, to preserve way shape..
23588 function replaceMovedVertex(nodeId, wayId, graph, delta) {
23589 var way = graph.entity(wayId),
23590 moved = graph.entity(nodeId),
23591 movedIndex = way.nodes.indexOf(nodeId),
23592 len, prevIndex, nextIndex;
23594 if (way.isClosed()) {
23595 len = way.nodes.length - 1;
23596 prevIndex = (movedIndex + len - 1) % len;
23597 nextIndex = (movedIndex + len + 1) % len;
23599 len = way.nodes.length;
23600 prevIndex = movedIndex - 1;
23601 nextIndex = movedIndex + 1;
23604 var prev = graph.hasEntity(way.nodes[prevIndex]),
23605 next = graph.hasEntity(way.nodes[nextIndex]);
23607 // Don't add orig vertex at endpoint..
23608 if (!prev || !next) return graph;
23610 var key = wayId + '_' + nodeId,
23611 orig = cache.replacedVertex[key];
23614 cache.replacedVertex[key] = orig;
23615 cache.startLoc[orig.id] = cache.startLoc[nodeId];
23620 start = projection(cache.startLoc[nodeId]);
23621 end = projection.invert(vecAdd(start, delta));
23623 end = cache.startLoc[nodeId];
23625 orig = orig.move(end);
23627 var angle = Math.abs(iD.geo.angle(orig, prev, projection) -
23628 iD.geo.angle(orig, next, projection)) * 180 / Math.PI;
23630 // Don't add orig vertex if it would just make a straight line..
23631 if (angle > 175 && angle < 185) return graph;
23633 // Don't add orig vertex if another point is already nearby (within 10m)
23634 if (iD.geo.sphericalDistance(prev.loc, orig.loc) < 10 ||
23635 iD.geo.sphericalDistance(orig.loc, next.loc) < 10) return graph;
23637 // moving forward or backward along way?
23638 var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
23639 p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
23640 d1 = iD.geo.pathLength(p1),
23641 d2 = iD.geo.pathLength(p2),
23642 insertAt = (d1 < d2) ? movedIndex : nextIndex;
23644 // moving around closed loop?
23645 if (way.isClosed() && insertAt === 0) insertAt = len;
23647 way = way.addNode(orig.id, insertAt);
23648 return graph.replace(orig).replace(way);
23651 // Reorder nodes around intersections that have moved..
23652 function unZorroIntersection(intersection, graph) {
23653 var vertex = graph.entity(intersection.nodeId),
23654 way1 = graph.entity(intersection.movedId),
23655 way2 = graph.entity(intersection.unmovedId),
23656 isEP1 = intersection.movedIsEP,
23657 isEP2 = intersection.unmovedIsEP;
23659 // don't move the vertex if it is the endpoint of both ways.
23660 if (isEP1 && isEP2) return graph;
23662 var nodes1 = _.without(graph.childNodes(way1), vertex),
23663 nodes2 = _.without(graph.childNodes(way2), vertex);
23665 if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
23666 if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
23668 var edge1 = !isEP1 && iD.geo.chooseEdge(nodes1, projection(vertex.loc), projection),
23669 edge2 = !isEP2 && iD.geo.chooseEdge(nodes2, projection(vertex.loc), projection),
23672 // snap vertex to nearest edge (or some point between them)..
23673 if (!isEP1 && !isEP2) {
23674 var epsilon = 1e-4, maxIter = 10;
23675 for (var i = 0; i < maxIter; i++) {
23676 loc = iD.geo.interp(edge1.loc, edge2.loc, 0.5);
23677 edge1 = iD.geo.chooseEdge(nodes1, projection(loc), projection);
23678 edge2 = iD.geo.chooseEdge(nodes2, projection(loc), projection);
23679 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
23681 } else if (!isEP1) {
23687 graph = graph.replace(vertex.move(loc));
23689 // if zorro happened, reorder nodes..
23690 if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
23691 way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
23692 graph = graph.replace(way1);
23694 if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
23695 way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
23696 graph = graph.replace(way2);
23703 function cleanupIntersections(graph) {
23704 _.each(cache.intersection, function(obj) {
23705 graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
23706 graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
23707 graph = unZorroIntersection(obj, graph);
23713 // check if moving way endpoint can cross an unmoved way, if so limit delta..
23714 function limitDelta(graph) {
23715 _.each(cache.intersection, function(obj) {
23716 if (!obj.movedIsEP) return;
23718 var node = graph.entity(obj.nodeId),
23719 start = projection(node.loc),
23720 end = vecAdd(start, delta),
23721 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
23722 movedPath = _.map(_.map(movedNodes, 'loc'),
23723 function(loc) { return vecAdd(projection(loc), delta); }),
23724 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
23725 unmovedPath = _.map(_.map(unmovedNodes, 'loc'), projection),
23726 hits = iD.geo.pathIntersections(movedPath, unmovedPath);
23728 for (var i = 0; i < hits.length; i++) {
23729 if (_.isEqual(hits[i], end)) continue;
23730 var edge = iD.geo.chooseEdge(unmovedNodes, end, projection);
23731 delta = vecSub(projection(edge.loc), start);
23737 var action = function(graph) {
23738 if (delta[0] === 0 && delta[1] === 0) return graph;
23742 if (!_.isEmpty(cache.intersection)) {
23746 _.each(cache.nodes, function(id) {
23747 var node = graph.entity(id),
23748 start = projection(node.loc),
23749 end = vecAdd(start, delta);
23750 graph = graph.replace(node.move(projection.invert(end)));
23753 if (!_.isEmpty(cache.intersection)) {
23754 graph = cleanupIntersections(graph);
23760 action.disabled = function(graph) {
23761 function incompleteRelation(id) {
23762 var entity = graph.entity(id);
23763 return entity.type === 'relation' && !entity.isComplete(graph);
23766 if (_.some(moveIds, incompleteRelation))
23767 return 'incomplete_relation';
23770 action.delta = function() {
23776 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
23777 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
23778 iD.actions.MoveNode = function(nodeId, loc) {
23779 return function(graph) {
23780 return graph.replace(graph.entity(nodeId).move(loc));
23783 iD.actions.Noop = function() {
23784 return function(graph) {
23789 * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
23792 iD.actions.Orthogonalize = function(wayId, projection) {
23793 var threshold = 12, // degrees within right or straight to alter
23794 lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
23795 upperThreshold = Math.cos(threshold * Math.PI / 180);
23797 var action = function(graph) {
23798 var way = graph.entity(wayId),
23799 nodes = graph.childNodes(way),
23800 points = _.uniq(nodes).map(function(n) { return projection(n.loc); }),
23801 corner = {i: 0, dotp: 1},
23803 i, j, score, motions;
23805 if (nodes.length === 4) {
23806 for (i = 0; i < 1000; i++) {
23807 motions = points.map(calcMotion);
23808 points[corner.i] = addPoints(points[corner.i],motions[corner.i]);
23809 score = corner.dotp;
23810 if (score < epsilon) {
23815 graph = graph.replace(graph.entity(nodes[corner.i].id)
23816 .move(projection.invert(points[corner.i])));
23819 originalPoints = _.clone(points);
23822 for (i = 0; i < 1000; i++) {
23823 motions = points.map(calcMotion);
23824 for (j = 0; j < motions.length; j++) {
23825 points[j] = addPoints(points[j],motions[j]);
23827 var newScore = squareness(points);
23828 if (newScore < score) {
23829 best = _.clone(points);
23832 if (score < epsilon) {
23839 for (i = 0; i < points.length; i++) {
23840 // only move the points that actually moved
23841 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
23842 graph = graph.replace(graph.entity(nodes[i].id)
23843 .move(projection.invert(points[i])));
23847 // remove empty nodes on straight sections
23848 for (i = 0; i < points.length; i++) {
23849 var node = nodes[i];
23851 if (graph.parentWays(node).length > 1 ||
23852 graph.parentRelations(node).length ||
23853 node.hasInterestingTags()) {
23858 var dotp = normalizedDotProduct(i, points);
23859 if (dotp < -1 + epsilon) {
23860 graph = iD.actions.DeleteNode(nodes[i].id)(graph);
23867 function calcMotion(b, i, array) {
23868 var a = array[(i - 1 + array.length) % array.length],
23869 c = array[(i + 1) % array.length],
23870 p = subtractPoints(a, b),
23871 q = subtractPoints(c, b),
23874 scale = 2 * Math.min(iD.geo.euclideanDistance(p, [0, 0]), iD.geo.euclideanDistance(q, [0, 0]));
23875 p = normalizePoint(p, 1.0);
23876 q = normalizePoint(q, 1.0);
23878 dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
23880 // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
23881 if (array.length > 3) {
23882 if (dotp < -0.707106781186547) {
23885 } else if (dotp && Math.abs(dotp) < corner.dotp) {
23887 corner.dotp = Math.abs(dotp);
23890 return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
23894 function squareness(points) {
23895 return points.reduce(function(sum, val, i, array) {
23896 var dotp = normalizedDotProduct(i, array);
23898 dotp = filterDotProduct(dotp);
23899 return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
23903 function normalizedDotProduct(i, points) {
23904 var a = points[(i - 1 + points.length) % points.length],
23906 c = points[(i + 1) % points.length],
23907 p = subtractPoints(a, b),
23908 q = subtractPoints(c, b);
23910 p = normalizePoint(p, 1.0);
23911 q = normalizePoint(q, 1.0);
23913 return p[0] * q[0] + p[1] * q[1];
23916 function subtractPoints(a, b) {
23917 return [a[0] - b[0], a[1] - b[1]];
23920 function addPoints(a, b) {
23921 return [a[0] + b[0], a[1] + b[1]];
23924 function normalizePoint(point, scale) {
23925 var vector = [0, 0];
23926 var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
23927 if (length !== 0) {
23928 vector[0] = point[0] / length;
23929 vector[1] = point[1] / length;
23932 vector[0] *= scale;
23933 vector[1] *= scale;
23938 function filterDotProduct(dotp) {
23939 if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
23946 action.disabled = function(graph) {
23947 var way = graph.entity(wayId),
23948 nodes = graph.childNodes(way),
23949 points = _.uniq(nodes).map(function(n) { return projection(n.loc); });
23951 if (squareness(points)) {
23955 return 'not_squarish';
23960 // Create a restriction relation for `turn`, which must have the following structure:
23963 // from: { node: <node ID>, way: <way ID> },
23964 // via: { node: <node ID> },
23965 // to: { node: <node ID>, way: <way ID> },
23966 // restriction: <'no_right_turn', 'no_left_turn', etc.>
23969 // This specifies a restriction of type `restriction` when traveling from
23970 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
23971 // (The action does not check that these entities form a valid intersection.)
23973 // If `restriction` is not provided, it is automatically determined by
23974 // iD.geo.inferRestriction.
23976 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
23977 // and `to.node` are used to determine which portion of the split ways become
23978 // members of the restriction.
23980 // For testing convenience, accepts an ID to assign to the new relation.
23981 // Normally, this will be undefined and the relation will automatically
23982 // be assigned a new ID.
23984 iD.actions.RestrictTurn = function(turn, projection, restrictionId) {
23985 return function(graph) {
23986 var from = graph.entity(turn.from.way),
23987 via = graph.entity(turn.via.node),
23988 to = graph.entity(turn.to.way);
23990 function isClosingNode(way, nodeId) {
23991 return nodeId === way.first() && nodeId === way.last();
23994 function split(toOrFrom) {
23995 var newID = toOrFrom.newID || iD.Way().id;
23996 graph = iD.actions.Split(via.id, [newID])
23997 .limitWays([toOrFrom.way])(graph);
23999 var a = graph.entity(newID),
24000 b = graph.entity(toOrFrom.way);
24002 if (a.nodes.indexOf(toOrFrom.node) !== -1) {
24009 if (!from.affix(via.id) || isClosingNode(from, via.id)) {
24010 if (turn.from.node === turn.to.node) {
24012 from = to = split(turn.from)[0];
24013 } else if (turn.from.way === turn.to.way) {
24014 // Straight-on or circular
24015 var s = split(turn.from);
24020 from = split(turn.from)[0];
24024 if (!to.affix(via.id) || isClosingNode(to, via.id)) {
24025 to = split(turn.to)[0];
24028 return graph.replace(iD.Relation({
24031 type: 'restriction',
24032 restriction: turn.restriction ||
24033 iD.geo.inferRestriction(
24041 {id: from.id, type: 'way', role: 'from'},
24042 {id: via.id, type: 'node', role: 'via'},
24043 {id: to.id, type: 'way', role: 'to'}
24049 Order the nodes of a way in reverse order and reverse any direction dependent tags
24050 other than `oneway`. (We assume that correcting a backwards oneway is the primary
24051 reason for reversing a way.)
24053 The following transforms are performed:
24056 *:right=* ⟺ *:left=*
24057 *:forward=* ⟺ *:backward=*
24058 direction=up ⟺ direction=down
24059 incline=up ⟺ incline=down
24063 role=forward ⟺ role=backward
24064 role=north ⟺ role=south
24065 role=east ⟺ role=west
24067 In addition, numeric-valued `incline` tags are negated.
24069 The JOSM implementation was used as a guide, but transformations that were of unclear benefit
24070 or adjusted tags that don't seem to be used in practice were omitted.
24073 http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
24074 http://wiki.openstreetmap.org/wiki/Key:direction#Steps
24075 http://wiki.openstreetmap.org/wiki/Key:incline
24076 http://wiki.openstreetmap.org/wiki/Route#Members
24077 http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
24079 iD.actions.Reverse = function(wayId, options) {
24080 var replacements = [
24081 [/:right$/, ':left'], [/:left$/, ':right'],
24082 [/:forward$/, ':backward'], [/:backward$/, ':forward']
24084 numeric = /^([+\-]?)(?=[\d.])/,
24086 forward: 'backward',
24087 backward: 'forward',
24094 function reverseKey(key) {
24095 for (var i = 0; i < replacements.length; ++i) {
24096 var replacement = replacements[i];
24097 if (replacement[0].test(key)) {
24098 return key.replace(replacement[0], replacement[1]);
24104 function reverseValue(key, value) {
24105 if (key === 'incline' && numeric.test(value)) {
24106 return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
24107 } else if (key === 'incline' || key === 'direction') {
24108 return {up: 'down', down: 'up'}[value] || value;
24109 } else if (options && options.reverseOneway && key === 'oneway') {
24110 return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
24112 return {left: 'right', right: 'left'}[value] || value;
24116 return function(graph) {
24117 var way = graph.entity(wayId),
24118 nodes = way.nodes.slice().reverse(),
24119 tags = {}, key, role;
24121 for (key in way.tags) {
24122 tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
24125 graph.parentRelations(way).forEach(function(relation) {
24126 relation.members.forEach(function(member, index) {
24127 if (member.id === way.id && (role = roleReversals[member.role])) {
24128 relation = relation.updateMember({role: role}, index);
24129 graph = graph.replace(relation);
24134 return graph.replace(way.update({nodes: nodes, tags: tags}));
24137 iD.actions.Revert = function(id) {
24139 var action = function(graph) {
24140 var entity = graph.hasEntity(id),
24141 base = graph.base().entities[id];
24143 if (entity && !base) { // entity will be removed..
24144 if (entity.type === 'node') {
24145 graph.parentWays(entity)
24146 .forEach(function(parent) {
24147 parent = parent.removeNode(id);
24148 graph = graph.replace(parent);
24150 if (parent.isDegenerate()) {
24151 graph = iD.actions.DeleteWay(parent.id)(graph);
24156 graph.parentRelations(entity)
24157 .forEach(function(parent) {
24158 parent = parent.removeMembersWithID(id);
24159 graph = graph.replace(parent);
24161 if (parent.isDegenerate()) {
24162 graph = iD.actions.DeleteRelation(parent.id)(graph);
24167 return graph.revert(id);
24172 iD.actions.RotateWay = function(wayId, pivot, angle, projection) {
24173 return function(graph) {
24174 return graph.update(function(graph) {
24175 var way = graph.entity(wayId);
24177 _.uniq(way.nodes).forEach(function(id) {
24179 var node = graph.entity(id),
24180 point = projection(node.loc),
24183 radial[0] = point[0] - pivot[0];
24184 radial[1] = point[1] - pivot[1];
24187 radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + pivot[0],
24188 radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + pivot[1]
24191 graph = graph.replace(node.move(projection.invert(point)));
24198 // Split a way at the given node.
24200 // Optionally, split only the given ways, if multiple ways share
24203 // This is the inverse of `iD.actions.Join`.
24205 // For testing convenience, accepts an ID to assign to the new way.
24206 // Normally, this will be undefined and the way will automatically
24207 // be assigned a new ID.
24210 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
24212 iD.actions.Split = function(nodeId, newWayIds) {
24215 // if the way is closed, we need to search for a partner node
24216 // to split the way at.
24218 // The following looks for a node that is both far away from
24219 // the initial node in terms of way segment length and nearby
24220 // in terms of beeline-distance. This assures that areas get
24221 // split on the most "natural" points (independent of the number
24223 // For example: bone-shaped areas get split across their waist
24224 // line, circles across the diameter.
24225 function splitArea(nodes, idxA, graph) {
24226 var lengths = new Array(nodes.length),
24232 function wrap(index) {
24233 return iD.util.wrap(index, nodes.length);
24236 function dist(nA, nB) {
24237 return iD.geo.sphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
24240 // calculate lengths
24242 for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
24243 length += dist(nodes[i], nodes[wrap(i-1)]);
24244 lengths[i] = length;
24248 for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
24249 length += dist(nodes[i], nodes[wrap(i+1)]);
24250 if (length < lengths[i])
24251 lengths[i] = length;
24254 // determine best opposite node to split
24255 for (i = 0; i < nodes.length; i++) {
24256 var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
24266 function split(graph, wayA, newWayId) {
24267 var wayB = iD.Way({id: newWayId, tags: wayA.tags}),
24270 isArea = wayA.isArea(),
24271 isOuter = iD.geo.isSimpleMultipolygonOuterMember(wayA, graph);
24273 if (wayA.isClosed()) {
24274 var nodes = wayA.nodes.slice(0, -1),
24275 idxA = _.indexOf(nodes, nodeId),
24276 idxB = splitArea(nodes, idxA, graph);
24279 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
24280 nodesB = nodes.slice(idxB, idxA + 1);
24282 nodesA = nodes.slice(idxA, idxB + 1);
24283 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
24286 var idx = _.indexOf(wayA.nodes, nodeId, 1);
24287 nodesA = wayA.nodes.slice(0, idx + 1);
24288 nodesB = wayA.nodes.slice(idx);
24291 wayA = wayA.update({nodes: nodesA});
24292 wayB = wayB.update({nodes: nodesB});
24294 graph = graph.replace(wayA);
24295 graph = graph.replace(wayB);
24297 graph.parentRelations(wayA).forEach(function(relation) {
24298 if (relation.isRestriction()) {
24299 var via = relation.memberByRole('via');
24300 if (via && wayB.contains(via.id)) {
24301 relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
24302 graph = graph.replace(relation);
24305 if (relation === isOuter) {
24306 graph = graph.replace(relation.mergeTags(wayA.tags));
24307 graph = graph.replace(wayA.update({tags: {}}));
24308 graph = graph.replace(wayB.update({tags: {}}));
24314 role: relation.memberById(wayA.id).role
24317 graph = iD.actions.AddMember(relation.id, member)(graph);
24321 if (!isOuter && isArea) {
24322 var multipolygon = iD.Relation({
24323 tags: _.extend({}, wayA.tags, {type: 'multipolygon'}),
24325 {id: wayA.id, role: 'outer', type: 'way'},
24326 {id: wayB.id, role: 'outer', type: 'way'}
24329 graph = graph.replace(multipolygon);
24330 graph = graph.replace(wayA.update({tags: {}}));
24331 graph = graph.replace(wayB.update({tags: {}}));
24337 var action = function(graph) {
24338 var candidates = action.ways(graph);
24339 for (var i = 0; i < candidates.length; i++) {
24340 graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
24345 action.ways = function(graph) {
24346 var node = graph.entity(nodeId),
24347 parents = graph.parentWays(node),
24348 hasLines = _.some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
24350 return parents.filter(function(parent) {
24351 if (wayIds && wayIds.indexOf(parent.id) === -1)
24354 if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
24357 if (parent.isClosed()) {
24361 for (var i = 1; i < parent.nodes.length - 1; i++) {
24362 if (parent.nodes[i] === nodeId) {
24371 action.disabled = function(graph) {
24372 var candidates = action.ways(graph);
24373 if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
24374 return 'not_eligible';
24377 action.limitWays = function(_) {
24378 if (!arguments.length) return wayIds;
24386 * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
24389 iD.actions.Straighten = function(wayId, projection) {
24390 function positionAlongWay(n, s, e) {
24391 return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1]))/
24392 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
24395 var action = function(graph) {
24396 var way = graph.entity(wayId),
24397 nodes = graph.childNodes(way),
24398 points = nodes.map(function(n) { return projection(n.loc); }),
24399 startPoint = points[0],
24400 endPoint = points[points.length-1],
24404 for (i = 1; i < points.length-1; i++) {
24405 var node = nodes[i],
24408 if (graph.parentWays(node).length > 1 ||
24409 graph.parentRelations(node).length ||
24410 node.hasInterestingTags()) {
24412 var u = positionAlongWay(point, startPoint, endPoint),
24413 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
24414 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]);
24416 graph = graph.replace(graph.entity(node.id)
24417 .move(projection.invert([p0, p1])));
24420 if (toDelete.indexOf(node) === -1) {
24421 toDelete.push(node);
24426 for (i = 0; i < toDelete.length; i++) {
24427 graph = iD.actions.DeleteNode(toDelete[i].id)(graph);
24433 action.disabled = function(graph) {
24434 // check way isn't too bendy
24435 var way = graph.entity(wayId),
24436 nodes = graph.childNodes(way),
24437 points = nodes.map(function(n) { return projection(n.loc); }),
24438 startPoint = points[0],
24439 endPoint = points[points.length-1],
24440 threshold = 0.2 * Math.sqrt(Math.pow(startPoint[0] - endPoint[0], 2) + Math.pow(startPoint[1] - endPoint[1], 2)),
24443 if (threshold === 0) {
24444 return 'too_bendy';
24447 for (i = 1; i < points.length-1; i++) {
24448 var point = points[i],
24449 u = positionAlongWay(point, startPoint, endPoint),
24450 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
24451 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
24452 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
24454 // to bendy if point is off by 20% of total start/end distance in projected space
24455 if (isNaN(dist) || dist > threshold) {
24456 return 'too_bendy';
24463 // Remove the effects of `turn.restriction` on `turn`, which must have the
24464 // following structure:
24467 // from: { node: <node ID>, way: <way ID> },
24468 // via: { node: <node ID> },
24469 // to: { node: <node ID>, way: <way ID> },
24470 // restriction: <relation ID>
24473 // In the simple case, `restriction` is a reference to a `no_*` restriction
24474 // on the turn itself. In this case, it is simply deleted.
24476 // The more complex case is where `restriction` references an `only_*`
24477 // restriction on a different turn in the same intersection. In that case,
24478 // that restriction is also deleted, but at the same time restrictions on
24479 // the turns other than the first two are created.
24481 iD.actions.UnrestrictTurn = function(turn) {
24482 return function(graph) {
24483 return iD.actions.DeleteRelation(turn.restriction)(graph);
24487 iD.behavior.AddWay = function(context) {
24488 var event = d3.dispatch('start', 'startFromWay', 'startFromNode'),
24489 draw = iD.behavior.Draw(context);
24491 var addWay = function(surface) {
24492 draw.on('click', event.start)
24493 .on('clickWay', event.startFromWay)
24494 .on('clickNode', event.startFromNode)
24495 .on('cancel', addWay.cancel)
24496 .on('finish', addWay.cancel);
24499 .dblclickEnable(false);
24501 surface.call(draw);
24504 addWay.off = function(surface) {
24505 surface.call(draw.off);
24508 addWay.cancel = function() {
24509 window.setTimeout(function() {
24510 context.map().dblclickEnable(true);
24513 context.enter(iD.modes.Browse(context));
24516 addWay.tail = function(text) {
24521 return d3.rebind(addWay, event, 'on');
24523 iD.behavior.Breathe = function() {
24524 var duration = 800,
24525 selector = '.selected.shadow, .selected .shadow',
24526 selected = d3.select(null),
24531 function reset(selection) {
24533 .style('stroke-opacity', null)
24534 .style('stroke-width', null)
24535 .style('fill-opacity', null)
24539 function setAnimationParams(transition, fromTo) {
24541 .style('stroke-opacity', function(d) { return params[d.id][fromTo].opacity; })
24542 .style('stroke-width', function(d) { return params[d.id][fromTo].width; })
24543 .style('fill-opacity', function(d) { return params[d.id][fromTo].opacity; })
24544 .style('r', function(d) { return params[d.id][fromTo].width; });
24547 function calcAnimationParams(selection) {
24550 .each(function(d) {
24551 var s = d3.select(this),
24552 tag = s.node().tagName,
24553 p = {'from': {}, 'to': {}},
24556 // determine base opacity and width
24557 if (tag === 'circle') {
24558 opacity = parseFloat(s.style('fill-opacity') || 0.5);
24559 width = parseFloat(s.style('r') || 15.5);
24561 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
24562 width = parseFloat(s.style('stroke-width') || 10);
24565 // calculate from/to interpolation params..
24567 p.from.opacity = opacity * 0.6;
24568 p.to.opacity = opacity * 1.25;
24569 p.from.width = width * 0.9;
24570 p.to.width = width * (tag === 'circle' ? 1.5 : 1.25);
24575 function run(surface, fromTo) {
24576 var toFrom = (fromTo === 'from' ? 'to': 'from'),
24577 currSelected = surface.selectAll(selector),
24578 currClassed = surface.attr('class'),
24581 if (done || currSelected.empty()) {
24582 selected.call(reset);
24586 if (!_.isEqual(currSelected, selected) || currClassed !== classed) {
24587 selected.call(reset);
24588 classed = currClassed;
24589 selected = currSelected.call(calcAnimationParams);
24594 .call(setAnimationParams, fromTo)
24595 .duration(duration)
24596 .each(function() { ++n; })
24597 .each('end', function() {
24598 if (!--n) { // call once
24599 surface.call(run, toFrom);
24604 var breathe = function(surface) {
24606 d3.timer(function() {
24607 if (done) return true;
24609 var currSelected = surface.selectAll(selector);
24610 if (currSelected.empty()) return false;
24612 surface.call(run, 'from');
24617 breathe.off = function() {
24628 iD.behavior.Copy = function(context) {
24629 var keybinding = d3.keybinding('copy');
24631 function groupEntities(ids, graph) {
24632 var entities = ids.map(function (id) { return graph.entity(id); });
24633 return _.extend({relation: [], way: [], node: []},
24634 _.groupBy(entities, function(entity) { return entity.type; }));
24637 function getDescendants(id, graph, descendants) {
24638 var entity = graph.entity(id),
24641 descendants = descendants || {};
24643 if (entity.type === 'relation') {
24644 children = _.map(entity.members, 'id');
24645 } else if (entity.type === 'way') {
24646 children = entity.nodes;
24651 for (i = 0; i < children.length; i++) {
24652 if (!descendants[children[i]]) {
24653 descendants[children[i]] = true;
24654 descendants = getDescendants(children[i], graph, descendants);
24658 return descendants;
24661 function doCopy() {
24662 d3.event.preventDefault();
24663 if (context.inIntro()) return;
24665 var graph = context.graph(),
24666 selected = groupEntities(context.selectedIDs(), graph),
24671 for (i = 0; i < selected.relation.length; i++) {
24672 entity = selected.relation[i];
24673 if (!skip[entity.id] && entity.isComplete(graph)) {
24674 canCopy.push(entity.id);
24675 skip = getDescendants(entity.id, graph, skip);
24678 for (i = 0; i < selected.way.length; i++) {
24679 entity = selected.way[i];
24680 if (!skip[entity.id]) {
24681 canCopy.push(entity.id);
24682 skip = getDescendants(entity.id, graph, skip);
24685 for (i = 0; i < selected.node.length; i++) {
24686 entity = selected.node[i];
24687 if (!skip[entity.id]) {
24688 canCopy.push(entity.id);
24692 context.copyIDs(canCopy);
24696 keybinding.on(iD.ui.cmd('⌘C'), doCopy);
24697 d3.select(document).call(keybinding);
24701 copy.off = function() {
24702 d3.select(document).call(keybinding.off);
24708 `iD.behavior.drag` is like `d3.behavior.drag`, with the following differences:
24710 * The `origin` function is expected to return an [x, y] tuple rather than an
24712 * The events are `start`, `move`, and `end`.
24713 (https://github.com/mbostock/d3/issues/563)
24714 * The `start` event is not dispatched until the first cursor movement occurs.
24715 (https://github.com/mbostock/d3/pull/368)
24716 * The `move` event has a `point` and `delta` [x, y] tuple properties rather
24717 than `x`, `y`, `dx`, and `dy` properties.
24718 * The `end` event is not dispatched if no movement occurs.
24719 * An `off` function is available that unbinds the drag's internal event handlers.
24720 * Delegation is supported via the `delegate` function.
24723 iD.behavior.drag = function() {
24724 function d3_eventCancel() {
24725 d3.event.stopPropagation();
24726 d3.event.preventDefault();
24729 var event = d3.dispatch('start', 'move', 'end'),
24733 event_, target, surface;
24735 event.of = function(thiz, argumentz) {
24736 return function(e1) {
24737 var e0 = e1.sourceEvent = d3.event;
24741 event[e1.type].apply(thiz, argumentz);
24748 var d3_event_userSelectProperty = iD.util.prefixCSSProperty('UserSelect'),
24749 d3_event_userSelectSuppress = d3_event_userSelectProperty ?
24751 var selection = d3.selection(),
24752 select = selection.style(d3_event_userSelectProperty);
24753 selection.style(d3_event_userSelectProperty, 'none');
24754 return function () {
24755 selection.style(d3_event_userSelectProperty, select);
24759 var w = d3.select(window).on('selectstart.' + type, d3_eventCancel);
24760 return function () {
24761 w.on('selectstart.' + type, null);
24765 function mousedown() {
24767 event_ = event.of(target, arguments);
24768 var eventTarget = d3.event.target,
24769 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
24773 selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
24775 var w = d3.select(window)
24776 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
24777 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
24780 offset = origin.apply(target, arguments);
24781 offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
24786 if (touchId === null) d3.event.stopPropagation();
24789 var p = target.parentNode || surface;
24790 return touchId !== null ? d3.touches(p).filter(function(p) {
24791 return p.identifier === touchId;
24792 })[0] : d3.mouse(p);
24795 function dragmove() {
24798 dx = p[0] - origin_[0],
24799 dy = p[1] - origin_[1];
24801 if (dx === 0 && dy === 0)
24816 point: [p[0] + offset[0], p[1] + offset[1]],
24821 function dragend() {
24828 if (d3.event.target === eventTarget) w.on('click.drag', click, true);
24831 w.on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
24832 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
24838 w.on('click.drag', null);
24842 function drag(selection) {
24843 var matchesSelector = iD.util.prefixDOMProperty('matchesSelector'),
24844 delegate = mousedown;
24847 delegate = function() {
24849 target = d3.event.target;
24850 for (; target && target !== root; target = target.parentNode) {
24851 if (target[matchesSelector](selector) &&
24852 (!filter || filter(target.__data__))) {
24853 return mousedown.call(target, target.__data__);
24859 selection.on('mousedown.drag' + selector, delegate)
24860 .on('touchstart.drag' + selector, delegate);
24863 drag.off = function(selection) {
24864 selection.on('mousedown.drag' + selector, null)
24865 .on('touchstart.drag' + selector, null);
24868 drag.delegate = function(_) {
24869 if (!arguments.length) return selector;
24874 drag.filter = function(_) {
24875 if (!arguments.length) return origin;
24880 drag.origin = function (_) {
24881 if (!arguments.length) return origin;
24886 drag.cancel = function() {
24888 .on('mousemove.drag', null)
24889 .on('mouseup.drag', null);
24893 drag.target = function() {
24894 if (!arguments.length) return target;
24895 target = arguments[0];
24896 event_ = event.of(target, Array.prototype.slice.call(arguments, 1));
24900 drag.surface = function() {
24901 if (!arguments.length) return surface;
24902 surface = arguments[0];
24906 return d3.rebind(drag, event, 'on');
24908 iD.behavior.Draw = function(context) {
24909 var event = d3.dispatch('move', 'click', 'clickWay',
24910 'clickNode', 'undo', 'cancel', 'finish'),
24911 keybinding = d3.keybinding('draw'),
24912 hover = iD.behavior.Hover(context)
24914 .on('hover', context.ui().sidebar.hover),
24915 tail = iD.behavior.Tail(),
24916 edit = iD.behavior.Edit(context),
24917 closeTolerance = 4,
24919 mouseLeave = false,
24921 cached = iD.behavior.Draw;
24924 if (d3.event.altKey) return {};
24926 if (d3.event.type === 'keydown') {
24927 return (lastMouse && lastMouse.target.__data__) || {};
24929 return d3.event.target.__data__ || {};
24933 function mousedown() {
24936 var p = context.container().node();
24937 return touchId !== null ? d3.touches(p).filter(function(p) {
24938 return p.identifier === touchId;
24939 })[0] : d3.mouse(p);
24942 var element = d3.select(this),
24943 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
24947 element.on('mousemove.draw', null);
24949 d3.select(window).on('mouseup.draw', function() {
24950 var t2 = +new Date(),
24952 dist = iD.geo.euclideanDistance(p1, p2);
24954 element.on('mousemove.draw', mousemove);
24955 d3.select(window).on('mouseup.draw', null);
24957 if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
24958 // Prevent a quick second click
24959 d3.select(window).on('click.draw-block', function() {
24960 d3.event.stopPropagation();
24963 context.map().dblclickEnable(false);
24965 window.setTimeout(function() {
24966 context.map().dblclickEnable(true);
24967 d3.select(window).on('click.draw-block', null);
24975 function mousemove() {
24976 lastMouse = d3.event;
24977 event.move(datum());
24980 function mouseenter() {
24981 mouseLeave = false;
24984 function mouseleave() {
24990 if (d.type === 'way') {
24991 var dims = context.map().dimensions(),
24992 mouse = context.mouse(),
24994 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
24995 mouse[1] > pad && mouse[1] < dims[1] - pad;
24998 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection),
24999 edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
25000 event.clickWay(choice.loc, edge);
25002 event.click(context.map().mouseCoordinates());
25005 } else if (d.type === 'node') {
25006 event.clickNode(d);
25009 event.click(context.map().mouseCoordinates());
25014 var currSpace = context.mouse();
25015 if (cached.disableSpace && cached.lastSpace) {
25016 var dist = iD.geo.euclideanDistance(cached.lastSpace, currSpace);
25017 if (dist > tolerance) {
25018 cached.disableSpace = false;
25022 if (cached.disableSpace || mouseLeave || !lastMouse) return;
25024 // user must move mouse or release space bar to allow another click
25025 cached.lastSpace = currSpace;
25026 cached.disableSpace = true;
25028 d3.select(window).on('keyup.space-block', function() {
25029 cached.disableSpace = false;
25030 d3.select(window).on('keyup.space-block', null);
25033 d3.event.preventDefault();
25037 function backspace() {
25038 d3.event.preventDefault();
25043 d3.event.preventDefault();
25048 d3.event.preventDefault();
25052 function draw(selection) {
25053 context.install(hover);
25054 context.install(edit);
25056 if (!context.inIntro() && !cached.usedTails[tail.text()]) {
25057 context.install(tail);
25061 .on('⌫', backspace)
25065 .on('space', space)
25066 .on('⌥space', space);
25069 .on('mouseenter.draw', mouseenter)
25070 .on('mouseleave.draw', mouseleave)
25071 .on('mousedown.draw', mousedown)
25072 .on('mousemove.draw', mousemove);
25074 d3.select(document)
25080 draw.off = function(selection) {
25081 context.ui().sidebar.hover.cancel();
25082 context.uninstall(hover);
25083 context.uninstall(edit);
25085 if (!context.inIntro() && !cached.usedTails[tail.text()]) {
25086 context.uninstall(tail);
25087 cached.usedTails[tail.text()] = true;
25091 .on('mouseenter.draw', null)
25092 .on('mouseleave.draw', null)
25093 .on('mousedown.draw', null)
25094 .on('mousemove.draw', null);
25097 .on('mouseup.draw', null);
25098 // note: keyup.space-block, click.draw-block should remain
25100 d3.select(document)
25101 .call(keybinding.off);
25104 draw.tail = function(_) {
25109 return d3.rebind(draw, event, 'on');
25112 iD.behavior.Draw.usedTails = {};
25113 iD.behavior.Draw.disableSpace = false;
25114 iD.behavior.Draw.lastSpace = null;
25115 iD.behavior.DrawWay = function(context, wayId, index, mode, baseGraph) {
25116 var way = context.entity(wayId),
25117 isArea = context.geometry(wayId) === 'area',
25119 annotation = t((way.isDegenerate() ?
25120 'operations.start.annotation.' :
25121 'operations.continue.annotation.') + context.geometry(wayId)),
25122 draw = iD.behavior.Draw(context);
25124 var startIndex = typeof index === 'undefined' ? way.nodes.length - 1 : 0,
25125 start = iD.Node({loc: context.graph().entity(way.nodes[startIndex]).loc}),
25126 end = iD.Node({loc: context.map().mouseCoordinates()}),
25128 nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
25129 tags: _.clone(way.tags)
25132 var f = context[way.isDegenerate() ? 'replace' : 'perform'];
25134 f(iD.actions.AddEntity(end),
25135 iD.actions.AddVertex(wayId, end.id, index));
25137 f(iD.actions.AddEntity(start),
25138 iD.actions.AddEntity(end),
25139 iD.actions.AddEntity(segment));
25142 function move(datum) {
25145 if (datum.type === 'node' && datum.id !== end.id) {
25148 } else if (datum.type === 'way' && datum.id !== segment.id) {
25149 var dims = context.map().dimensions(),
25150 mouse = context.mouse(),
25152 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
25153 mouse[1] > pad && mouse[1] < dims[1] - pad;
25156 loc = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
25161 loc = context.map().mouseCoordinates();
25164 context.replace(iD.actions.MoveNode(end.id, loc));
25167 function undone() {
25169 context.enter(iD.modes.Browse(context));
25172 function setActiveElements() {
25173 var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
25174 context.surface().selectAll(iD.util.entitySelector(active))
25175 .classed('active', true);
25178 var drawWay = function(surface) {
25179 draw.on('move', move)
25180 .on('click', drawWay.add)
25181 .on('clickWay', drawWay.addWay)
25182 .on('clickNode', drawWay.addNode)
25183 .on('undo', context.undo)
25184 .on('cancel', drawWay.cancel)
25185 .on('finish', drawWay.finish);
25188 .dblclickEnable(false)
25189 .on('drawn.draw', setActiveElements);
25191 setActiveElements();
25193 surface.call(draw);
25196 .on('undone.draw', undone);
25199 drawWay.off = function(surface) {
25204 .on('drawn.draw', null);
25206 surface.call(draw.off)
25207 .selectAll('.active')
25208 .classed('active', false);
25211 .on('undone.draw', null);
25214 function ReplaceTemporaryNode(newNode) {
25215 return function(graph) {
25218 .replace(way.addNode(newNode.id, index))
25223 .replace(graph.entity(wayId).addNode(newNode.id, index))
25231 // Accept the current position of the temporary node and continue drawing.
25232 drawWay.add = function(loc) {
25234 // prevent duplicate nodes
25235 var last = context.hasEntity(way.nodes[way.nodes.length - (isArea ? 2 : 1)]);
25236 if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
25238 var newNode = iD.Node({loc: loc});
25241 iD.actions.AddEntity(newNode),
25242 ReplaceTemporaryNode(newNode),
25246 context.enter(mode);
25249 // Connect the way to an existing way.
25250 drawWay.addWay = function(loc, edge) {
25251 var previousEdge = startIndex ?
25252 [way.nodes[startIndex], way.nodes[startIndex - 1]] :
25253 [way.nodes[0], way.nodes[1]];
25255 // Avoid creating duplicate segments
25256 if (!isArea && iD.geo.edgeEqual(edge, previousEdge))
25259 var newNode = iD.Node({ loc: loc });
25262 iD.actions.AddMidpoint({ loc: loc, edge: edge}, newNode),
25263 ReplaceTemporaryNode(newNode),
25267 context.enter(mode);
25270 // Connect the way to an existing node and continue drawing.
25271 drawWay.addNode = function(node) {
25273 // Avoid creating duplicate segments
25274 if (way.areAdjacent(node.id, way.nodes[way.nodes.length - 1])) return;
25277 ReplaceTemporaryNode(node),
25281 context.enter(mode);
25284 // Finish the draw operation, removing the temporary node. If the way has enough
25285 // nodes to be valid, it's selected. Otherwise, return to browse mode.
25286 drawWay.finish = function() {
25290 window.setTimeout(function() {
25291 context.map().dblclickEnable(true);
25294 if (context.hasEntity(wayId)) {
25296 iD.modes.Select(context, [wayId])
25297 .suppressMenu(true)
25298 .newFeature(true));
25300 context.enter(iD.modes.Browse(context));
25304 // Cancel the draw operation and return to browse, deleting everything drawn.
25305 drawWay.cancel = function() {
25307 d3.functor(baseGraph),
25308 t('operations.cancel_draw.annotation'));
25310 window.setTimeout(function() {
25311 context.map().dblclickEnable(true);
25315 context.enter(iD.modes.Browse(context));
25318 drawWay.tail = function(text) {
25325 iD.behavior.Edit = function(context) {
25328 .minzoom(context.minEditableZoom());
25331 edit.off = function() {
25338 iD.behavior.Hash = function(context) {
25339 var s0 = null, // cached location.hash
25340 lat = 90 - 1e-8; // allowable latitude range
25342 var parser = function(map, s) {
25343 var q = iD.util.stringQs(s);
25344 var args = (q.map || '').split('/').map(Number);
25345 if (args.length < 3 || args.some(isNaN)) {
25346 return true; // replace bogus hash
25347 } else if (s !== formatter(map).slice(1)) {
25348 map.centerZoom([args[1],
25349 Math.min(lat, Math.max(-lat, args[2]))], args[0]);
25353 var formatter = function(map) {
25354 var mode = context.mode(),
25355 center = map.center(),
25357 precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)),
25358 q = _.omit(iD.util.stringQs(location.hash.substring(1)), 'comment'),
25361 if (mode && mode.id === 'browse') {
25364 var selected = context.selectedIDs().filter(function(id) {
25365 return !context.entity(id).isNew();
25367 if (selected.length) {
25368 newParams.id = selected.join(',');
25372 newParams.map = zoom.toFixed(2) +
25373 '/' + center[0].toFixed(precision) +
25374 '/' + center[1].toFixed(precision);
25376 return '#' + iD.util.qsString(_.assign(q, newParams), true);
25379 function update() {
25380 if (context.inIntro()) return;
25381 var s1 = formatter(context.map());
25382 if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map!
25385 var throttledUpdate = _.throttle(update, 500);
25387 function hashchange() {
25388 if (location.hash === s0) return; // ignore spurious hashchange events
25389 if (parser(context.map(), (s0 = location.hash).substring(1))) {
25390 update(); // replace bogus hash
25396 .on('move.hash', throttledUpdate);
25399 .on('enter.hash', throttledUpdate);
25402 .on('hashchange.hash', hashchange);
25404 if (location.hash) {
25405 var q = iD.util.stringQs(location.hash.substring(1));
25406 if (q.id) context.zoomToEntity(q.id.split(',')[0], !q.map);
25407 if (q.comment) context.storage('comment', q.comment);
25409 if (q.map) hash.hadHash = true;
25413 hash.off = function() {
25414 throttledUpdate.cancel();
25417 .on('move.hash', null);
25420 .on('enter.hash', null);
25423 .on('hashchange.hash', null);
25425 location.hash = '';
25431 The hover behavior adds the `.hover` class on mouseover to all elements to which
25432 the identical datum is bound, and removes it on mouseout.
25434 The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
25435 representation may consist of several elements scattered throughout the DOM hierarchy.
25436 Only one of these elements can have the :hover pseudo-class, but all of them will
25437 have the .hover class.
25439 iD.behavior.Hover = function() {
25440 var dispatch = d3.dispatch('hover'),
25445 function keydown() {
25446 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
25447 dispatch.hover(null);
25448 selection.selectAll('.hover')
25449 .classed('hover-suppressed', true)
25450 .classed('hover', false);
25455 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
25456 dispatch.hover(target ? target.id : null);
25457 selection.selectAll('.hover-suppressed')
25458 .classed('hover-suppressed', false)
25459 .classed('hover', true);
25463 var hover = function(__) {
25466 function enter(d) {
25467 if (d === target) return;
25471 selection.selectAll('.hover')
25472 .classed('hover', false);
25473 selection.selectAll('.hover-suppressed')
25474 .classed('hover-suppressed', false);
25476 if (target instanceof iD.Entity) {
25477 var selector = '.' + target.id;
25479 if (target.type === 'relation') {
25480 target.members.forEach(function(member) {
25481 selector += ', .' + member.id;
25485 var suppressed = altDisables && d3.event && d3.event.altKey;
25487 selection.selectAll(selector)
25488 .classed(suppressed ? 'hover-suppressed' : 'hover', true);
25490 dispatch.hover(target.id);
25492 dispatch.hover(null);
25498 function mouseover() {
25500 var target = d3.event.target;
25501 enter(target ? target.__data__ : null);
25504 function mouseout() {
25506 var target = d3.event.relatedTarget;
25507 enter(target ? target.__data__ : null);
25510 function mousedown() {
25513 .on('mouseup.hover', mouseup);
25516 function mouseup() {
25521 .on('mouseover.hover', mouseover)
25522 .on('mouseout.hover', mouseout)
25523 .on('mousedown.hover', mousedown)
25524 .on('mouseup.hover', mouseup);
25527 .on('keydown.hover', keydown)
25528 .on('keyup.hover', keyup);
25531 hover.off = function(selection) {
25532 selection.selectAll('.hover')
25533 .classed('hover', false);
25534 selection.selectAll('.hover-suppressed')
25535 .classed('hover-suppressed', false);
25538 .on('mouseover.hover', null)
25539 .on('mouseout.hover', null)
25540 .on('mousedown.hover', null)
25541 .on('mouseup.hover', null);
25544 .on('keydown.hover', null)
25545 .on('keyup.hover', null)
25546 .on('mouseup.hover', null);
25549 hover.altDisables = function(_) {
25550 if (!arguments.length) return altDisables;
25555 return d3.rebind(hover, dispatch, 'on');
25557 iD.behavior.Lasso = function(context) {
25559 var behavior = function(selection) {
25562 function mousedown() {
25563 var button = 0; // left
25564 if (d3.event.button === button && d3.event.shiftKey === true) {
25568 .on('mousemove.lasso', mousemove)
25569 .on('mouseup.lasso', mouseup);
25571 d3.event.stopPropagation();
25575 function mousemove() {
25577 lasso = iD.ui.Lasso(context);
25578 context.surface().call(lasso);
25581 lasso.p(context.mouse());
25584 function normalize(a, b) {
25586 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
25587 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
25590 function lassoed() {
25591 if (!lasso) return [];
25593 var graph = context.graph(),
25594 bounds = lasso.extent().map(context.projection.invert),
25595 extent = iD.geo.Extent(normalize(bounds[0], bounds[1]));
25597 return _.map(context.intersects(extent).filter(function(entity) {
25598 return entity.type === 'node' &&
25599 iD.geo.pointInPolygon(context.projection(entity.loc), lasso.coordinates) &&
25600 !context.features().isHidden(entity, graph, entity.geometry(graph));
25604 function mouseup() {
25606 .on('mousemove.lasso', null)
25607 .on('mouseup.lasso', null);
25609 if (!lasso) return;
25611 var ids = lassoed();
25615 context.enter(iD.modes.Select(context, ids));
25620 .on('mousedown.lasso', mousedown);
25623 behavior.off = function(selection) {
25624 selection.on('mousedown.lasso', null);
25629 iD.behavior.Paste = function(context) {
25630 var keybinding = d3.keybinding('paste');
25632 function omitTag(v, k) {
25640 k === 'description' ||
25641 k.indexOf('name') !== -1 ||
25642 k.indexOf('wiki') === 0 ||
25643 k.indexOf('addr:') === 0 ||
25644 k.indexOf('contact:') === 0
25648 function doPaste() {
25649 d3.event.preventDefault();
25650 if (context.inIntro()) return;
25652 var baseGraph = context.graph(),
25653 mouse = context.mouse(),
25654 projection = context.projection,
25655 viewport = iD.geo.Extent(projection.clipExtent()).polygon();
25657 if (!iD.geo.pointInPolygon(mouse, viewport)) return;
25659 var extent = iD.geo.Extent(),
25660 oldIDs = context.copyIDs(),
25661 oldGraph = context.copyGraph(),
25664 if (!oldIDs.length) return;
25666 var action = iD.actions.CopyEntities(oldIDs, oldGraph);
25667 context.perform(action);
25669 var copies = action.copies();
25670 for (var id in copies) {
25671 var oldEntity = oldGraph.entity(id),
25672 newEntity = copies[id];
25674 extent._extend(oldEntity.extent(oldGraph));
25675 newIDs.push(newEntity.id);
25676 context.perform(iD.actions.ChangeTags(newEntity.id, _.omit(newEntity.tags, omitTag)));
25679 // Put pasted objects where mouse pointer is..
25680 var center = projection(extent.center()),
25681 delta = [ mouse[0] - center[0], mouse[1] - center[1] ];
25683 context.perform(iD.actions.Move(newIDs, delta, projection));
25684 context.enter(iD.modes.Move(context, newIDs, baseGraph));
25688 keybinding.on(iD.ui.cmd('⌘V'), doPaste);
25689 d3.select(document).call(keybinding);
25693 paste.off = function() {
25694 d3.select(document).call(keybinding.off);
25699 iD.behavior.Select = function(context) {
25700 function keydown() {
25701 if (d3.event && d3.event.shiftKey) {
25703 .classed('behavior-multiselect', true);
25708 if (!d3.event || !d3.event.shiftKey) {
25710 .classed('behavior-multiselect', false);
25715 var datum = d3.event.target.__data__,
25716 lasso = d3.select('#surface .lasso').node(),
25717 mode = context.mode();
25719 if (!(datum instanceof iD.Entity)) {
25720 if (!d3.event.shiftKey && !lasso && mode.id !== 'browse')
25721 context.enter(iD.modes.Browse(context));
25723 } else if (!d3.event.shiftKey && !lasso) {
25724 // Avoid re-entering Select mode with same entity.
25725 if (context.selectedIDs().length !== 1 || context.selectedIDs()[0] !== datum.id) {
25726 context.enter(iD.modes.Select(context, [datum.id]));
25728 mode.suppressMenu(false).reselect();
25730 } else if (context.selectedIDs().indexOf(datum.id) >= 0) {
25731 var selectedIDs = _.without(context.selectedIDs(), datum.id);
25732 context.enter(selectedIDs.length ?
25733 iD.modes.Select(context, selectedIDs) :
25734 iD.modes.Browse(context));
25737 context.enter(iD.modes.Select(context, context.selectedIDs().concat([datum.id])));
25741 var behavior = function(selection) {
25743 .on('keydown.select', keydown)
25744 .on('keyup.select', keyup);
25746 selection.on('click.select', click);
25751 behavior.off = function(selection) {
25753 .on('keydown.select', null)
25754 .on('keyup.select', null);
25756 selection.on('click.select', null);
25763 iD.behavior.Tail = function() {
25767 tooltipSize = [0, 0],
25768 selectionSize = [0, 0];
25770 function tail(selection) {
25774 .on('resize.tail', function() { selectionSize = selection.dimensions(); });
25777 container.style('display', 'block');
25778 tooltipSize = container.dimensions();
25781 function mousemove() {
25782 if (container.style('display') === 'none') show();
25783 var xoffset = ((d3.event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
25784 -tooltipSize[0] - xmargin : xmargin;
25785 container.classed('left', xoffset > 0);
25786 iD.util.setTransform(container, d3.event.clientX + xoffset, d3.event.clientY);
25789 function mouseleave() {
25790 if (d3.event.relatedTarget !== container.node()) {
25791 container.style('display', 'none');
25795 function mouseenter() {
25796 if (d3.event.relatedTarget !== container.node()) {
25801 container = d3.select(document.body)
25803 .style('display', 'none')
25804 .attr('class', 'tail tooltip-inner');
25806 container.append('div')
25810 .on('mousemove.tail', mousemove)
25811 .on('mouseenter.tail', mouseenter)
25812 .on('mouseleave.tail', mouseleave);
25815 .on('mousemove.tail', mousemove);
25817 tooltipSize = container.dimensions();
25818 selectionSize = selection.dimensions();
25821 tail.off = function(selection) {
25825 .on('mousemove.tail', null)
25829 .on('mousemove.tail', null)
25830 .on('mouseenter.tail', null)
25831 .on('mouseleave.tail', null);
25834 .on('resize.tail', null);
25837 tail.text = function(_) {
25838 if (!arguments.length) return text;
25846 iD.modes.AddArea = function(context) {
25850 title: t('modes.add_area.title'),
25851 description: t('modes.add_area.description'),
25855 var behavior = iD.behavior.AddWay(context)
25856 .tail(t('modes.add_area.tail'))
25857 .on('start', start)
25858 .on('startFromWay', startFromWay)
25859 .on('startFromNode', startFromNode),
25860 defaultTags = {area: 'yes'};
25862 function start(loc) {
25863 var graph = context.graph(),
25864 node = iD.Node({loc: loc}),
25865 way = iD.Way({tags: defaultTags});
25868 iD.actions.AddEntity(node),
25869 iD.actions.AddEntity(way),
25870 iD.actions.AddVertex(way.id, node.id),
25871 iD.actions.AddVertex(way.id, node.id));
25873 context.enter(iD.modes.DrawArea(context, way.id, graph));
25876 function startFromWay(loc, edge) {
25877 var graph = context.graph(),
25878 node = iD.Node({loc: loc}),
25879 way = iD.Way({tags: defaultTags});
25882 iD.actions.AddEntity(node),
25883 iD.actions.AddEntity(way),
25884 iD.actions.AddVertex(way.id, node.id),
25885 iD.actions.AddVertex(way.id, node.id),
25886 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
25888 context.enter(iD.modes.DrawArea(context, way.id, graph));
25891 function startFromNode(node) {
25892 var graph = context.graph(),
25893 way = iD.Way({tags: defaultTags});
25896 iD.actions.AddEntity(way),
25897 iD.actions.AddVertex(way.id, node.id),
25898 iD.actions.AddVertex(way.id, node.id));
25900 context.enter(iD.modes.DrawArea(context, way.id, graph));
25903 mode.enter = function() {
25904 context.install(behavior);
25907 mode.exit = function() {
25908 context.uninstall(behavior);
25913 iD.modes.AddLine = function(context) {
25917 title: t('modes.add_line.title'),
25918 description: t('modes.add_line.description'),
25922 var behavior = iD.behavior.AddWay(context)
25923 .tail(t('modes.add_line.tail'))
25924 .on('start', start)
25925 .on('startFromWay', startFromWay)
25926 .on('startFromNode', startFromNode);
25928 function start(loc) {
25929 var baseGraph = context.graph(),
25930 node = iD.Node({loc: loc}),
25934 iD.actions.AddEntity(node),
25935 iD.actions.AddEntity(way),
25936 iD.actions.AddVertex(way.id, node.id));
25938 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
25941 function startFromWay(loc, edge) {
25942 var baseGraph = context.graph(),
25943 node = iD.Node({loc: loc}),
25947 iD.actions.AddEntity(node),
25948 iD.actions.AddEntity(way),
25949 iD.actions.AddVertex(way.id, node.id),
25950 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
25952 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
25955 function startFromNode(node) {
25956 var baseGraph = context.graph(),
25960 iD.actions.AddEntity(way),
25961 iD.actions.AddVertex(way.id, node.id));
25963 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
25966 mode.enter = function() {
25967 context.install(behavior);
25970 mode.exit = function() {
25971 context.uninstall(behavior);
25976 iD.modes.AddPoint = function(context) {
25980 title: t('modes.add_point.title'),
25981 description: t('modes.add_point.description'),
25985 var behavior = iD.behavior.Draw(context)
25986 .tail(t('modes.add_point.tail'))
25988 .on('clickWay', addWay)
25989 .on('clickNode', addNode)
25990 .on('cancel', cancel)
25991 .on('finish', cancel);
25993 function add(loc) {
25994 var node = iD.Node({loc: loc});
25997 iD.actions.AddEntity(node),
25998 t('operations.add.annotation.point'));
26001 iD.modes.Select(context, [node.id])
26002 .suppressMenu(true)
26003 .newFeature(true));
26006 function addWay(loc) {
26010 function addNode(node) {
26014 function cancel() {
26015 context.enter(iD.modes.Browse(context));
26018 mode.enter = function() {
26019 context.install(behavior);
26022 mode.exit = function() {
26023 context.uninstall(behavior);
26028 iD.modes.Browse = function(context) {
26032 title: t('modes.browse.title'),
26033 description: t('modes.browse.description')
26037 iD.behavior.Paste(context),
26038 iD.behavior.Hover(context)
26039 .on('hover', context.ui().sidebar.hover),
26040 iD.behavior.Select(context),
26041 iD.behavior.Lasso(context),
26042 iD.modes.DragNode(context).behavior];
26044 mode.enter = function() {
26045 behaviors.forEach(function(behavior) {
26046 context.install(behavior);
26049 // Get focus on the body.
26050 if (document.activeElement && document.activeElement.blur) {
26051 document.activeElement.blur();
26055 context.ui().sidebar.show(sidebar);
26057 context.ui().sidebar.select(null);
26061 mode.exit = function() {
26062 context.ui().sidebar.hover.cancel();
26063 behaviors.forEach(function(behavior) {
26064 context.uninstall(behavior);
26068 context.ui().sidebar.hide();
26072 mode.sidebar = function(_) {
26073 if (!arguments.length) return sidebar;
26080 iD.modes.DragNode = function(context) {
26091 hover = iD.behavior.Hover(context)
26093 .on('hover', context.ui().sidebar.hover),
26094 edit = iD.behavior.Edit(context);
26096 function edge(point, size) {
26097 var pad = [30, 100, 30, 100];
26098 if (point[0] > size[0] - pad[0]) return [-10, 0];
26099 else if (point[0] < pad[2]) return [10, 0];
26100 else if (point[1] > size[1] - pad[1]) return [0, -10];
26101 else if (point[1] < pad[3]) return [0, 10];
26105 function startNudge(nudge) {
26106 if (nudgeInterval) window.clearInterval(nudgeInterval);
26107 nudgeInterval = window.setInterval(function() {
26108 context.pan(nudge);
26112 function stopNudge() {
26113 if (nudgeInterval) window.clearInterval(nudgeInterval);
26114 nudgeInterval = null;
26117 function moveAnnotation(entity) {
26118 return t('operations.move.annotation.' + entity.geometry(context.graph()));
26121 function connectAnnotation(entity) {
26122 return t('operations.connect.annotation.' + entity.geometry(context.graph()));
26125 function origin(entity) {
26126 return context.projection(entity.loc);
26129 function start(entity) {
26130 cancelled = d3.event.sourceEvent.shiftKey ||
26131 context.features().hasHiddenConnections(entity, context.graph());
26133 if (cancelled) return behavior.cancel();
26135 wasMidpoint = entity.type === 'midpoint';
26137 var midpoint = entity;
26138 entity = iD.Node();
26139 context.perform(iD.actions.AddMidpoint(midpoint, entity));
26141 var vertex = context.surface()
26142 .selectAll('.' + entity.id);
26143 behavior.target(vertex.node(), entity);
26147 iD.actions.Noop());
26150 activeIDs = _.map(context.graph().parentWays(entity), 'id');
26151 activeIDs.push(entity.id);
26153 context.enter(mode);
26157 if (d3.event.sourceEvent.altKey) {
26161 return d3.event.sourceEvent.target.__data__ || {};
26164 // via https://gist.github.com/shawnbot/4166283
26165 function childOf(p, c) {
26166 if (p === c) return false;
26167 while (c && c !== p) c = c.parentNode;
26171 function move(entity) {
26172 if (cancelled) return;
26173 d3.event.sourceEvent.stopPropagation();
26175 var nudge = childOf(context.container().node(),
26176 d3.event.sourceEvent.toElement) &&
26177 edge(d3.event.point, context.map().dimensions());
26179 if (nudge) startNudge(nudge);
26182 var loc = context.projection.invert(d3.event.point);
26185 if (d.type === 'node' && d.id !== entity.id) {
26187 } else if (d.type === 'way' && !d3.select(d3.event.sourceEvent.target).classed('fill')) {
26188 loc = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
26192 iD.actions.MoveNode(entity.id, loc),
26193 moveAnnotation(entity));
26196 function end(entity) {
26197 if (cancelled) return;
26201 if (d.type === 'way') {
26202 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection);
26204 iD.actions.AddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
26205 connectAnnotation(d));
26207 } else if (d.type === 'node' && d.id !== entity.id) {
26209 iD.actions.Connect([d.id, entity.id]),
26210 connectAnnotation(d));
26212 } else if (wasMidpoint) {
26215 t('operations.add.annotation.vertex'));
26220 moveAnnotation(entity));
26223 var reselection = selectedIDs.filter(function(id) {
26224 return context.graph().hasEntity(id);
26227 if (reselection.length) {
26229 iD.modes.Select(context, reselection)
26230 .suppressMenu(true));
26232 context.enter(iD.modes.Browse(context));
26236 function cancel() {
26238 context.enter(iD.modes.Browse(context));
26241 function setActiveElements() {
26242 context.surface().selectAll(iD.util.entitySelector(activeIDs))
26243 .classed('active', true);
26246 var behavior = iD.behavior.drag()
26247 .delegate('g.node, g.point, g.midpoint')
26248 .surface(context.surface().node())
26250 .on('start', start)
26254 mode.enter = function() {
26255 context.install(hover);
26256 context.install(edit);
26259 .on('undone.drag-node', cancel);
26262 .on('drawn.drag-node', setActiveElements);
26264 setActiveElements();
26267 mode.exit = function() {
26268 context.ui().sidebar.hover.cancel();
26269 context.uninstall(hover);
26270 context.uninstall(edit);
26273 .on('undone.drag-node', null);
26276 .on('drawn.drag-node', null);
26279 .selectAll('.active')
26280 .classed('active', false);
26285 mode.selectedIDs = function(_) {
26286 if (!arguments.length) return selectedIDs;
26291 mode.behavior = behavior;
26295 iD.modes.DrawArea = function(context, wayId, baseGraph) {
26303 mode.enter = function() {
26304 var way = context.entity(wayId),
26305 headId = way.nodes[way.nodes.length - 2],
26306 tailId = way.first();
26308 behavior = iD.behavior.DrawWay(context, wayId, -1, mode, baseGraph)
26309 .tail(t('modes.draw_area.tail'));
26311 var addNode = behavior.addNode;
26313 behavior.addNode = function(node) {
26314 if (node.id === headId || node.id === tailId) {
26321 context.install(behavior);
26324 mode.exit = function() {
26325 context.uninstall(behavior);
26328 mode.selectedIDs = function() {
26334 iD.modes.DrawLine = function(context, wayId, baseGraph, affix) {
26342 mode.enter = function() {
26343 var way = context.entity(wayId),
26344 index = (affix === 'prefix') ? 0 : undefined,
26345 headId = (affix === 'prefix') ? way.first() : way.last();
26347 behavior = iD.behavior.DrawWay(context, wayId, index, mode, baseGraph)
26348 .tail(t('modes.draw_line.tail'));
26350 var addNode = behavior.addNode;
26352 behavior.addNode = function(node) {
26353 if (node.id === headId) {
26360 context.install(behavior);
26363 mode.exit = function() {
26364 context.uninstall(behavior);
26367 mode.selectedIDs = function() {
26373 iD.modes.Move = function(context, entityIDs, baseGraph) {
26379 var keybinding = d3.keybinding('move'),
26380 edit = iD.behavior.Edit(context),
26381 annotation = entityIDs.length === 1 ?
26382 t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
26383 t('operations.move.annotation.multiple'),
26388 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
26390 function edge(point, size) {
26391 var pad = [30, 100, 30, 100];
26392 if (point[0] > size[0] - pad[0]) return [-10, 0];
26393 else if (point[0] < pad[2]) return [10, 0];
26394 else if (point[1] > size[1] - pad[1]) return [0, -10];
26395 else if (point[1] < pad[3]) return [0, 10];
26399 function startNudge(nudge) {
26400 if (nudgeInterval) window.clearInterval(nudgeInterval);
26401 nudgeInterval = window.setInterval(function() {
26402 context.pan(nudge);
26404 var currMouse = context.mouse(),
26405 origMouse = context.projection(origin),
26406 delta = vecSub(vecSub(currMouse, origMouse), nudge),
26407 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
26409 context.overwrite(action, annotation);
26414 function stopNudge() {
26415 if (nudgeInterval) window.clearInterval(nudgeInterval);
26416 nudgeInterval = null;
26420 var currMouse = context.mouse(),
26421 origMouse = context.projection(origin),
26422 delta = vecSub(currMouse, origMouse),
26423 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
26425 context.overwrite(action, annotation);
26427 var nudge = edge(currMouse, context.map().dimensions());
26428 if (nudge) startNudge(nudge);
26432 function finish() {
26433 d3.event.stopPropagation();
26434 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
26438 function cancel() {
26440 while (context.graph() !== baseGraph) context.pop();
26441 context.enter(iD.modes.Browse(context));
26444 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
26449 function undone() {
26450 context.enter(iD.modes.Browse(context));
26453 mode.enter = function() {
26454 origin = context.map().mouseCoordinates();
26457 context.install(edit);
26464 .on('mousemove.move', move)
26465 .on('click.move', finish);
26468 .on('undone.move', undone);
26474 d3.select(document)
26478 mode.exit = function() {
26481 context.uninstall(edit);
26484 .on('mousemove.move', null)
26485 .on('click.move', null);
26488 .on('undone.move', null);
26495 iD.modes.RotateWay = function(context, wayId) {
26501 var keybinding = d3.keybinding('rotate-way'),
26502 edit = iD.behavior.Edit(context);
26504 mode.enter = function() {
26505 context.install(edit);
26507 var annotation = t('operations.rotate.annotation.' + context.geometry(wayId)),
26508 way = context.graph().entity(wayId),
26509 nodes = _.uniq(context.graph().childNodes(way)),
26510 points = nodes.map(function(n) { return context.projection(n.loc); }),
26511 pivot = d3.geom.polygon(points).centroid(),
26518 function rotate() {
26520 var mousePoint = context.mouse(),
26521 newAngle = Math.atan2(mousePoint[1] - pivot[1], mousePoint[0] - pivot[0]);
26523 if (typeof angle === 'undefined') angle = newAngle;
26526 iD.actions.RotateWay(wayId, pivot, newAngle - angle, context.projection),
26532 function finish() {
26533 d3.event.stopPropagation();
26534 context.enter(iD.modes.Select(context, [wayId])
26535 .suppressMenu(true));
26538 function cancel() {
26540 context.enter(iD.modes.Select(context, [wayId])
26541 .suppressMenu(true));
26544 function undone() {
26545 context.enter(iD.modes.Browse(context));
26549 .on('mousemove.rotate-way', rotate)
26550 .on('click.rotate-way', finish);
26553 .on('undone.rotate-way', undone);
26559 d3.select(document)
26563 mode.exit = function() {
26564 context.uninstall(edit);
26567 .on('mousemove.rotate-way', null)
26568 .on('click.rotate-way', null);
26571 .on('undone.rotate-way', null);
26578 iD.modes.Save = function(context) {
26579 var ui = iD.ui.Commit(context)
26580 .on('cancel', cancel)
26583 function cancel() {
26584 context.enter(iD.modes.Browse(context));
26587 function save(e, tryAgain) {
26588 function withChildNodes(ids, graph) {
26589 return _.uniq(_.reduce(ids, function(result, id) {
26590 var e = graph.entity(id);
26591 if (e.type === 'way') {
26593 var cn = graph.childNodes(e);
26594 result.push.apply(result, _.map(_.filter(cn, 'version'), 'id'));
26596 /* eslint-disable no-console */
26597 if (typeof console !== 'undefined') console.error(err);
26598 /* eslint-enable no-console */
26605 var loading = iD.ui.Loading(context).message(t('save.uploading')).blocking(true),
26606 history = context.history(),
26607 origChanges = history.changes(iD.actions.DiscardTags(history.difference())),
26608 localGraph = context.graph(),
26609 remoteGraph = iD.Graph(history.base(), true),
26610 modified = _.filter(history.difference().summary(), {changeType: 'modified'}),
26611 toCheck = _.map(_.map(modified, 'entity'), 'id'),
26612 toLoad = withChildNodes(toCheck, localGraph),
26616 if (!tryAgain) history.perform(iD.actions.Noop()); // checkpoint
26617 context.container().call(loading);
26619 if (toCheck.length) {
26620 context.connection().loadMultiple(toLoad, loaded);
26626 // Reload modified entities into an alternate graph and check for conflicts..
26627 function loaded(err, result) {
26628 if (errors.length) return;
26632 msg: err.responseText,
26633 details: [ t('save.status_code', { code: err.status }) ]
26639 _.each(result.data, function(entity) {
26640 remoteGraph.replace(entity);
26641 toLoad = _.without(toLoad, entity.id);
26643 // Because loadMultiple doesn't download /full like loadEntity,
26644 // need to also load children that aren't already being checked..
26645 if (!entity.visible) return;
26646 if (entity.type === 'way') {
26647 loadMore.push.apply(loadMore,
26648 _.difference(entity.nodes, toCheck, toLoad, loadMore));
26649 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
26650 loadMore.push.apply(loadMore,
26651 _.difference(_.map(entity.members, 'id'), toCheck, toLoad, loadMore));
26655 if (loadMore.length) {
26656 toLoad.push.apply(toLoad, loadMore);
26657 context.connection().loadMultiple(loadMore, loaded);
26660 if (!toLoad.length) {
26667 function checkConflicts() {
26668 function choice(id, text, action) {
26669 return { id: id, text: text, action: function() { history.replace(action); } };
26671 function formatUser(d) {
26672 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
26674 function entityName(entity) {
26675 return iD.util.displayName(entity) || (iD.util.displayType(entity.id) + ' ' + entity.id);
26678 function compareVersions(local, remote) {
26679 if (local.version !== remote.version) return false;
26681 if (local.type === 'way') {
26682 var children = _.union(local.nodes, remote.nodes);
26684 for (var i = 0; i < children.length; i++) {
26685 var a = localGraph.hasEntity(children[i]),
26686 b = remoteGraph.hasEntity(children[i]);
26688 if (a && b && a.version !== b.version) return false;
26695 _.each(toCheck, function(id) {
26696 var local = localGraph.entity(id),
26697 remote = remoteGraph.entity(id);
26699 if (compareVersions(local, remote)) return;
26701 var action = iD.actions.MergeRemoteChanges,
26702 merge = action(id, localGraph, remoteGraph, formatUser);
26704 history.replace(merge);
26706 var mergeConflicts = merge.conflicts();
26707 if (!mergeConflicts.length) return; // merged safely
26709 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
26710 forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
26711 keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
26712 keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
26716 name: entityName(local),
26717 details: mergeConflicts,
26720 choice(id, keepMine, forceLocal),
26721 choice(id, keepTheirs, forceRemote)
26730 function finalize() {
26731 if (conflicts.length) {
26732 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
26734 } else if (errors.length) {
26737 var changes = history.changes(iD.actions.DiscardTags(history.difference()));
26738 if (changes.modified.length || changes.created.length || changes.deleted.length) {
26739 context.connection().putChangeset(
26742 history.imageryUsed(),
26743 function(err, changeset_id) {
26746 msg: err.responseText,
26747 details: [ t('save.status_code', { code: err.status }) ]
26751 history.clearSaved();
26752 success(e, changeset_id);
26753 // Add delay to allow for postgres replication #1646 #2678
26754 window.setTimeout(function() {
26760 } else { // changes were insignificant or reverted by user
26769 function showConflicts() {
26770 var selection = context.container()
26771 .select('#sidebar')
26773 .attr('class','sidebar-component');
26777 selection.call(iD.ui.Conflicts(context)
26779 .on('download', function() {
26780 var data = JXON.stringify(context.connection().osmChangeJXON('CHANGEME', origChanges)),
26781 win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
26784 .on('cancel', function() {
26786 selection.remove();
26788 .on('save', function() {
26789 for (var i = 0; i < conflicts.length; i++) {
26790 if (conflicts[i].chosen === 1) { // user chose "keep theirs"
26791 var entity = context.hasEntity(conflicts[i].id);
26792 if (entity && entity.type === 'way') {
26793 var children = _.uniq(entity.nodes);
26794 for (var j = 0; j < children.length; j++) {
26795 history.replace(iD.actions.Revert(children[j]));
26798 history.replace(iD.actions.Revert(conflicts[i].id));
26802 selection.remove();
26809 function showErrors() {
26810 var selection = iD.ui.confirm(context.container());
26816 .select('.modal-section.header')
26818 .text(t('save.error'));
26820 addErrors(selection, errors);
26821 selection.okButton();
26825 function addErrors(selection, data) {
26826 var message = selection
26827 .select('.modal-section.message-text');
26829 var items = message
26830 .selectAll('.error-container')
26833 var enter = items.enter()
26835 .attr('class', 'error-container');
26839 .attr('class', 'error-description')
26841 .classed('hide-toggle', true)
26842 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
26843 .on('click', function() {
26844 var error = d3.select(this),
26845 detail = d3.select(this.nextElementSibling),
26846 exp = error.classed('expanded');
26848 detail.style('display', exp ? 'none' : 'block');
26849 error.classed('expanded', !exp);
26851 d3.event.preventDefault();
26854 var details = enter
26856 .attr('class', 'error-detail-container')
26857 .style('display', 'none');
26861 .attr('class', 'error-detail-list')
26863 .data(function(d) { return d.details || []; })
26866 .attr('class', 'error-detail-item')
26867 .text(function(d) { return d; });
26876 function success(e, changeset_id) {
26877 context.enter(iD.modes.Browse(context)
26878 .sidebar(iD.ui.Success(context)
26883 .on('cancel', function() {
26884 context.ui().sidebar.hide();
26892 mode.enter = function() {
26893 context.connection().authenticate(function(err) {
26897 context.ui().sidebar.show(ui);
26902 mode.exit = function() {
26903 context.ui().sidebar.hide();
26908 iD.modes.Select = function(context, selectedIDs) {
26914 var keybinding = d3.keybinding('select'),
26917 iD.behavior.Copy(context),
26918 iD.behavior.Paste(context),
26919 iD.behavior.Breathe(context),
26920 iD.behavior.Hover(context),
26921 iD.behavior.Select(context),
26922 iD.behavior.Lasso(context),
26923 iD.modes.DragNode(context)
26924 .selectedIDs(selectedIDs)
26928 newFeature = false,
26929 suppressMenu = false;
26931 var wrap = context.container()
26932 .select('.inspector-wrap');
26935 function singular() {
26936 if (selectedIDs.length === 1) {
26937 return context.hasEntity(selectedIDs[0]);
26941 function closeMenu() {
26943 context.surface().call(radialMenu.close);
26947 function positionMenu() {
26948 if (suppressMenu || !radialMenu) { return; }
26950 var entity = singular();
26951 if (entity && context.geometry(entity.id) === 'relation') {
26952 suppressMenu = true;
26953 } else if (entity && entity.type === 'node') {
26954 radialMenu.center(context.projection(entity.loc));
26956 var point = context.mouse(),
26957 viewport = iD.geo.Extent(context.projection.clipExtent()).polygon();
26958 if (iD.geo.pointInPolygon(point, viewport)) {
26959 radialMenu.center(point);
26961 suppressMenu = true;
26966 function showMenu() {
26968 if (!suppressMenu && radialMenu) {
26969 context.surface().call(radialMenu);
26973 function toggleMenu() {
26974 if (d3.select('.radial-menu').empty()) {
26981 mode.selectedIDs = function() {
26982 return selectedIDs;
26985 mode.reselect = function() {
26986 var surfaceNode = context.surface().node();
26987 if (surfaceNode.focus) { // FF doesn't support it
26988 surfaceNode.focus();
26995 mode.newFeature = function(_) {
26996 if (!arguments.length) return newFeature;
27001 mode.suppressMenu = function(_) {
27002 if (!arguments.length) return suppressMenu;
27007 mode.enter = function() {
27008 function update() {
27010 if (_.some(selectedIDs, function(id) { return !context.hasEntity(id); })) {
27011 // Exit mode if selected entity gets undone
27012 context.enter(iD.modes.Browse(context));
27016 function dblclick() {
27017 var target = d3.select(d3.event.target),
27018 datum = target.datum();
27020 if (datum instanceof iD.Way && !target.classed('fill')) {
27021 var choice = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection),
27024 var prev = datum.nodes[choice.index - 1],
27025 next = datum.nodes[choice.index];
27028 iD.actions.AddMidpoint({loc: choice.loc, edge: [prev, next]}, node),
27029 t('operations.add.annotation.vertex'));
27031 d3.event.preventDefault();
27032 d3.event.stopPropagation();
27036 function selectElements(drawn) {
27037 var entity = singular();
27038 if (entity && context.geometry(entity.id) === 'relation') {
27039 suppressMenu = true;
27043 var selection = context.surface()
27044 .selectAll(iD.util.entityOrMemberSelector(selectedIDs, context.graph()));
27046 if (selection.empty()) {
27047 if (drawn) { // Exit mode if selected DOM elements have disappeared..
27048 context.enter(iD.modes.Browse(context));
27052 .classed('selected', true);
27057 if (!context.inIntro()) {
27058 context.enter(iD.modes.Browse(context));
27063 behaviors.forEach(function(behavior) {
27064 context.install(behavior);
27067 var operations = _.without(d3.values(iD.operations), iD.operations.Delete)
27068 .map(function(o) { return o(selectedIDs, context); })
27069 .filter(function(o) { return o.available(); });
27071 operations.unshift(iD.operations.Delete(selectedIDs, context));
27074 .on('⎋', esc, true)
27075 .on('space', toggleMenu);
27077 operations.forEach(function(operation) {
27078 operation.keys.forEach(function(key) {
27079 keybinding.on(key, function() {
27080 if (!(context.inIntro() || operation.disabled())) {
27087 d3.select(document)
27090 radialMenu = iD.ui.RadialMenu(context, operations);
27092 context.ui().sidebar
27093 .select(singular() ? singular().id : null, newFeature);
27096 .on('undone.select', update)
27097 .on('redone.select', update);
27100 .on('move.select', closeMenu)
27101 .on('drawn.select', selectElements);
27105 var show = d3.event && !suppressMenu;
27111 timeout = window.setTimeout(function() {
27117 .on('dblclick.select', dblclick);
27120 if (selectedIDs.length > 1) {
27121 var entities = iD.ui.SelectionList(context, selectedIDs);
27122 context.ui().sidebar.show(entities);
27126 mode.exit = function() {
27127 if (timeout) window.clearTimeout(timeout);
27129 if (inspector) wrap.call(inspector.close);
27131 behaviors.forEach(function(behavior) {
27132 context.uninstall(behavior);
27137 radialMenu = undefined;
27140 .on('undone.select', null)
27141 .on('redone.select', null);
27144 .on('dblclick.select', null)
27145 .selectAll('.selected')
27146 .classed('selected', false);
27148 context.map().on('drawn.select', null);
27149 context.ui().sidebar.hide();
27154 iD.operations = {};
27155 iD.operations.Circularize = function(selectedIDs, context) {
27156 var entityId = selectedIDs[0],
27157 entity = context.entity(entityId),
27158 extent = entity.extent(context.graph()),
27159 geometry = context.geometry(entityId),
27160 action = iD.actions.Circularize(entityId, context.projection);
27162 var operation = function() {
27163 var annotation = t('operations.circularize.annotation.' + geometry);
27164 context.perform(action, annotation);
27167 operation.available = function() {
27168 return selectedIDs.length === 1 &&
27169 entity.type === 'way' &&
27170 _.uniq(entity.nodes).length > 1;
27173 operation.disabled = function() {
27175 if (extent.percentContainedIn(context.extent()) < 0.8) {
27176 reason = 'too_large';
27177 } else if (context.hasHiddenConnections(entityId)) {
27178 reason = 'connected_to_hidden';
27180 return action.disabled(context.graph()) || reason;
27183 operation.tooltip = function() {
27184 var disable = operation.disabled();
27186 t('operations.circularize.' + disable) :
27187 t('operations.circularize.description.' + geometry);
27190 operation.id = 'circularize';
27191 operation.keys = [t('operations.circularize.key')];
27192 operation.title = t('operations.circularize.title');
27196 iD.operations.Continue = function(selectedIDs, context) {
27197 var graph = context.graph(),
27198 entities = selectedIDs.map(function(id) { return graph.entity(id); }),
27199 geometries = _.extend({line: [], vertex: []},
27200 _.groupBy(entities, function(entity) { return entity.geometry(graph); })),
27201 vertex = geometries.vertex[0];
27203 function candidateWays() {
27204 return graph.parentWays(vertex).filter(function(parent) {
27205 return parent.geometry(graph) === 'line' &&
27206 parent.affix(vertex.id) &&
27207 (geometries.line.length === 0 || geometries.line[0] === parent);
27211 var operation = function() {
27212 var candidate = candidateWays()[0];
27213 context.enter(iD.modes.DrawLine(
27217 candidate.affix(vertex.id)));
27220 operation.available = function() {
27221 return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
27222 !context.features().hasHiddenConnections(vertex, context.graph());
27225 operation.disabled = function() {
27226 var candidates = candidateWays();
27227 if (candidates.length === 0)
27228 return 'not_eligible';
27229 if (candidates.length > 1)
27233 operation.tooltip = function() {
27234 var disable = operation.disabled();
27236 t('operations.continue.' + disable) :
27237 t('operations.continue.description');
27240 operation.id = 'continue';
27241 operation.keys = [t('operations.continue.key')];
27242 operation.title = t('operations.continue.title');
27246 iD.operations.Delete = function(selectedIDs, context) {
27247 var action = iD.actions.DeleteMultiple(selectedIDs);
27249 var operation = function() {
27253 if (selectedIDs.length > 1) {
27254 annotation = t('operations.delete.annotation.multiple', {n: selectedIDs.length});
27257 var id = selectedIDs[0],
27258 entity = context.entity(id),
27259 geometry = context.geometry(id),
27260 parents = context.graph().parentWays(entity),
27261 parent = parents[0];
27263 annotation = t('operations.delete.annotation.' + geometry);
27265 // Select the next closest node in the way.
27266 if (geometry === 'vertex' && parents.length === 1 && parent.nodes.length > 2) {
27267 var nodes = parent.nodes,
27268 i = nodes.indexOf(id);
27272 } else if (i === nodes.length - 1) {
27275 var a = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
27276 b = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
27277 i = a < b ? i - 1 : i + 1;
27280 nextSelectedID = nodes[i];
27284 if (nextSelectedID && context.hasEntity(nextSelectedID)) {
27285 context.enter(iD.modes.Select(context, [nextSelectedID]));
27287 context.enter(iD.modes.Browse(context));
27295 operation.available = function() {
27299 operation.disabled = function() {
27301 if (_.some(selectedIDs, context.hasHiddenConnections)) {
27302 reason = 'connected_to_hidden';
27304 return action.disabled(context.graph()) || reason;
27307 operation.tooltip = function() {
27308 var disable = operation.disabled();
27310 t('operations.delete.' + disable) :
27311 t('operations.delete.description');
27314 operation.id = 'delete';
27315 operation.keys = [iD.ui.cmd('⌘⌫'), iD.ui.cmd('⌘⌦')];
27316 operation.title = t('operations.delete.title');
27320 iD.operations.Disconnect = function(selectedIDs, context) {
27321 var vertices = _.filter(selectedIDs, function vertex(entityId) {
27322 return context.geometry(entityId) === 'vertex';
27325 var entityId = vertices[0],
27326 action = iD.actions.Disconnect(entityId);
27328 if (selectedIDs.length > 1) {
27329 action.limitWays(_.without(selectedIDs, entityId));
27332 var operation = function() {
27333 context.perform(action, t('operations.disconnect.annotation'));
27336 operation.available = function() {
27337 return vertices.length === 1;
27340 operation.disabled = function() {
27342 if (_.some(selectedIDs, context.hasHiddenConnections)) {
27343 reason = 'connected_to_hidden';
27345 return action.disabled(context.graph()) || reason;
27348 operation.tooltip = function() {
27349 var disable = operation.disabled();
27351 t('operations.disconnect.' + disable) :
27352 t('operations.disconnect.description');
27355 operation.id = 'disconnect';
27356 operation.keys = [t('operations.disconnect.key')];
27357 operation.title = t('operations.disconnect.title');
27361 iD.operations.Merge = function(selectedIDs, context) {
27362 var join = iD.actions.Join(selectedIDs),
27363 merge = iD.actions.Merge(selectedIDs),
27364 mergePolygon = iD.actions.MergePolygon(selectedIDs);
27366 var operation = function() {
27367 var annotation = t('operations.merge.annotation', {n: selectedIDs.length}),
27370 if (!join.disabled(context.graph())) {
27372 } else if (!merge.disabled(context.graph())) {
27375 action = mergePolygon;
27378 context.perform(action, annotation);
27379 context.enter(iD.modes.Select(context, selectedIDs.filter(function(id) { return context.hasEntity(id); }))
27380 .suppressMenu(true));
27383 operation.available = function() {
27384 return selectedIDs.length >= 2;
27387 operation.disabled = function() {
27388 return join.disabled(context.graph()) &&
27389 merge.disabled(context.graph()) &&
27390 mergePolygon.disabled(context.graph());
27393 operation.tooltip = function() {
27394 var j = join.disabled(context.graph()),
27395 m = merge.disabled(context.graph()),
27396 p = mergePolygon.disabled(context.graph());
27398 if (j === 'restriction' && m && p)
27399 return t('operations.merge.restriction', {relation: context.presets().item('type/restriction').name()});
27401 if (p === 'incomplete_relation' && j && m)
27402 return t('operations.merge.incomplete_relation');
27405 return t('operations.merge.' + j);
27407 return t('operations.merge.description');
27410 operation.id = 'merge';
27411 operation.keys = [t('operations.merge.key')];
27412 operation.title = t('operations.merge.title');
27416 iD.operations.Move = function(selectedIDs, context) {
27417 var extent = selectedIDs.reduce(function(extent, id) {
27418 return extent.extend(context.entity(id).extent(context.graph()));
27419 }, iD.geo.Extent());
27421 var operation = function() {
27422 context.enter(iD.modes.Move(context, selectedIDs));
27425 operation.available = function() {
27426 return selectedIDs.length > 1 ||
27427 context.entity(selectedIDs[0]).type !== 'node';
27430 operation.disabled = function() {
27432 if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
27433 reason = 'too_large';
27434 } else if (_.some(selectedIDs, context.hasHiddenConnections)) {
27435 reason = 'connected_to_hidden';
27437 return iD.actions.Move(selectedIDs).disabled(context.graph()) || reason;
27440 operation.tooltip = function() {
27441 var disable = operation.disabled();
27443 t('operations.move.' + disable) :
27444 t('operations.move.description');
27447 operation.id = 'move';
27448 operation.keys = [t('operations.move.key')];
27449 operation.title = t('operations.move.title');
27453 iD.operations.Orthogonalize = function(selectedIDs, context) {
27454 var entityId = selectedIDs[0],
27455 entity = context.entity(entityId),
27456 extent = entity.extent(context.graph()),
27457 geometry = context.geometry(entityId),
27458 action = iD.actions.Orthogonalize(entityId, context.projection);
27460 var operation = function() {
27461 var annotation = t('operations.orthogonalize.annotation.' + geometry);
27462 context.perform(action, annotation);
27465 operation.available = function() {
27466 return selectedIDs.length === 1 &&
27467 entity.type === 'way' &&
27468 entity.isClosed() &&
27469 _.uniq(entity.nodes).length > 2;
27472 operation.disabled = function() {
27474 if (extent.percentContainedIn(context.extent()) < 0.8) {
27475 reason = 'too_large';
27476 } else if (context.hasHiddenConnections(entityId)) {
27477 reason = 'connected_to_hidden';
27479 return action.disabled(context.graph()) || reason;
27482 operation.tooltip = function() {
27483 var disable = operation.disabled();
27485 t('operations.orthogonalize.' + disable) :
27486 t('operations.orthogonalize.description.' + geometry);
27489 operation.id = 'orthogonalize';
27490 operation.keys = [t('operations.orthogonalize.key')];
27491 operation.title = t('operations.orthogonalize.title');
27495 iD.operations.Reverse = function(selectedIDs, context) {
27496 var entityId = selectedIDs[0];
27498 var operation = function() {
27500 iD.actions.Reverse(entityId),
27501 t('operations.reverse.annotation'));
27504 operation.available = function() {
27505 return selectedIDs.length === 1 &&
27506 context.geometry(entityId) === 'line';
27509 operation.disabled = function() {
27513 operation.tooltip = function() {
27514 return t('operations.reverse.description');
27517 operation.id = 'reverse';
27518 operation.keys = [t('operations.reverse.key')];
27519 operation.title = t('operations.reverse.title');
27523 iD.operations.Rotate = function(selectedIDs, context) {
27524 var entityId = selectedIDs[0],
27525 entity = context.entity(entityId),
27526 extent = entity.extent(context.graph()),
27527 geometry = context.geometry(entityId);
27529 var operation = function() {
27530 context.enter(iD.modes.RotateWay(context, entityId));
27533 operation.available = function() {
27534 if (selectedIDs.length !== 1 || entity.type !== 'way')
27536 if (geometry === 'area')
27538 if (entity.isClosed() &&
27539 context.graph().parentRelations(entity).some(function(r) { return r.isMultipolygon(); }))
27544 operation.disabled = function() {
27545 if (extent.percentContainedIn(context.extent()) < 0.8) {
27546 return 'too_large';
27547 } else if (context.hasHiddenConnections(entityId)) {
27548 return 'connected_to_hidden';
27554 operation.tooltip = function() {
27555 var disable = operation.disabled();
27557 t('operations.rotate.' + disable) :
27558 t('operations.rotate.description');
27561 operation.id = 'rotate';
27562 operation.keys = [t('operations.rotate.key')];
27563 operation.title = t('operations.rotate.title');
27567 iD.operations.Split = function(selectedIDs, context) {
27568 var vertices = _.filter(selectedIDs, function vertex(entityId) {
27569 return context.geometry(entityId) === 'vertex';
27572 var entityId = vertices[0],
27573 action = iD.actions.Split(entityId);
27575 if (selectedIDs.length > 1) {
27576 action.limitWays(_.without(selectedIDs, entityId));
27579 var operation = function() {
27582 var ways = action.ways(context.graph());
27583 if (ways.length === 1) {
27584 annotation = t('operations.split.annotation.' + context.geometry(ways[0].id));
27586 annotation = t('operations.split.annotation.multiple', {n: ways.length});
27589 var difference = context.perform(action, annotation);
27590 context.enter(iD.modes.Select(context, difference.extantIDs()));
27593 operation.available = function() {
27594 return vertices.length === 1;
27597 operation.disabled = function() {
27599 if (_.some(selectedIDs, context.hasHiddenConnections)) {
27600 reason = 'connected_to_hidden';
27602 return action.disabled(context.graph()) || reason;
27605 operation.tooltip = function() {
27606 var disable = operation.disabled();
27608 return t('operations.split.' + disable);
27611 var ways = action.ways(context.graph());
27612 if (ways.length === 1) {
27613 return t('operations.split.description.' + context.geometry(ways[0].id));
27615 return t('operations.split.description.multiple');
27619 operation.id = 'split';
27620 operation.keys = [t('operations.split.key')];
27621 operation.title = t('operations.split.title');
27625 iD.operations.Straighten = function(selectedIDs, context) {
27626 var entityId = selectedIDs[0],
27627 action = iD.actions.Straighten(entityId, context.projection);
27629 function operation() {
27630 var annotation = t('operations.straighten.annotation');
27631 context.perform(action, annotation);
27634 operation.available = function() {
27635 var entity = context.entity(entityId);
27636 return selectedIDs.length === 1 &&
27637 entity.type === 'way' &&
27638 !entity.isClosed() &&
27639 _.uniq(entity.nodes).length > 2;
27642 operation.disabled = function() {
27644 if (context.hasHiddenConnections(entityId)) {
27645 reason = 'connected_to_hidden';
27647 return action.disabled(context.graph()) || reason;
27650 operation.tooltip = function() {
27651 var disable = operation.disabled();
27653 t('operations.straighten.' + disable) :
27654 t('operations.straighten.description');
27657 operation.id = 'straighten';
27658 operation.keys = [t('operations.straighten.key')];
27659 operation.title = t('operations.straighten.title');
27663 iD.Connection = function(useHttps) {
27664 if (typeof useHttps !== 'boolean') {
27665 useHttps = window.location.protocol === 'https:';
27668 var event = d3.dispatch('authenticating', 'authenticated', 'auth', 'loading', 'loaded'),
27669 protocol = useHttps ? 'https:' : 'http:',
27670 url = protocol + '//www.openstreetmap.org',
27676 url: protocol + '//www.openstreetmap.org',
27677 oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
27678 oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
27679 loading: authenticating,
27680 done: authenticated
27684 memberStr = 'member',
27687 relationStr = 'relation',
27692 connection.changesetURL = function(changesetId) {
27693 return url + '/changeset/' + changesetId;
27696 connection.changesetsURL = function(center, zoom) {
27697 var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
27698 return url + '/history#map=' +
27699 Math.floor(zoom) + '/' +
27700 center[1].toFixed(precision) + '/' +
27701 center[0].toFixed(precision);
27704 connection.entityURL = function(entity) {
27705 return url + '/' + entity.type + '/' + entity.osmId();
27708 connection.userURL = function(username) {
27709 return url + '/user/' + username;
27712 connection.loadFromURL = function(url, callback) {
27713 function done(err, dom) {
27714 return callback(err, parse(dom));
27716 return d3.xml(url).get(done);
27719 connection.loadEntity = function(id, callback) {
27720 var type = iD.Entity.id.type(id),
27721 osmID = iD.Entity.id.toOSM(id);
27723 connection.loadFromURL(
27724 url + '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
27725 function(err, entities) {
27726 if (callback) callback(err, {data: entities});
27730 connection.loadEntityVersion = function(id, version, callback) {
27731 var type = iD.Entity.id.type(id),
27732 osmID = iD.Entity.id.toOSM(id);
27734 connection.loadFromURL(
27735 url + '/api/0.6/' + type + '/' + osmID + '/' + version,
27736 function(err, entities) {
27737 if (callback) callback(err, {data: entities});
27741 connection.loadMultiple = function(ids, callback) {
27742 _.each(_.groupBy(_.uniq(ids), iD.Entity.id.type), function(v, k) {
27743 var type = k + 's',
27744 osmIDs = _.map(v, iD.Entity.id.toOSM);
27746 _.each(_.chunk(osmIDs, 150), function(arr) {
27747 connection.loadFromURL(
27748 url + '/api/0.6/' + type + '?' + type + '=' + arr.join(),
27749 function(err, entities) {
27750 if (callback) callback(err, {data: entities});
27756 function authenticating() {
27757 event.authenticating();
27760 function authenticated() {
27761 event.authenticated();
27764 function getLoc(attrs) {
27765 var lon = attrs.lon && attrs.lon.value,
27766 lat = attrs.lat && attrs.lat.value;
27767 return [parseFloat(lon), parseFloat(lat)];
27770 function getNodes(obj) {
27771 var elems = obj.getElementsByTagName(ndStr),
27772 nodes = new Array(elems.length);
27773 for (var i = 0, l = elems.length; i < l; i++) {
27774 nodes[i] = 'n' + elems[i].attributes.ref.value;
27779 function getTags(obj) {
27780 var elems = obj.getElementsByTagName(tagStr),
27782 for (var i = 0, l = elems.length; i < l; i++) {
27783 var attrs = elems[i].attributes;
27784 tags[attrs.k.value] = attrs.v.value;
27789 function getMembers(obj) {
27790 var elems = obj.getElementsByTagName(memberStr),
27791 members = new Array(elems.length);
27792 for (var i = 0, l = elems.length; i < l; i++) {
27793 var attrs = elems[i].attributes;
27795 id: attrs.type.value[0] + attrs.ref.value,
27796 type: attrs.type.value,
27797 role: attrs.role.value
27803 function getVisible(attrs) {
27804 return (!attrs.visible || attrs.visible.value !== 'false');
27808 node: function nodeData(obj) {
27809 var attrs = obj.attributes;
27810 return new iD.Node({
27811 id: iD.Entity.id.fromOSM(nodeStr, attrs.id.value),
27812 loc: getLoc(attrs),
27813 version: attrs.version.value,
27814 user: attrs.user && attrs.user.value,
27815 tags: getTags(obj),
27816 visible: getVisible(attrs)
27820 way: function wayData(obj) {
27821 var attrs = obj.attributes;
27822 return new iD.Way({
27823 id: iD.Entity.id.fromOSM(wayStr, attrs.id.value),
27824 version: attrs.version.value,
27825 user: attrs.user && attrs.user.value,
27826 tags: getTags(obj),
27827 nodes: getNodes(obj),
27828 visible: getVisible(attrs)
27832 relation: function relationData(obj) {
27833 var attrs = obj.attributes;
27834 return new iD.Relation({
27835 id: iD.Entity.id.fromOSM(relationStr, attrs.id.value),
27836 version: attrs.version.value,
27837 user: attrs.user && attrs.user.value,
27838 tags: getTags(obj),
27839 members: getMembers(obj),
27840 visible: getVisible(attrs)
27845 function parse(dom) {
27846 if (!dom || !dom.childNodes) return;
27848 var root = dom.childNodes[0],
27849 children = root.childNodes,
27852 for (var i = 0, l = children.length; i < l; i++) {
27853 var child = children[i],
27854 parser = parsers[child.nodeName];
27856 entities.push(parser(child));
27863 connection.authenticated = function() {
27864 return oauth.authenticated();
27867 // Generate Changeset XML. Returns a string.
27868 connection.changesetJXON = function(tags) {
27872 tag: _.map(tags, function(value, key) {
27873 return { '@k': key, '@v': value };
27882 // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
27883 // XML. Returns a string.
27884 connection.osmChangeJXON = function(changeset_id, changes) {
27885 function nest(x, order) {
27887 for (var i = 0; i < x.length; i++) {
27888 var tagName = Object.keys(x[i])[0];
27889 if (!groups[tagName]) groups[tagName] = [];
27890 groups[tagName].push(x[i][tagName]);
27893 order.forEach(function(o) {
27894 if (groups[o]) ordered[o] = groups[o];
27899 function rep(entity) {
27900 return entity.asJXON(changeset_id);
27906 '@generator': 'iD',
27907 'create': nest(changes.created.map(rep), ['node', 'way', 'relation']),
27908 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
27909 'delete': _.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {'@if-unused': true})
27914 connection.changesetTags = function(comment, imageryUsed) {
27915 var detected = iD.detect(),
27917 created_by: 'iD ' + iD.version,
27918 imagery_used: imageryUsed.join(';').substr(0, 255),
27919 host: (window.location.origin + window.location.pathname).substr(0, 255),
27920 locale: detected.locale
27924 tags.comment = comment.substr(0, 255);
27930 connection.putChangeset = function(changes, comment, imageryUsed, callback) {
27933 path: '/api/0.6/changeset/create',
27934 options: { header: { 'Content-Type': 'text/xml' } },
27935 content: JXON.stringify(connection.changesetJXON(connection.changesetTags(comment, imageryUsed)))
27936 }, function(err, changeset_id) {
27937 if (err) return callback(err);
27940 path: '/api/0.6/changeset/' + changeset_id + '/upload',
27941 options: { header: { 'Content-Type': 'text/xml' } },
27942 content: JXON.stringify(connection.osmChangeJXON(changeset_id, changes))
27944 if (err) return callback(err);
27945 // POST was successful, safe to call the callback.
27946 // Still attempt to close changeset, but ignore response because #2667
27947 // Add delay to allow for postgres replication #1646 #2678
27948 window.setTimeout(function() { callback(null, changeset_id); }, 2500);
27951 path: '/api/0.6/changeset/' + changeset_id + '/close',
27952 options: { header: { 'Content-Type': 'text/xml' } }
27953 }, d3.functor(true));
27958 connection.userDetails = function(callback) {
27960 callback(undefined, userDetails);
27964 function done(err, user_details) {
27965 if (err) return callback(err);
27967 var u = user_details.getElementsByTagName('user')[0],
27968 img = u.getElementsByTagName('img'),
27971 if (img && img[0] && img[0].getAttribute('href')) {
27972 image_url = img[0].getAttribute('href');
27976 display_name: u.attributes.display_name.value,
27977 image_url: image_url,
27978 id: u.attributes.id.value
27981 callback(undefined, userDetails);
27984 oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
27987 connection.userChangesets = function(callback) {
27988 connection.userDetails(function(err, user) {
27989 if (err) return callback(err);
27991 function done(changesets) {
27992 callback(undefined, Array.prototype.map.call(changesets.getElementsByTagName('changeset'),
27993 function (changeset) {
27994 return { tags: getTags(changeset) };
27998 d3.xml(url + '/api/0.6/changesets?user=' + user.id).get()
28000 .on('error', callback);
28004 connection.status = function(callback) {
28005 function done(capabilities) {
28006 var apiStatus = capabilities.getElementsByTagName('status');
28007 callback(undefined, apiStatus[0].getAttribute('api'));
28009 d3.xml(url + '/api/capabilities').get()
28011 .on('error', callback);
28014 function abortRequest(i) { i.abort(); }
28016 connection.tileZoom = function(_) {
28017 if (!arguments.length) return tileZoom;
28022 connection.loadTiles = function(projection, dimensions, callback) {
28026 var s = projection.scale() * 2 * Math.PI,
28027 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
28028 ts = 256 * Math.pow(2, z - tileZoom),
28030 s / 2 - projection.translate()[0],
28031 s / 2 - projection.translate()[1]];
28033 var tiles = d3.geo.tile()
28034 .scaleExtent([tileZoom, tileZoom])
28037 .translate(projection.translate())()
28038 .map(function(tile) {
28039 var x = tile[0] * ts - origin[0],
28040 y = tile[1] * ts - origin[1];
28043 id: tile.toString(),
28044 extent: iD.geo.Extent(
28045 projection.invert([x, y + ts]),
28046 projection.invert([x + ts, y]))
28050 function bboxUrl(tile) {
28051 return url + '/api/0.6/map?bbox=' + tile.extent.toParam();
28054 _.filter(inflight, function(v, i) {
28055 var wanted = _.find(tiles, function(tile) {
28056 return i === tile.id;
28058 if (!wanted) delete inflight[i];
28060 }).map(abortRequest);
28062 tiles.forEach(function(tile) {
28065 if (loadedTiles[id] || inflight[id]) return;
28067 if (_.isEmpty(inflight)) {
28071 inflight[id] = connection.loadFromURL(bboxUrl(tile), function(err, parsed) {
28072 loadedTiles[id] = true;
28073 delete inflight[id];
28075 if (callback) callback(err, _.extend({data: parsed}, tile));
28077 if (_.isEmpty(inflight)) {
28084 connection.switch = function(options) {
28086 oauth.options(_.extend({
28087 loading: authenticating,
28088 done: authenticated
28091 connection.flush();
28095 connection.toggle = function(_) {
28100 connection.flush = function() {
28101 userDetails = undefined;
28102 _.forEach(inflight, abortRequest);
28108 connection.loadedTiles = function(_) {
28109 if (!arguments.length) return loadedTiles;
28114 connection.logout = function() {
28115 userDetails = undefined;
28121 connection.authenticate = function(callback) {
28122 userDetails = undefined;
28123 function done(err, res) {
28125 if (callback) callback(err, res);
28127 return oauth.authenticate(done);
28130 return d3.rebind(connection, event, 'on');
28133 iD.Difference represents the difference between two graphs.
28134 It knows how to calculate the set of entities that were
28135 created, modified, or deleted, and also contains the logic
28136 for recursively extending a difference to the complete set
28137 of entities that will require a redraw, taking into account
28138 child and parent relationships.
28140 iD.Difference = function(base, head) {
28141 var changes = {}, length = 0;
28143 function changed(h, b) {
28144 return h !== b && !_.isEqual(_.omit(h, 'v'), _.omit(b, 'v'));
28147 _.each(head.entities, function(h, id) {
28148 var b = base.entities[id];
28149 if (changed(h, b)) {
28150 changes[id] = {base: b, head: h};
28155 _.each(base.entities, function(b, id) {
28156 var h = head.entities[id];
28157 if (!changes[id] && changed(h, b)) {
28158 changes[id] = {base: b, head: h};
28163 function addParents(parents, result) {
28164 for (var i = 0; i < parents.length; i++) {
28165 var parent = parents[i];
28167 if (parent.id in result)
28170 result[parent.id] = parent;
28171 addParents(head.parentRelations(parent), result);
28175 var difference = {};
28177 difference.length = function() {
28181 difference.changes = function() {
28185 difference.extantIDs = function() {
28187 _.each(changes, function(change, id) {
28188 if (change.head) result.push(id);
28193 difference.modified = function() {
28195 _.each(changes, function(change) {
28196 if (change.base && change.head) result.push(change.head);
28201 difference.created = function() {
28203 _.each(changes, function(change) {
28204 if (!change.base && change.head) result.push(change.head);
28209 difference.deleted = function() {
28211 _.each(changes, function(change) {
28212 if (change.base && !change.head) result.push(change.base);
28217 difference.summary = function() {
28220 function addEntity(entity, graph, changeType) {
28221 relevant[entity.id] = {
28224 changeType: changeType
28228 function addParents(entity) {
28229 var parents = head.parentWays(entity);
28230 for (var j = parents.length - 1; j >= 0; j--) {
28231 var parent = parents[j];
28232 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
28236 _.each(changes, function(change) {
28237 if (change.head && change.head.geometry(head) !== 'vertex') {
28238 addEntity(change.head, head, change.base ? 'modified' : 'created');
28240 } else if (change.base && change.base.geometry(base) !== 'vertex') {
28241 addEntity(change.base, base, 'deleted');
28243 } else if (change.base && change.head) { // modified vertex
28244 var moved = !_.isEqual(change.base.loc, change.head.loc),
28245 retagged = !_.isEqual(change.base.tags, change.head.tags);
28248 addParents(change.head);
28251 if (retagged || (moved && change.head.hasInterestingTags())) {
28252 addEntity(change.head, head, 'modified');
28255 } else if (change.head && change.head.hasInterestingTags()) { // created vertex
28256 addEntity(change.head, head, 'created');
28258 } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
28259 addEntity(change.base, base, 'deleted');
28263 return d3.values(relevant);
28266 difference.complete = function(extent) {
28267 var result = {}, id, change;
28269 for (id in changes) {
28270 change = changes[id];
28272 var h = change.head,
28277 (!h || !h.intersects(extent, head)) &&
28278 (!b || !b.intersects(extent, base)))
28283 if (entity.type === 'way') {
28284 var nh = h ? h.nodes : [],
28285 nb = b ? b.nodes : [],
28288 diff = _.difference(nh, nb);
28289 for (i = 0; i < diff.length; i++) {
28290 result[diff[i]] = head.hasEntity(diff[i]);
28293 diff = _.difference(nb, nh);
28294 for (i = 0; i < diff.length; i++) {
28295 result[diff[i]] = head.hasEntity(diff[i]);
28299 addParents(head.parentWays(entity), result);
28300 addParents(head.parentRelations(entity), result);
28308 iD.Entity = function(attrs) {
28309 // For prototypal inheritance.
28310 if (this instanceof iD.Entity) return;
28312 // Create the appropriate subtype.
28313 if (attrs && attrs.type) {
28314 return iD.Entity[attrs.type].apply(this, arguments);
28315 } else if (attrs && attrs.id) {
28316 return iD.Entity[iD.Entity.id.type(attrs.id)].apply(this, arguments);
28319 // Initialize a generic Entity (used only in tests).
28320 return (new iD.Entity()).initialize(arguments);
28323 iD.Entity.id = function(type) {
28324 return iD.Entity.id.fromOSM(type, iD.Entity.id.next[type]--);
28327 iD.Entity.id.next = {node: -1, way: -1, relation: -1};
28329 iD.Entity.id.fromOSM = function(type, id) {
28330 return type[0] + id;
28333 iD.Entity.id.toOSM = function(id) {
28334 return id.slice(1);
28337 iD.Entity.id.type = function(id) {
28338 return {'n': 'node', 'w': 'way', 'r': 'relation'}[id[0]];
28341 // A function suitable for use as the second argument to d3.selection#data().
28342 iD.Entity.key = function(entity) {
28343 return entity.id + 'v' + (entity.v || 0);
28346 iD.Entity.prototype = {
28349 initialize: function(sources) {
28350 for (var i = 0; i < sources.length; ++i) {
28351 var source = sources[i];
28352 for (var prop in source) {
28353 if (Object.prototype.hasOwnProperty.call(source, prop)) {
28354 if (source[prop] === undefined) {
28357 this[prop] = source[prop];
28363 if (!this.id && this.type) {
28364 this.id = iD.Entity.id(this.type);
28366 if (!this.hasOwnProperty('visible')) {
28367 this.visible = true;
28371 Object.freeze(this);
28372 Object.freeze(this.tags);
28374 if (this.loc) Object.freeze(this.loc);
28375 if (this.nodes) Object.freeze(this.nodes);
28376 if (this.members) Object.freeze(this.members);
28382 copy: function(resolver, copies) {
28383 if (copies[this.id])
28384 return copies[this.id];
28386 var copy = iD.Entity(this, {id: undefined, user: undefined, version: undefined});
28387 copies[this.id] = copy;
28392 osmId: function() {
28393 return iD.Entity.id.toOSM(this.id);
28396 isNew: function() {
28397 return this.osmId() < 0;
28400 update: function(attrs) {
28401 return iD.Entity(this, attrs, {v: 1 + (this.v || 0)});
28404 mergeTags: function(tags) {
28405 var merged = _.clone(this.tags), changed = false;
28406 for (var k in tags) {
28407 var t1 = merged[k],
28412 } else if (t1 !== t2) {
28414 merged[k] = _.union(t1.split(/;\s*/), t2.split(/;\s*/)).join(';');
28417 return changed ? this.update({tags: merged}) : this;
28420 intersects: function(extent, resolver) {
28421 return this.extent(resolver).intersects(extent);
28424 isUsed: function(resolver) {
28425 return _.without(Object.keys(this.tags), 'area').length > 0 ||
28426 resolver.parentRelations(this).length > 0;
28429 hasInterestingTags: function() {
28430 return _.keys(this.tags).some(iD.interestingTag);
28433 isHighwayIntersection: function() {
28437 deprecatedTags: function() {
28438 var tags = _.toPairs(this.tags);
28439 var deprecated = {};
28441 iD.data.deprecated.forEach(function(d) {
28442 var match = _.toPairs(d.old)[0];
28443 tags.forEach(function(t) {
28444 if (t[0] === match[0] &&
28445 (t[1] === match[1] || match[1] === '*')) {
28446 deprecated[t[0]] = t[1];
28454 iD.Graph = function(other, mutable) {
28455 if (!(this instanceof iD.Graph)) return new iD.Graph(other, mutable);
28457 if (other instanceof iD.Graph) {
28458 var base = other.base();
28459 this.entities = _.assign(Object.create(base.entities), other.entities);
28460 this._parentWays = _.assign(Object.create(base.parentWays), other._parentWays);
28461 this._parentRels = _.assign(Object.create(base.parentRels), other._parentRels);
28464 this.entities = Object.create({});
28465 this._parentWays = Object.create({});
28466 this._parentRels = Object.create({});
28467 this.rebase(other || [], [this]);
28470 this.transients = {};
28471 this._childNodes = {};
28472 this.frozen = !mutable;
28475 iD.Graph.prototype = {
28476 hasEntity: function(id) {
28477 return this.entities[id];
28480 entity: function(id) {
28481 var entity = this.entities[id];
28483 throw new Error('entity ' + id + ' not found');
28488 transient: function(entity, key, fn) {
28489 var id = entity.id,
28490 transients = this.transients[id] ||
28491 (this.transients[id] = {});
28493 if (transients[key] !== undefined) {
28494 return transients[key];
28497 transients[key] = fn.call(entity);
28499 return transients[key];
28502 parentWays: function(entity) {
28503 var parents = this._parentWays[entity.id],
28507 for (var i = 0; i < parents.length; i++) {
28508 result.push(this.entity(parents[i]));
28514 isPoi: function(entity) {
28515 var parentWays = this._parentWays[entity.id];
28516 return !parentWays || parentWays.length === 0;
28519 isShared: function(entity) {
28520 var parentWays = this._parentWays[entity.id];
28521 return parentWays && parentWays.length > 1;
28524 parentRelations: function(entity) {
28525 var parents = this._parentRels[entity.id],
28529 for (var i = 0; i < parents.length; i++) {
28530 result.push(this.entity(parents[i]));
28536 childNodes: function(entity) {
28537 if (this._childNodes[entity.id]) return this._childNodes[entity.id];
28538 if (!entity.nodes) return [];
28541 for (var i = 0; i < entity.nodes.length; i++) {
28542 nodes[i] = this.entity(entity.nodes[i]);
28545 if (iD.debug) Object.freeze(nodes);
28547 this._childNodes[entity.id] = nodes;
28548 return this._childNodes[entity.id];
28553 'entities': iD.util.getPrototypeOf(this.entities),
28554 'parentWays': iD.util.getPrototypeOf(this._parentWays),
28555 'parentRels': iD.util.getPrototypeOf(this._parentRels)
28559 // Unlike other graph methods, rebase mutates in place. This is because it
28560 // is used only during the history operation that merges newly downloaded
28561 // data into each state. To external consumers, it should appear as if the
28562 // graph always contained the newly downloaded data.
28563 rebase: function(entities, stack, force) {
28564 var base = this.base(),
28567 for (i = 0; i < entities.length; i++) {
28568 var entity = entities[i];
28570 if (!entity.visible || (!force && base.entities[entity.id]))
28573 // Merging data into the base graph
28574 base.entities[entity.id] = entity;
28575 this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
28577 // Restore provisionally-deleted nodes that are discovered to have an extant parent
28578 if (entity.type === 'way') {
28579 for (j = 0; j < entity.nodes.length; j++) {
28580 id = entity.nodes[j];
28581 for (k = 1; k < stack.length; k++) {
28582 var ents = stack[k].entities;
28583 if (ents.hasOwnProperty(id) && ents[id] === undefined) {
28591 for (i = 0; i < stack.length; i++) {
28592 stack[i]._updateRebased();
28596 _updateRebased: function() {
28597 var base = this.base(),
28598 i, k, child, id, keys;
28600 keys = Object.keys(this._parentWays);
28601 for (i = 0; i < keys.length; i++) {
28603 if (base.parentWays[child]) {
28604 for (k = 0; k < base.parentWays[child].length; k++) {
28605 id = base.parentWays[child][k];
28606 if (!this.entities.hasOwnProperty(id) && !_.includes(this._parentWays[child], id)) {
28607 this._parentWays[child].push(id);
28613 keys = Object.keys(this._parentRels);
28614 for (i = 0; i < keys.length; i++) {
28616 if (base.parentRels[child]) {
28617 for (k = 0; k < base.parentRels[child].length; k++) {
28618 id = base.parentRels[child][k];
28619 if (!this.entities.hasOwnProperty(id) && !_.includes(this._parentRels[child], id)) {
28620 this._parentRels[child].push(id);
28626 this.transients = {};
28628 // this._childNodes is not updated, under the assumption that
28629 // ways are always downloaded with their child nodes.
28632 // Updates calculated properties (parentWays, parentRels) for the specified change
28633 _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
28635 parentWays = parentWays || this._parentWays;
28636 parentRels = parentRels || this._parentRels;
28638 var type = entity && entity.type || oldentity && oldentity.type,
28639 removed, added, ways, rels, i;
28642 if (type === 'way') {
28644 // Update parentWays
28645 if (oldentity && entity) {
28646 removed = _.difference(oldentity.nodes, entity.nodes);
28647 added = _.difference(entity.nodes, oldentity.nodes);
28648 } else if (oldentity) {
28649 removed = oldentity.nodes;
28651 } else if (entity) {
28653 added = entity.nodes;
28655 for (i = 0; i < removed.length; i++) {
28656 parentWays[removed[i]] = _.without(parentWays[removed[i]], oldentity.id);
28658 for (i = 0; i < added.length; i++) {
28659 ways = _.without(parentWays[added[i]], entity.id);
28660 ways.push(entity.id);
28661 parentWays[added[i]] = ways;
28664 } else if (type === 'relation') {
28666 // Update parentRels
28667 if (oldentity && entity) {
28668 removed = _.difference(oldentity.members, entity.members);
28669 added = _.difference(entity.members, oldentity);
28670 } else if (oldentity) {
28671 removed = oldentity.members;
28673 } else if (entity) {
28675 added = entity.members;
28677 for (i = 0; i < removed.length; i++) {
28678 parentRels[removed[i].id] = _.without(parentRels[removed[i].id], oldentity.id);
28680 for (i = 0; i < added.length; i++) {
28681 rels = _.without(parentRels[added[i].id], entity.id);
28682 rels.push(entity.id);
28683 parentRels[added[i].id] = rels;
28688 replace: function(entity) {
28689 if (this.entities[entity.id] === entity)
28692 return this.update(function() {
28693 this._updateCalculated(this.entities[entity.id], entity);
28694 this.entities[entity.id] = entity;
28698 remove: function(entity) {
28699 return this.update(function() {
28700 this._updateCalculated(entity, undefined);
28701 this.entities[entity.id] = undefined;
28705 revert: function(id) {
28706 var baseEntity = this.base().entities[id],
28707 headEntity = this.entities[id];
28709 if (headEntity === baseEntity)
28712 return this.update(function() {
28713 this._updateCalculated(headEntity, baseEntity);
28714 delete this.entities[id];
28718 update: function() {
28719 var graph = this.frozen ? iD.Graph(this, true) : this;
28721 for (var i = 0; i < arguments.length; i++) {
28722 arguments[i].call(graph, graph);
28725 if (this.frozen) graph.frozen = true;
28730 // Obliterates any existing entities
28731 load: function(entities) {
28732 var base = this.base();
28733 this.entities = Object.create(base.entities);
28735 for (var i in entities) {
28736 this.entities[i] = entities[i];
28737 this._updateCalculated(base.entities[i], this.entities[i]);
28743 iD.History = function(context) {
28744 var stack, index, tree,
28745 imageryUsed = ['Bing'],
28746 dispatch = d3.dispatch('change', 'undone', 'redone'),
28747 lock = iD.util.SessionMutex('lock');
28749 function perform(actions) {
28750 actions = Array.prototype.slice.call(actions);
28754 if (!_.isFunction(_.last(actions))) {
28755 annotation = actions.pop();
28758 var graph = stack[index].graph;
28759 for (var i = 0; i < actions.length; i++) {
28760 graph = actions[i](graph);
28765 annotation: annotation,
28766 imageryUsed: imageryUsed
28770 function change(previous) {
28771 var difference = iD.Difference(previous, history.graph());
28772 dispatch.change(difference);
28776 // iD uses namespaced keys so multiple installations do not conflict
28777 function getKey(n) {
28778 return 'iD_' + window.location.origin + '_' + n;
28782 graph: function() {
28783 return stack[index].graph;
28787 return stack[0].graph;
28790 merge: function(entities, extent) {
28791 stack[0].graph.rebase(entities, _.map(stack, 'graph'), false);
28792 tree.rebase(entities, false);
28794 dispatch.change(undefined, extent);
28797 perform: function() {
28798 var previous = stack[index].graph;
28800 stack = stack.slice(0, index + 1);
28801 stack.push(perform(arguments));
28804 return change(previous);
28807 replace: function() {
28808 var previous = stack[index].graph;
28810 // assert(index == stack.length - 1)
28811 stack[index] = perform(arguments);
28813 return change(previous);
28817 var previous = stack[index].graph;
28822 return change(previous);
28826 // Same as calling pop and then perform
28827 overwrite: function() {
28828 var previous = stack[index].graph;
28834 stack = stack.slice(0, index + 1);
28835 stack.push(perform(arguments));
28838 return change(previous);
28842 var previous = stack[index].graph;
28844 // Pop to the next annotated state.
28845 while (index > 0) {
28847 if (stack[index].annotation) break;
28851 return change(previous);
28855 var previous = stack[index].graph;
28857 while (index < stack.length - 1) {
28859 if (stack[index].annotation) break;
28863 return change(previous);
28866 undoAnnotation: function() {
28869 if (stack[i].annotation) return stack[i].annotation;
28874 redoAnnotation: function() {
28876 while (i <= stack.length - 1) {
28877 if (stack[i].annotation) return stack[i].annotation;
28882 intersects: function(extent) {
28883 return tree.intersects(extent, stack[index].graph);
28886 difference: function() {
28887 var base = stack[0].graph,
28888 head = stack[index].graph;
28889 return iD.Difference(base, head);
28892 changes: function(action) {
28893 var base = stack[0].graph,
28894 head = stack[index].graph;
28897 head = action(head);
28900 var difference = iD.Difference(base, head);
28903 modified: difference.modified(),
28904 created: difference.created(),
28905 deleted: difference.deleted()
28909 validate: function(changes) {
28910 return _(iD.validations)
28911 .map(function(fn) { return fn()(changes, stack[index].graph); })
28916 hasChanges: function() {
28917 return this.difference().length() > 0;
28920 imageryUsed: function(sources) {
28922 imageryUsed = sources;
28925 return _(stack.slice(1, index + 1))
28926 .map('imageryUsed')
28929 .without(undefined, 'Custom')
28934 reset: function() {
28935 stack = [{graph: iD.Graph()}];
28937 tree = iD.Tree(stack[0].graph);
28942 toJSON: function() {
28943 if (!this.hasChanges()) return;
28945 var allEntities = {},
28949 var s = stack.map(function(i) {
28950 var modified = [], deleted = [];
28952 _.forEach(i.graph.entities, function(entity, id) {
28954 var key = iD.Entity.key(entity);
28955 allEntities[key] = entity;
28956 modified.push(key);
28961 // make sure that the originals of changed or deleted entities get merged
28962 // into the base of the stack after restoring the data from JSON.
28963 if (id in base.graph.entities) {
28964 baseEntities[id] = base.graph.entities[id];
28966 // get originals of parent entities too
28967 _.forEach(base.graph._parentWays[id], function(parentId) {
28968 if (parentId in base.graph.entities) {
28969 baseEntities[parentId] = base.graph.entities[parentId];
28976 if (modified.length) x.modified = modified;
28977 if (deleted.length) x.deleted = deleted;
28978 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
28979 if (i.annotation) x.annotation = i.annotation;
28984 return JSON.stringify({
28986 entities: _.values(allEntities),
28987 baseEntities: _.values(baseEntities),
28989 nextIDs: iD.Entity.id.next,
28994 fromJSON: function(json, loadChildNodes) {
28995 var h = JSON.parse(json),
28996 loadComplete = true;
28998 iD.Entity.id.next = h.nextIDs;
29001 if (h.version === 2 || h.version === 3) {
29002 var allEntities = {};
29004 h.entities.forEach(function(entity) {
29005 allEntities[iD.Entity.key(entity)] = iD.Entity(entity);
29008 if (h.version === 3) {
29009 // This merges originals for changed entities into the base of
29010 // the stack even if the current stack doesn't have them (for
29011 // example when iD has been restarted in a different region)
29012 var baseEntities = h.baseEntities.map(function(d) { return iD.Entity(d); });
29013 stack[0].graph.rebase(baseEntities, _.map(stack, 'graph'), true);
29014 tree.rebase(baseEntities, true);
29016 // When we restore a modified way, we also need to fetch any missing
29017 // childnodes that would normally have been downloaded with it.. #2142
29018 if (loadChildNodes) {
29019 var missing = _(baseEntities)
29020 .filter({ type: 'way' })
29024 .reject(function(n) { return stack[0].graph.hasEntity(n); })
29027 if (!_.isEmpty(missing)) {
29028 loadComplete = false;
29029 context.redrawEnable(false);
29031 var loading = iD.ui.Loading(context).blocking(true);
29032 context.container().call(loading);
29034 var childNodesLoaded = function(err, result) {
29036 var visible = _.groupBy(result.data, 'visible');
29037 if (!_.isEmpty(visible.true)) {
29038 missing = _.difference(missing, _.map(visible.true, 'id'));
29039 stack[0].graph.rebase(visible.true, _.map(stack, 'graph'), true);
29040 tree.rebase(visible.true, true);
29043 // fetch older versions of nodes that were deleted..
29044 _.each(visible.false, function(entity) {
29045 context.connection()
29046 .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
29050 if (err || _.isEmpty(missing)) {
29052 context.redrawEnable(true);
29057 context.connection().loadMultiple(missing, childNodesLoaded);
29062 stack = h.stack.map(function(d) {
29063 var entities = {}, entity;
29066 d.modified.forEach(function(key) {
29067 entity = allEntities[key];
29068 entities[entity.id] = entity;
29073 d.deleted.forEach(function(id) {
29074 entities[id] = undefined;
29079 graph: iD.Graph(stack[0].graph).load(entities),
29080 annotation: d.annotation,
29081 imageryUsed: d.imageryUsed
29085 } else { // original version
29086 stack = h.stack.map(function(d) {
29089 for (var i in d.entities) {
29090 var entity = d.entities[i];
29091 entities[i] = entity === 'undefined' ? undefined : iD.Entity(entity);
29094 d.graph = iD.Graph(stack[0].graph).load(entities);
29099 if (loadComplete) {
29107 if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
29111 clearSaved: function() {
29112 context.debouncedSave.cancel();
29113 if (lock.locked()) context.storage(getKey('saved_history'), null);
29118 return lock.lock();
29121 unlock: function() {
29125 // is iD not open in another window and it detects that
29126 // there's a history stored in localStorage that's recoverable?
29127 restorableChanges: function() {
29128 return lock.locked() && !!context.storage(getKey('saved_history'));
29131 // load history from a version stored in localStorage
29132 restore: function() {
29133 if (!lock.locked()) return;
29135 var json = context.storage(getKey('saved_history'));
29136 if (json) history.fromJSON(json, true);
29145 return d3.rebind(history, dispatch, 'on');
29147 iD.Node = iD.Entity.node = function iD_Node() {
29148 if (!(this instanceof iD_Node)) {
29149 return (new iD_Node()).initialize(arguments);
29150 } else if (arguments.length) {
29151 this.initialize(arguments);
29155 iD.Node.prototype = Object.create(iD.Entity.prototype);
29157 _.extend(iD.Node.prototype, {
29160 extent: function() {
29161 return new iD.geo.Extent(this.loc);
29164 geometry: function(graph) {
29165 return graph.transient(this, 'geometry', function() {
29166 return graph.isPoi(this) ? 'point' : 'vertex';
29170 move: function(loc) {
29171 return this.update({loc: loc});
29174 isIntersection: function(resolver) {
29175 return resolver.transient(this, 'isIntersection', function() {
29176 return resolver.parentWays(this).filter(function(parent) {
29177 return (parent.tags.highway ||
29178 parent.tags.waterway ||
29179 parent.tags.railway ||
29180 parent.tags.aeroway) &&
29181 parent.geometry(resolver) === 'line';
29186 isHighwayIntersection: function(resolver) {
29187 return resolver.transient(this, 'isHighwayIntersection', function() {
29188 return resolver.parentWays(this).filter(function(parent) {
29189 return parent.tags.highway && parent.geometry(resolver) === 'line';
29194 asJXON: function(changeset_id) {
29197 '@id': this.osmId(),
29198 '@lon': this.loc[0],
29199 '@lat': this.loc[1],
29200 '@version': (this.version || 0),
29201 tag: _.map(this.tags, function(v, k) {
29202 return { keyAttributes: { k: k, v: v } };
29206 if (changeset_id) r.node['@changeset'] = changeset_id;
29210 asGeoJSON: function() {
29213 coordinates: this.loc
29217 iD.Relation = iD.Entity.relation = function iD_Relation() {
29218 if (!(this instanceof iD_Relation)) {
29219 return (new iD_Relation()).initialize(arguments);
29220 } else if (arguments.length) {
29221 this.initialize(arguments);
29225 iD.Relation.prototype = Object.create(iD.Entity.prototype);
29227 iD.Relation.creationOrder = function(a, b) {
29228 var aId = parseInt(iD.Entity.id.toOSM(a.id), 10);
29229 var bId = parseInt(iD.Entity.id.toOSM(b.id), 10);
29231 if (aId < 0 || bId < 0) return aId - bId;
29235 _.extend(iD.Relation.prototype, {
29239 copy: function(resolver, copies) {
29240 if (copies[this.id])
29241 return copies[this.id];
29243 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
29245 var members = this.members.map(function(member) {
29246 return _.extend({}, member, {id: resolver.entity(member.id).copy(resolver, copies).id});
29249 copy = copy.update({members: members});
29250 copies[this.id] = copy;
29255 extent: function(resolver, memo) {
29256 return resolver.transient(this, 'extent', function() {
29257 if (memo && memo[this.id]) return iD.geo.Extent();
29259 memo[this.id] = true;
29261 var extent = iD.geo.Extent();
29262 for (var i = 0; i < this.members.length; i++) {
29263 var member = resolver.hasEntity(this.members[i].id);
29265 extent._extend(member.extent(resolver, memo));
29272 geometry: function(graph) {
29273 return graph.transient(this, 'geometry', function() {
29274 return this.isMultipolygon() ? 'area' : 'relation';
29278 isDegenerate: function() {
29279 return this.members.length === 0;
29282 // Return an array of members, each extended with an 'index' property whose value
29283 // is the member index.
29284 indexedMembers: function() {
29285 var result = new Array(this.members.length);
29286 for (var i = 0; i < this.members.length; i++) {
29287 result[i] = _.extend({}, this.members[i], {index: i});
29292 // Return the first member with the given role. A copy of the member object
29293 // is returned, extended with an 'index' property whose value is the member index.
29294 memberByRole: function(role) {
29295 for (var i = 0; i < this.members.length; i++) {
29296 if (this.members[i].role === role) {
29297 return _.extend({}, this.members[i], {index: i});
29302 // Return the first member with the given id. A copy of the member object
29303 // is returned, extended with an 'index' property whose value is the member index.
29304 memberById: function(id) {
29305 for (var i = 0; i < this.members.length; i++) {
29306 if (this.members[i].id === id) {
29307 return _.extend({}, this.members[i], {index: i});
29312 // Return the first member with the given id and role. A copy of the member object
29313 // is returned, extended with an 'index' property whose value is the member index.
29314 memberByIdAndRole: function(id, role) {
29315 for (var i = 0; i < this.members.length; i++) {
29316 if (this.members[i].id === id && this.members[i].role === role) {
29317 return _.extend({}, this.members[i], {index: i});
29322 addMember: function(member, index) {
29323 var members = this.members.slice();
29324 members.splice(index === undefined ? members.length : index, 0, member);
29325 return this.update({members: members});
29328 updateMember: function(member, index) {
29329 var members = this.members.slice();
29330 members.splice(index, 1, _.extend({}, members[index], member));
29331 return this.update({members: members});
29334 removeMember: function(index) {
29335 var members = this.members.slice();
29336 members.splice(index, 1);
29337 return this.update({members: members});
29340 removeMembersWithID: function(id) {
29341 var members = _.reject(this.members, function(m) { return m.id === id; });
29342 return this.update({members: members});
29345 // Wherever a member appears with id `needle.id`, replace it with a member
29346 // with id `replacement.id`, type `replacement.type`, and the original role,
29347 // unless a member already exists with that id and role. Return an updated
29349 replaceMember: function(needle, replacement) {
29350 if (!this.memberById(needle.id))
29355 for (var i = 0; i < this.members.length; i++) {
29356 var member = this.members[i];
29357 if (member.id !== needle.id) {
29358 members.push(member);
29359 } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
29360 members.push({id: replacement.id, type: replacement.type, role: member.role});
29364 return this.update({members: members});
29367 asJXON: function(changeset_id) {
29370 '@id': this.osmId(),
29371 '@version': this.version || 0,
29372 member: _.map(this.members, function(member) {
29373 return { keyAttributes: { type: member.type, role: member.role, ref: iD.Entity.id.toOSM(member.id) } };
29375 tag: _.map(this.tags, function(v, k) {
29376 return { keyAttributes: { k: k, v: v } };
29380 if (changeset_id) r.relation['@changeset'] = changeset_id;
29384 asGeoJSON: function(resolver) {
29385 return resolver.transient(this, 'GeoJSON', function () {
29386 if (this.isMultipolygon()) {
29388 type: 'MultiPolygon',
29389 coordinates: this.multipolygon(resolver)
29393 type: 'FeatureCollection',
29394 properties: this.tags,
29395 features: this.members.map(function (member) {
29396 return _.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
29403 area: function(resolver) {
29404 return resolver.transient(this, 'area', function() {
29405 return d3.geo.area(this.asGeoJSON(resolver));
29409 isMultipolygon: function() {
29410 return this.tags.type === 'multipolygon';
29413 isComplete: function(resolver) {
29414 for (var i = 0; i < this.members.length; i++) {
29415 if (!resolver.hasEntity(this.members[i].id)) {
29422 isRestriction: function() {
29423 return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
29426 // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
29427 // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
29429 // This corresponds to the structure needed for rendering a multipolygon path using a
29430 // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
29432 // In the case of invalid geometries, this function will still return a result which
29433 // includes the nodes of all way members, but some Nds may be unclosed and some inner
29434 // rings not matched with the intended outer ring.
29436 multipolygon: function(resolver) {
29437 var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
29438 inners = this.members.filter(function(m) { return 'inner' === m.role; });
29440 outers = iD.geo.joinWays(outers, resolver);
29441 inners = iD.geo.joinWays(inners, resolver);
29443 outers = outers.map(function(outer) { return _.map(outer.nodes, 'loc'); });
29444 inners = inners.map(function(inner) { return _.map(inner.nodes, 'loc'); });
29446 var result = outers.map(function(o) {
29447 // Heuristic for detecting counterclockwise winding order. Assumes
29448 // that OpenStreetMap polygons are not hemisphere-spanning.
29449 return [d3.geo.area({type: 'Polygon', coordinates: [o]}) > 2 * Math.PI ? o.reverse() : o];
29452 function findOuter(inner) {
29455 for (o = 0; o < outers.length; o++) {
29457 if (iD.geo.polygonContainsPolygon(outer, inner))
29461 for (o = 0; o < outers.length; o++) {
29463 if (iD.geo.polygonIntersectsPolygon(outer, inner))
29468 for (var i = 0; i < inners.length; i++) {
29469 var inner = inners[i];
29471 if (d3.geo.area({type: 'Polygon', coordinates: [inner]}) < 2 * Math.PI) {
29472 inner = inner.reverse();
29475 var o = findOuter(inners[i]);
29476 if (o !== undefined)
29477 result[o].push(inners[i]);
29479 result.push([inners[i]]); // Invalid geometry
29487 'chair_lift': true,
29488 'mixed_lift': true,
29493 'magic_carpet': true,
29498 'motorway_link': true
29504 'piste:halfpipe': true
29528 iD.interestingTag = function (key) {
29529 return key !== 'attribution' &&
29530 key !== 'created_by' &&
29531 key !== 'source' &&
29533 key.indexOf('tiger:') !== 0;
29536 iD.Tree = function(head) {
29537 var rtree = rbush(),
29540 function entityRectangle(entity) {
29541 var rect = entity.extent(head).rectangle();
29542 rect.id = entity.id;
29543 rectangles[entity.id] = rect;
29547 function updateParents(entity, insertions, memo) {
29548 head.parentWays(entity).forEach(function(way) {
29549 if (rectangles[way.id]) {
29550 rtree.remove(rectangles[way.id]);
29551 insertions[way.id] = way;
29553 updateParents(way, insertions, memo);
29556 head.parentRelations(entity).forEach(function(relation) {
29557 if (memo[entity.id]) return;
29558 memo[entity.id] = true;
29559 if (rectangles[relation.id]) {
29560 rtree.remove(rectangles[relation.id]);
29561 insertions[relation.id] = relation;
29563 updateParents(relation, insertions, memo);
29569 tree.rebase = function(entities, force) {
29570 var insertions = {};
29572 for (var i = 0; i < entities.length; i++) {
29573 var entity = entities[i];
29575 if (!entity.visible)
29578 if (head.entities.hasOwnProperty(entity.id) || rectangles[entity.id]) {
29581 } else if (rectangles[entity.id]) {
29582 rtree.remove(rectangles[entity.id]);
29586 insertions[entity.id] = entity;
29587 updateParents(entity, insertions, {});
29590 rtree.load(_.map(insertions, entityRectangle));
29595 tree.intersects = function(extent, graph) {
29596 if (graph !== head) {
29597 var diff = iD.Difference(head, graph),
29602 diff.deleted().forEach(function(entity) {
29603 rtree.remove(rectangles[entity.id]);
29604 delete rectangles[entity.id];
29607 diff.modified().forEach(function(entity) {
29608 rtree.remove(rectangles[entity.id]);
29609 insertions[entity.id] = entity;
29610 updateParents(entity, insertions, {});
29613 diff.created().forEach(function(entity) {
29614 insertions[entity.id] = entity;
29617 rtree.load(_.map(insertions, entityRectangle));
29620 return rtree.search(extent.rectangle()).map(function(rect) {
29621 return head.entity(rect.id);
29627 iD.Way = iD.Entity.way = function iD_Way() {
29628 if (!(this instanceof iD_Way)) {
29629 return (new iD_Way()).initialize(arguments);
29630 } else if (arguments.length) {
29631 this.initialize(arguments);
29635 iD.Way.prototype = Object.create(iD.Entity.prototype);
29637 _.extend(iD.Way.prototype, {
29641 copy: function(resolver, copies) {
29642 if (copies[this.id])
29643 return copies[this.id];
29645 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
29647 var nodes = this.nodes.map(function(id) {
29648 return resolver.entity(id).copy(resolver, copies).id;
29651 copy = copy.update({nodes: nodes});
29652 copies[this.id] = copy;
29657 extent: function(resolver) {
29658 return resolver.transient(this, 'extent', function() {
29659 var extent = iD.geo.Extent();
29660 for (var i = 0; i < this.nodes.length; i++) {
29661 var node = resolver.hasEntity(this.nodes[i]);
29663 extent._extend(node.extent());
29670 first: function() {
29671 return this.nodes[0];
29675 return this.nodes[this.nodes.length - 1];
29678 contains: function(node) {
29679 return this.nodes.indexOf(node) >= 0;
29682 affix: function(node) {
29683 if (this.nodes[0] === node) return 'prefix';
29684 if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
29687 layer: function() {
29688 // explicit layer tag, clamp between -10, 10..
29689 if (this.tags.layer !== undefined) {
29690 return Math.max(-10, Math.min(+(this.tags.layer), 10));
29693 // implied layer tag..
29694 if (this.tags.location === 'overground') return 1;
29695 if (this.tags.location === 'underground') return -1;
29696 if (this.tags.location === 'underwater') return -10;
29698 if (this.tags.power === 'line') return 10;
29699 if (this.tags.power === 'minor_line') return 10;
29700 if (this.tags.aerialway) return 10;
29701 if (this.tags.bridge) return 1;
29702 if (this.tags.cutting) return -1;
29703 if (this.tags.tunnel) return -1;
29704 if (this.tags.waterway) return -1;
29705 if (this.tags.man_made === 'pipeline') return -10;
29706 if (this.tags.boundary) return -10;
29710 isOneWay: function() {
29711 // explicit oneway tag..
29712 if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
29713 if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
29715 // implied oneway tag..
29716 for (var key in this.tags) {
29717 if (key in iD.oneWayTags && (this.tags[key] in iD.oneWayTags[key]))
29723 isClosed: function() {
29724 return this.nodes.length > 0 && this.first() === this.last();
29727 isConvex: function(resolver) {
29728 if (!this.isClosed() || this.isDegenerate()) return null;
29730 var nodes = _.uniq(resolver.childNodes(this)),
29731 coords = _.map(nodes, 'loc'),
29732 curr = 0, prev = 0;
29734 for (var i = 0; i < coords.length; i++) {
29735 var o = coords[(i+1) % coords.length],
29737 b = coords[(i+2) % coords.length],
29738 res = iD.geo.cross(o, a, b);
29740 curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
29743 } else if (prev && curr !== prev) {
29751 isArea: function() {
29752 if (this.tags.area === 'yes')
29754 if (!this.isClosed() || this.tags.area === 'no')
29756 for (var key in this.tags)
29757 if (key in iD.areaKeys && !(this.tags[key] in iD.areaKeys[key]))
29762 isDegenerate: function() {
29763 return _.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
29766 areAdjacent: function(n1, n2) {
29767 for (var i = 0; i < this.nodes.length; i++) {
29768 if (this.nodes[i] === n1) {
29769 if (this.nodes[i - 1] === n2) return true;
29770 if (this.nodes[i + 1] === n2) return true;
29776 geometry: function(graph) {
29777 return graph.transient(this, 'geometry', function() {
29778 return this.isArea() ? 'area' : 'line';
29782 addNode: function(id, index) {
29783 var nodes = this.nodes.slice();
29784 nodes.splice(index === undefined ? nodes.length : index, 0, id);
29785 return this.update({nodes: nodes});
29788 updateNode: function(id, index) {
29789 var nodes = this.nodes.slice();
29790 nodes.splice(index, 1, id);
29791 return this.update({nodes: nodes});
29794 replaceNode: function(needle, replacement) {
29795 if (this.nodes.indexOf(needle) < 0)
29798 var nodes = this.nodes.slice();
29799 for (var i = 0; i < nodes.length; i++) {
29800 if (nodes[i] === needle) {
29801 nodes[i] = replacement;
29804 return this.update({nodes: nodes});
29807 removeNode: function(id) {
29810 for (var i = 0; i < this.nodes.length; i++) {
29811 var node = this.nodes[i];
29812 if (node !== id && nodes[nodes.length - 1] !== node) {
29817 // Preserve circularity
29818 if (this.nodes.length > 1 && this.first() === id && this.last() === id && nodes[nodes.length - 1] !== nodes[0]) {
29819 nodes.push(nodes[0]);
29822 return this.update({nodes: nodes});
29825 asJXON: function(changeset_id) {
29828 '@id': this.osmId(),
29829 '@version': this.version || 0,
29830 nd: _.map(this.nodes, function(id) {
29831 return { keyAttributes: { ref: iD.Entity.id.toOSM(id) } };
29833 tag: _.map(this.tags, function(v, k) {
29834 return { keyAttributes: { k: k, v: v } };
29838 if (changeset_id) r.way['@changeset'] = changeset_id;
29842 asGeoJSON: function(resolver) {
29843 return resolver.transient(this, 'GeoJSON', function() {
29844 var coordinates = _.map(resolver.childNodes(this), 'loc');
29845 if (this.isArea() && this.isClosed()) {
29848 coordinates: [coordinates]
29852 type: 'LineString',
29853 coordinates: coordinates
29859 area: function(resolver) {
29860 return resolver.transient(this, 'area', function() {
29861 var nodes = resolver.childNodes(this);
29865 coordinates: [_.map(nodes, 'loc')]
29868 if (!this.isClosed() && nodes.length) {
29869 json.coordinates[0].push(nodes[0].loc);
29872 var area = d3.geo.area(json);
29874 // Heuristic for detecting counterclockwise winding order. Assumes
29875 // that OpenStreetMap polygons are not hemisphere-spanning.
29876 if (area > 2 * Math.PI) {
29877 json.coordinates[0] = json.coordinates[0].reverse();
29878 area = d3.geo.area(json);
29881 return isNaN(area) ? 0 : area;
29885 iD.Background = function(context) {
29886 var dispatch = d3.dispatch('change'),
29887 baseLayer = iD.TileLayer(context).projection(context.projection),
29888 overlayLayers = [],
29892 function findSource(id) {
29893 return _.find(backgroundSources, function(d) {
29894 return d.id && d.id === id;
29899 function background(selection) {
29900 var base = selection.selectAll('.layer-background')
29904 .insert('div', '.layer-data')
29905 .attr('class', 'layer layer-background');
29907 base.call(baseLayer);
29909 var overlays = selection.selectAll('.layer-overlay')
29910 .data(overlayLayers, function(d) { return d.source().name(); });
29913 .insert('div', '.layer-data')
29914 .attr('class', 'layer layer-overlay');
29916 overlays.each(function(layer) {
29917 d3.select(this).call(layer);
29925 background.updateImagery = function() {
29926 var b = background.baseLayerSource(),
29927 o = overlayLayers.map(function (d) { return d.source().id; }).join(','),
29928 meters = iD.geo.offsetToMeters(b.offset()),
29930 x = +meters[0].toFixed(2),
29931 y = +meters[1].toFixed(2),
29932 q = iD.util.stringQs(location.hash.substring(1));
29935 if (id === 'custom') {
29936 id = 'custom:' + b.template;
29942 delete q.background;
29951 if (Math.abs(x) > epsilon || Math.abs(y) > epsilon) {
29952 q.offset = x + ',' + y;
29957 location.replace('#' + iD.util.qsString(q, true));
29959 var imageryUsed = [b.imageryUsed()];
29961 overlayLayers.forEach(function (d) {
29962 var source = d.source();
29963 if (!source.isLocatorOverlay()) {
29964 imageryUsed.push(source.imageryUsed());
29968 var gpx = context.layers().layer('gpx');
29969 if (gpx && gpx.enabled() && gpx.hasGpx()) {
29970 imageryUsed.push('Local GPX');
29973 context.history().imageryUsed(imageryUsed);
29976 background.sources = function(extent) {
29977 return backgroundSources.filter(function(source) {
29978 return source.intersects(extent);
29982 background.dimensions = function(_) {
29983 baseLayer.dimensions(_);
29985 overlayLayers.forEach(function(layer) {
29986 layer.dimensions(_);
29990 background.baseLayerSource = function(d) {
29991 if (!arguments.length) return baseLayer.source();
29992 baseLayer.source(d);
29994 background.updateImagery();
29998 background.bing = function() {
29999 background.baseLayerSource(findSource('Bing'));
30002 background.showsLayer = function(d) {
30003 return d === baseLayer.source() ||
30004 (d.id === 'custom' && baseLayer.source().id === 'custom') ||
30005 overlayLayers.some(function(l) { return l.source() === d; });
30008 background.overlayLayerSources = function() {
30009 return overlayLayers.map(function (l) { return l.source(); });
30012 background.toggleOverlayLayer = function(d) {
30015 for (var i = 0; i < overlayLayers.length; i++) {
30016 layer = overlayLayers[i];
30017 if (layer.source() === d) {
30018 overlayLayers.splice(i, 1);
30020 background.updateImagery();
30025 layer = iD.TileLayer(context)
30027 .projection(context.projection)
30028 .dimensions(baseLayer.dimensions());
30030 overlayLayers.push(layer);
30032 background.updateImagery();
30035 background.nudge = function(d, zoom) {
30036 baseLayer.source().nudge(d, zoom);
30038 background.updateImagery();
30042 background.offset = function(d) {
30043 if (!arguments.length) return baseLayer.source().offset();
30044 baseLayer.source().offset(d);
30046 background.updateImagery();
30050 background.load = function(imagery) {
30051 function parseMap(qmap) {
30052 if (!qmap) return false;
30053 var args = qmap.split('/').map(Number);
30054 if (args.length < 3 || args.some(isNaN)) return false;
30055 return iD.geo.Extent([args[1], args[2]]);
30058 var q = iD.util.stringQs(location.hash.substring(1)),
30059 chosen = q.background || q.layer,
30060 extent = parseMap(q.map),
30063 backgroundSources = imagery.map(function(source) {
30064 if (source.type === 'bing') {
30065 return iD.BackgroundSource.Bing(source, dispatch);
30067 return iD.BackgroundSource(source);
30071 backgroundSources.unshift(iD.BackgroundSource.None());
30073 if (!chosen && extent) {
30074 best = _.find(this.sources(extent), function(s) { return s.best(); });
30077 if (chosen && chosen.indexOf('custom:') === 0) {
30078 background.baseLayerSource(iD.BackgroundSource.Custom(chosen.replace(/^custom:/, '')));
30080 background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
30083 var locator = _.find(backgroundSources, function(d) {
30084 return d.overlay && d.default;
30088 background.toggleOverlayLayer(locator);
30091 var overlays = (q.overlays || '').split(',');
30092 overlays.forEach(function(overlay) {
30093 overlay = findSource(overlay);
30095 background.toggleOverlayLayer(overlay);
30100 var gpx = context.layers().layer('gpx');
30107 var offset = q.offset.replace(/;/g, ',').split(',').map(function(n) {
30108 return !isNaN(n) && n;
30111 if (offset.length === 2) {
30112 background.offset(iD.geo.metersToOffset(offset));
30117 return d3.rebind(background, dispatch, 'on');
30119 iD.BackgroundSource = function(data) {
30120 var source = _.clone(data),
30122 name = source.name,
30123 best = !!source.best;
30125 source.scaleExtent = data.scaleExtent || [0, 20];
30126 source.overzoom = data.overzoom !== false;
30128 source.offset = function(_) {
30129 if (!arguments.length) return offset;
30134 source.nudge = function(_, zoomlevel) {
30135 offset[0] += _[0] / Math.pow(2, zoomlevel);
30136 offset[1] += _[1] / Math.pow(2, zoomlevel);
30140 source.name = function() {
30144 source.best = function() {
30148 source.area = function() {
30149 if (!data.polygon) return Number.MAX_VALUE; // worldwide
30150 var area = d3.geo.area({ type: 'MultiPolygon', coordinates: [ data.polygon ] });
30151 return isNaN(area) ? 0 : area;
30154 source.imageryUsed = function() {
30155 return source.id || name;
30158 source.url = function(coord) {
30159 return data.template
30160 .replace('{x}', coord[0])
30161 .replace('{y}', coord[1])
30162 // TMS-flipped y coordinate
30163 .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
30164 .replace(/\{z(oom)?\}/, coord[2])
30165 .replace(/\{switch:([^}]+)\}/, function(s, r) {
30166 var subdomains = r.split(',');
30167 return subdomains[(coord[0] + coord[1]) % subdomains.length];
30169 .replace('{u}', function() {
30171 for (var zoom = coord[2]; zoom > 0; zoom--) {
30173 var mask = 1 << (zoom - 1);
30174 if ((coord[0] & mask) !== 0) b++;
30175 if ((coord[1] & mask) !== 0) b += 2;
30182 source.intersects = function(extent) {
30183 extent = extent.polygon();
30184 return !data.polygon || data.polygon.some(function(polygon) {
30185 return iD.geo.polygonIntersectsPolygon(polygon, extent, true);
30189 source.validZoom = function(z) {
30190 return source.scaleExtent[0] <= z &&
30191 (source.overzoom || source.scaleExtent[1] > z);
30194 source.isLocatorOverlay = function() {
30195 return name === 'Locator Overlay';
30198 source.copyrightNotices = function() {};
30203 iD.BackgroundSource.Bing = function(data, dispatch) {
30204 // http://msdn.microsoft.com/en-us/library/ff701716.aspx
30205 // http://msdn.microsoft.com/en-us/library/ff701701.aspx
30207 data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
30209 var bing = iD.BackgroundSource(data),
30210 key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
30211 url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
30212 key + '&jsonp={callback}',
30215 d3.jsonp(url, function(json) {
30216 providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
30218 attribution: provider.attribution,
30219 areas: provider.coverageAreas.map(function(area) {
30221 zoom: [area.zoomMin, area.zoomMax],
30222 extent: iD.geo.Extent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
30230 bing.copyrightNotices = function(zoom, extent) {
30231 zoom = Math.min(zoom, 21);
30232 return providers.filter(function(provider) {
30233 return _.some(provider.areas, function(area) {
30234 return extent.intersects(area.extent) &&
30235 area.zoom[0] <= zoom &&
30236 area.zoom[1] >= zoom;
30238 }).map(function(provider) {
30239 return provider.attribution;
30243 bing.logo = 'bing_maps.png';
30244 bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
30249 iD.BackgroundSource.None = function() {
30250 var source = iD.BackgroundSource({id: 'none', template: ''});
30252 source.name = function() {
30253 return t('background.none');
30256 source.imageryUsed = function() {
30260 source.area = function() {
30267 iD.BackgroundSource.Custom = function(template) {
30268 var source = iD.BackgroundSource({id: 'custom', template: template});
30270 source.name = function() {
30271 return t('background.custom');
30274 source.imageryUsed = function() {
30275 return 'Custom (' + template + ')';
30278 source.area = function() {
30284 iD.Features = function(context) {
30285 var traffic_roads = {
30287 'motorway_link': true,
30289 'trunk_link': true,
30291 'primary_link': true,
30293 'secondary_link': true,
30295 'tertiary_link': true,
30296 'residential': true,
30297 'unclassified': true,
30298 'living_street': true
30301 var service_roads = {
30313 'pedestrian': true,
30317 var past_futures = {
30319 'construction': true,
30321 'dismantled': true,
30324 'demolished': true,
30325 'obliterated': true
30328 var dispatch = d3.dispatch('change', 'redraw'),
30336 function update() {
30337 _hidden = features.hidden();
30342 function defineFeature(k, filter, max) {
30346 enabled: true, // whether the user wants it enabled..
30348 currentMax: (max || Infinity),
30349 defaultMax: (max || Infinity),
30350 enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
30351 disable: function() { this.enabled = false; this.currentMax = 0; },
30352 hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
30353 autoHidden: function() { return this.hidden() && this.currentMax > 0; }
30358 defineFeature('points', function isPoint(entity, resolver, geometry) {
30359 return geometry === 'point';
30362 defineFeature('traffic_roads', function isTrafficRoad(entity) {
30363 return traffic_roads[entity.tags.highway];
30366 defineFeature('service_roads', function isServiceRoad(entity) {
30367 return service_roads[entity.tags.highway];
30370 defineFeature('paths', function isPath(entity) {
30371 return paths[entity.tags.highway];
30374 defineFeature('buildings', function isBuilding(entity) {
30376 !!entity.tags['building:part'] ||
30377 (!!entity.tags.building && entity.tags.building !== 'no') ||
30378 entity.tags.amenity === 'shelter' ||
30379 entity.tags.parking === 'multi-storey' ||
30380 entity.tags.parking === 'sheds' ||
30381 entity.tags.parking === 'carports' ||
30382 entity.tags.parking === 'garage_boxes'
30386 defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
30387 return geometry === 'area' &&
30388 !_features.buildings.filter(entity) &&
30389 !_features.water.filter(entity);
30392 defineFeature('boundaries', function isBoundary(entity) {
30393 return !!entity.tags.boundary;
30396 defineFeature('water', function isWater(entity) {
30398 !!entity.tags.waterway ||
30399 entity.tags.natural === 'water' ||
30400 entity.tags.natural === 'coastline' ||
30401 entity.tags.natural === 'bay' ||
30402 entity.tags.landuse === 'pond' ||
30403 entity.tags.landuse === 'basin' ||
30404 entity.tags.landuse === 'reservoir' ||
30405 entity.tags.landuse === 'salt_pond'
30409 defineFeature('rail', function isRail(entity) {
30411 !!entity.tags.railway ||
30412 entity.tags.landuse === 'railway'
30414 traffic_roads[entity.tags.highway] ||
30415 service_roads[entity.tags.highway] ||
30416 paths[entity.tags.highway]
30420 defineFeature('power', function isPower(entity) {
30421 return !!entity.tags.power;
30424 // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
30425 defineFeature('past_future', function isPastFuture(entity) {
30427 traffic_roads[entity.tags.highway] ||
30428 service_roads[entity.tags.highway] ||
30429 paths[entity.tags.highway]
30430 ) { return false; }
30432 var strings = Object.keys(entity.tags);
30434 for (var i = 0; i < strings.length; i++) {
30435 var s = strings[i];
30436 if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
30441 // Lines or areas that don't match another feature filter.
30442 // IMPORTANT: The 'others' feature must be the last one defined,
30443 // so that code in getMatches can skip this test if `hasMatch = true`
30444 defineFeature('others', function isOther(entity, resolver, geometry) {
30445 return (geometry === 'line' || geometry === 'area');
30449 function features() {}
30451 features.features = function() {
30455 features.keys = function() {
30459 features.enabled = function(k) {
30460 if (!arguments.length) {
30461 return _.filter(_keys, function(k) { return _features[k].enabled; });
30463 return _features[k] && _features[k].enabled;
30466 features.disabled = function(k) {
30467 if (!arguments.length) {
30468 return _.reject(_keys, function(k) { return _features[k].enabled; });
30470 return _features[k] && !_features[k].enabled;
30473 features.hidden = function(k) {
30474 if (!arguments.length) {
30475 return _.filter(_keys, function(k) { return _features[k].hidden(); });
30477 return _features[k] && _features[k].hidden();
30480 features.autoHidden = function(k) {
30481 if (!arguments.length) {
30482 return _.filter(_keys, function(k) { return _features[k].autoHidden(); });
30484 return _features[k] && _features[k].autoHidden();
30487 features.enable = function(k) {
30488 if (_features[k] && !_features[k].enabled) {
30489 _features[k].enable();
30494 features.disable = function(k) {
30495 if (_features[k] && _features[k].enabled) {
30496 _features[k].disable();
30501 features.toggle = function(k) {
30502 if (_features[k]) {
30503 (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
30508 features.resetStats = function() {
30509 _.each(_features, function(f) { f.count = 0; });
30513 features.gatherStats = function(d, resolver, dimensions) {
30514 var needsRedraw = false,
30515 type = _.groupBy(d, function(ent) { return ent.type; }),
30516 entities = [].concat(type.relation || [], type.way || [], type.node || []),
30517 currHidden, geometry, matches;
30519 _.each(_features, function(f) { f.count = 0; });
30521 // adjust the threshold for point/building culling based on viewport size..
30522 // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
30523 _cullFactor = dimensions[0] * dimensions[1] / 1000000;
30525 for (var i = 0; i < entities.length; i++) {
30526 geometry = entities[i].geometry(resolver);
30527 if (!(geometry === 'vertex' || geometry === 'relation')) {
30528 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
30529 for (var j = 0; j < matches.length; j++) {
30530 _features[matches[j]].count++;
30535 currHidden = features.hidden();
30536 if (currHidden !== _hidden) {
30537 _hidden = currHidden;
30538 needsRedraw = true;
30542 return needsRedraw;
30545 features.stats = function() {
30546 _.each(_keys, function(k) { _stats[k] = _features[k].count; });
30550 features.clear = function(d) {
30551 for (var i = 0; i < d.length; i++) {
30552 features.clearEntity(d[i]);
30556 features.clearEntity = function(entity) {
30557 delete _cache[iD.Entity.key(entity)];
30560 features.reset = function() {
30564 features.getMatches = function(entity, resolver, geometry) {
30565 if (geometry === 'vertex' || geometry === 'relation') return {};
30567 var ent = iD.Entity.key(entity);
30568 if (!_cache[ent]) {
30572 if (!_cache[ent].matches) {
30576 for (var i = 0; i < _keys.length; i++) {
30577 if (_keys[i] === 'others') {
30578 if (hasMatch) continue;
30580 // Multipolygon members:
30582 // 1. is a way that hasn't matched other "interesting" feature rules,
30583 // 2. and it belongs to a single parent multipolygon relation
30584 // ...then match whatever feature rules the parent multipolygon has matched.
30585 // see #2548, #2887
30588 // For this to work, getMatches must be called on relations before ways.
30590 if (entity.type === 'way') {
30591 var parents = features.getParents(entity, resolver, geometry);
30592 if (parents.length === 1 && parents[0].isMultipolygon()) {
30593 var pkey = iD.Entity.key(parents[0]);
30594 if (_cache[pkey] && _cache[pkey].matches) {
30595 matches = _.clone(_cache[pkey].matches);
30602 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
30603 matches[_keys[i]] = hasMatch = true;
30606 _cache[ent].matches = matches;
30609 return _cache[ent].matches;
30612 features.getParents = function(entity, resolver, geometry) {
30613 if (geometry === 'point') return [];
30615 var ent = iD.Entity.key(entity);
30616 if (!_cache[ent]) {
30620 if (!_cache[ent].parents) {
30622 if (geometry === 'vertex') {
30623 parents = resolver.parentWays(entity);
30624 } else { // 'line', 'area', 'relation'
30625 parents = resolver.parentRelations(entity);
30627 _cache[ent].parents = parents;
30629 return _cache[ent].parents;
30632 features.isHiddenFeature = function(entity, resolver, geometry) {
30633 if (!_hidden.length) return false;
30634 if (!entity.version) return false;
30636 var matches = features.getMatches(entity, resolver, geometry);
30638 for (var i = 0; i < _hidden.length; i++) {
30639 if (matches[_hidden[i]]) return true;
30644 features.isHiddenChild = function(entity, resolver, geometry) {
30645 if (!_hidden.length) return false;
30646 if (!entity.version || geometry === 'point') return false;
30648 var parents = features.getParents(entity, resolver, geometry);
30649 if (!parents.length) return false;
30651 for (var i = 0; i < parents.length; i++) {
30652 if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
30659 features.hasHiddenConnections = function(entity, resolver) {
30660 if (!_hidden.length) return false;
30661 var childNodes, connections;
30663 if (entity.type === 'midpoint') {
30664 childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
30667 childNodes = entity.nodes ? resolver.childNodes(entity) : [];
30668 connections = features.getParents(entity, resolver, entity.geometry(resolver));
30671 // gather ways connected to child nodes..
30672 connections = _.reduce(childNodes, function(result, e) {
30673 return resolver.isShared(e) ? _.union(result, resolver.parentWays(e)) : result;
30676 return connections.length ? _.some(connections, function(e) {
30677 return features.isHidden(e, resolver, e.geometry(resolver));
30681 features.isHidden = function(entity, resolver, geometry) {
30682 if (!_hidden.length) return false;
30683 if (!entity.version) return false;
30685 var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
30686 return fn(entity, resolver, geometry);
30689 features.filter = function(d, resolver) {
30690 if (!_hidden.length) return d;
30693 for (var i = 0; i < d.length; i++) {
30695 if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
30696 result.push(entity);
30702 return d3.rebind(features, dispatch, 'on');
30704 iD.Map = function(context) {
30705 var dimensions = [1, 1],
30706 dispatch = d3.dispatch('move', 'drawn'),
30707 projection = context.projection,
30708 zoom = d3.behavior.zoom()
30709 .translate(projection.translate())
30710 .scale(projection.scale() * 2 * Math.PI)
30711 .scaleExtent([1024, 256 * Math.pow(2, 24)])
30712 .on('zoom', zoomPan),
30713 dblclickEnabled = true,
30714 redrawEnabled = true,
30716 transformed = false,
30718 drawLayers = iD.svg.Layers(projection, context),
30719 drawPoints = iD.svg.Points(projection, context),
30720 drawVertices = iD.svg.Vertices(projection, context),
30721 drawLines = iD.svg.Lines(projection),
30722 drawAreas = iD.svg.Areas(projection),
30723 drawMidpoints = iD.svg.Midpoints(projection, context),
30724 drawLabels = iD.svg.Labels(projection, context),
30731 function map(selection) {
30733 .on('change.map', redraw);
30735 .on('change.map', redraw);
30736 context.background()
30737 .on('change.map', redraw);
30739 .on('redraw.map', redraw);
30741 .on('change.map', function() {
30742 context.background().updateImagery();
30747 .on('dblclick.map', dblClick)
30750 supersurface = selection.append('div')
30751 .attr('id', 'supersurface')
30752 .call(iD.util.setTransform, 0, 0);
30754 // Need a wrapper div because Opera can't cope with an absolutely positioned
30755 // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
30756 wrapper = supersurface
30758 .attr('class', 'layer layer-data');
30760 map.surface = surface = wrapper
30762 .selectAll('.surface')
30763 .attr('id', 'surface');
30766 .on('mousedown.zoom', function() {
30767 if (d3.event.button === 2) {
30768 d3.event.stopPropagation();
30771 .on('mouseup.zoom', function() {
30772 if (resetTransform()) redraw();
30774 .on('mousemove.map', function() {
30775 mousemove = d3.event;
30777 .on('mouseover.vertices', function() {
30778 if (map.editable() && !transformed) {
30779 var hover = d3.event.target.__data__;
30780 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
30781 dispatch.drawn({full: false});
30784 .on('mouseout.vertices', function() {
30785 if (map.editable() && !transformed) {
30786 var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__;
30787 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
30788 dispatch.drawn({full: false});
30794 .call(context.background());
30797 context.on('enter.map', function() {
30798 if (map.editable() && !transformed) {
30799 var all = context.intersects(map.extent()),
30800 filter = d3.functor(true),
30801 graph = context.graph();
30803 all = context.features().filter(all, graph);
30805 .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
30806 .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
30807 dispatch.drawn({full: false});
30811 map.dimensions(selection.dimensions());
30813 drawLabels.supersurface(supersurface);
30816 function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }
30818 function drawVector(difference, extent) {
30819 var graph = context.graph(),
30820 features = context.features(),
30821 all = context.intersects(map.extent()),
30825 var complete = difference.complete(map.extent());
30826 data = _.compact(_.values(complete));
30827 filter = function(d) { return d.id in complete; };
30828 features.clear(data);
30831 // force a full redraw if gatherStats detects that a feature
30832 // should be auto-hidden (e.g. points or buildings)..
30833 if (features.gatherStats(all, graph, dimensions)) {
30834 extent = undefined;
30838 data = context.intersects(map.extent().intersection(extent));
30839 var set = d3.set(_.map(data, 'id'));
30840 filter = function(d) { return set.has(d.id); };
30844 filter = d3.functor(true);
30848 data = features.filter(data, graph);
30851 .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
30852 .call(drawLines, graph, data, filter)
30853 .call(drawAreas, graph, data, filter)
30854 .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
30855 .call(drawLabels, graph, data, filter, dimensions, !difference && !extent)
30856 .call(drawPoints, graph, data, filter);
30858 dispatch.drawn({full: true});
30861 function editOff() {
30862 context.features().resetStats();
30863 surface.selectAll('.layer-osm *').remove();
30864 dispatch.drawn({full: true});
30867 function dblClick() {
30868 if (!dblclickEnabled) {
30869 d3.event.preventDefault();
30870 d3.event.stopImmediatePropagation();
30874 function zoomPan() {
30875 if (Math.log(d3.event.scale) / Math.LN2 - 8 < minzoom) {
30876 surface.interrupt();
30877 iD.ui.flash(context.container())
30878 .select('.content')
30879 .text(t('cannot_zoom'));
30880 setZoom(context.minEditableZoom(), true);
30882 dispatch.move(map);
30887 .translate(d3.event.translate)
30888 .scale(d3.event.scale / (2 * Math.PI));
30890 var scale = d3.event.scale / transformStart[0],
30891 tX = (d3.event.translate[0] / scale - transformStart[1][0]) * scale,
30892 tY = (d3.event.translate[1] / scale - transformStart[1][1]) * scale;
30894 transformed = true;
30895 iD.util.setTransform(supersurface, tX, tY, scale);
30898 dispatch.move(map);
30901 function resetTransform() {
30902 if (!transformed) return false;
30904 surface.selectAll('.radial-menu').interrupt().remove();
30905 iD.util.setTransform(supersurface, 0, 0);
30906 transformed = false;
30910 function redraw(difference, extent) {
30911 if (!surface || !redrawEnabled) return;
30913 clearTimeout(timeoutId);
30915 // If we are in the middle of a zoom/pan, we can't do differenced redraws.
30916 // It would result in artifacts where differenced entities are redrawn with
30917 // one transform and unchanged entities with another.
30918 if (resetTransform()) {
30919 difference = extent = undefined;
30922 var zoom = String(~~map.zoom());
30923 if (surface.attr('data-zoom') !== zoom) {
30924 surface.attr('data-zoom', zoom)
30925 .classed('low-zoom', zoom <= 16);
30929 supersurface.call(context.background());
30933 if (map.editable()) {
30934 context.loadTiles(projection, dimensions);
30935 drawVector(difference, extent);
30944 projection.scale() * 2 * Math.PI,
30945 projection.translate().slice()];
30951 function queueRedraw() {
30952 clearTimeout(timeoutId);
30953 timeoutId = setTimeout(function() { redraw(); }, 300);
30956 function pointLocation(p) {
30957 var translate = projection.translate(),
30958 scale = projection.scale() * 2 * Math.PI;
30959 return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
30962 function locationPoint(l) {
30963 var translate = projection.translate(),
30964 scale = projection.scale() * 2 * Math.PI;
30965 return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
30968 map.mouse = function() {
30969 var e = mousemove || d3.event, s;
30970 while ((s = e.sourceEvent)) e = s;
30974 map.mouseCoordinates = function() {
30975 return projection.invert(map.mouse());
30978 map.dblclickEnable = function(_) {
30979 if (!arguments.length) return dblclickEnabled;
30980 dblclickEnabled = _;
30984 map.redrawEnable = function(_) {
30985 if (!arguments.length) return redrawEnabled;
30990 function interpolateZoom(_) {
30991 var k = projection.scale(),
30992 t = projection.translate();
30994 surface.node().__chart__ = {
31001 projection.scale(k).translate(t); // undo setZoom projection changes
31003 zoom.event(surface.transition());
31006 function setZoom(_, force) {
31007 if (_ === map.zoom() && !force)
31009 var scale = 256 * Math.pow(2, _),
31010 center = pxCenter(),
31011 l = pointLocation(center);
31012 scale = Math.max(1024, Math.min(256 * Math.pow(2, 24), scale));
31013 projection.scale(scale / (2 * Math.PI));
31015 var t = projection.translate();
31016 l = locationPoint(l);
31017 t[0] += center[0] - l[0];
31018 t[1] += center[1] - l[1];
31019 projection.translate(t);
31020 zoom.translate(projection.translate());
31024 function setCenter(_) {
31025 var c = map.center();
31026 if (_[0] === c[0] && _[1] === c[1])
31028 var t = projection.translate(),
31030 ll = projection(_);
31031 projection.translate([
31032 t[0] - ll[0] + pxC[0],
31033 t[1] - ll[1] + pxC[1]]);
31034 zoom.translate(projection.translate());
31038 map.pan = function(d) {
31039 var t = projection.translate();
31042 projection.translate(t);
31043 zoom.translate(projection.translate());
31044 dispatch.move(map);
31048 map.dimensions = function(_) {
31049 if (!arguments.length) return dimensions;
31050 var center = map.center();
31052 drawLayers.dimensions(dimensions);
31053 context.background().dimensions(dimensions);
31054 projection.clipExtent([[0, 0], dimensions]);
31055 mouse = iD.util.fastMouse(supersurface.node());
31060 function zoomIn(integer) {
31061 interpolateZoom(~~map.zoom() + integer);
31064 function zoomOut(integer) {
31065 interpolateZoom(~~map.zoom() - integer);
31068 map.zoomIn = function() { zoomIn(1); };
31069 map.zoomInFurther = function() { zoomIn(4); };
31071 map.zoomOut = function() { zoomOut(1); };
31072 map.zoomOutFurther = function() { zoomOut(4); };
31074 map.center = function(loc) {
31075 if (!arguments.length) {
31076 return projection.invert(pxCenter());
31079 if (setCenter(loc)) {
31080 dispatch.move(map);
31086 map.zoom = function(z) {
31087 if (!arguments.length) {
31088 return Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8, 0);
31092 surface.interrupt();
31093 iD.ui.flash(context.container())
31094 .select('.content')
31095 .text(t('cannot_zoom'));
31096 z = context.minEditableZoom();
31100 dispatch.move(map);
31106 map.zoomTo = function(entity, zoomLimits) {
31107 var extent = entity.extent(context.graph());
31108 if (!isFinite(extent.area())) return;
31110 var zoom = map.trimmedExtentZoom(extent);
31111 zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
31112 map.centerZoom(extent.center(), Math.min(Math.max(zoom, zoomLimits[0]), zoomLimits[1]));
31115 map.centerZoom = function(loc, z) {
31116 var centered = setCenter(loc),
31117 zoomed = setZoom(z);
31119 if (centered || zoomed) {
31120 dispatch.move(map);
31126 map.centerEase = function(loc) {
31127 var from = map.center().slice(),
31131 surface.one('mousedown.ease', function() {
31135 d3.timer(function() {
31136 if (stop) return true;
31137 map.center(iD.geo.interp(from, loc, (t += 1) / 10));
31143 map.extent = function(_) {
31144 if (!arguments.length) {
31145 return new iD.geo.Extent(projection.invert([0, dimensions[1]]),
31146 projection.invert([dimensions[0], 0]));
31148 var extent = iD.geo.Extent(_);
31149 map.centerZoom(extent.center(), map.extentZoom(extent));
31153 map.trimmedExtent = function(_) {
31154 if (!arguments.length) {
31155 var headerY = 60, footerY = 30, pad = 10;
31156 return new iD.geo.Extent(projection.invert([pad, dimensions[1] - footerY - pad]),
31157 projection.invert([dimensions[0] - pad, headerY + pad]));
31159 var extent = iD.geo.Extent(_);
31160 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
31164 function calcZoom(extent, dim) {
31165 var tl = projection([extent[0][0], extent[1][1]]),
31166 br = projection([extent[1][0], extent[0][1]]);
31168 // Calculate maximum zoom that fits extent
31169 var hFactor = (br[0] - tl[0]) / dim[0],
31170 vFactor = (br[1] - tl[1]) / dim[1],
31171 hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
31172 vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
31173 newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
31178 map.extentZoom = function(_) {
31179 return calcZoom(iD.geo.Extent(_), dimensions);
31182 map.trimmedExtentZoom = function(_) {
31183 var trimY = 120, trimX = 40,
31184 trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
31185 return calcZoom(iD.geo.Extent(_), trimmed);
31188 map.editable = function() {
31189 return map.zoom() >= context.minEditableZoom();
31192 map.minzoom = function(_) {
31193 if (!arguments.length) return minzoom;
31198 map.layers = drawLayers;
31200 return d3.rebind(map, dispatch, 'on');
31202 iD.TileLayer = function(context) {
31203 var tileSize = 256,
31204 tile = d3.geo.tile(),
31209 transformProp = iD.util.prefixCSSProperty('Transform'),
31210 source = d3.functor('');
31213 // blacklist overlay tiles around Null Island..
31214 function nearNullIsland(x, y, z) {
31216 var center = Math.pow(2, z - 1),
31217 width = Math.pow(2, z - 6),
31218 min = center - (width / 2),
31219 max = center + (width / 2) - 1;
31220 return x >= min && x <= max && y >= min && y <= max;
31225 function tileSizeAtZoom(d, z) {
31226 var epsilon = 0.002;
31227 return ((tileSize * Math.pow(2, z - d[2])) / tileSize) + epsilon;
31230 function atZoom(t, distance) {
31231 var power = Math.pow(2, distance);
31233 Math.floor(t[0] * power),
31234 Math.floor(t[1] * power),
31238 function lookUp(d) {
31239 for (var up = -1; up > -d[2]; up--) {
31240 var tile = atZoom(d, up);
31241 if (cache[source.url(tile)] !== false) {
31247 function uniqueBy(a, n) {
31248 var o = [], seen = {};
31249 for (var i = 0; i < a.length; i++) {
31250 if (seen[a[i][n]] === undefined) {
31252 seen[a[i][n]] = true;
31258 function addSource(d) {
31259 d.push(source.url(d));
31263 // Update tiles based on current state of `projection`.
31264 function background(selection) {
31265 tile.scale(projection.scale() * 2 * Math.PI)
31266 .translate(projection.translate());
31269 projection.scale() * Math.PI - projection.translate()[0],
31270 projection.scale() * Math.PI - projection.translate()[1]];
31272 z = Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
31277 // Derive the tiles onscreen, remove those offscreen and position them.
31278 // Important that this part not depend on `projection` because it's
31279 // rentered when tiles load/error (see #644).
31280 function render(selection) {
31282 var showDebug = context.debugTile() && !source.overlay;
31284 if (source.validZoom(z)) {
31285 tile().forEach(function(d) {
31287 if (d[3] === '') return;
31288 if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
31290 if (cache[d[3]] === false && lookUp(d)) {
31291 requests.push(addSource(lookUp(d)));
31295 requests = uniqueBy(requests, 3).filter(function(r) {
31296 if (!!source.overlay && nearNullIsland(r[0], r[1], r[2])) {
31299 // don't re-request tiles which have failed in the past
31300 return cache[r[3]] !== false;
31304 var pixelOffset = [
31305 source.offset()[0] * Math.pow(2, z),
31306 source.offset()[1] * Math.pow(2, z)
31310 cache[d[3]] = true;
31314 .classed('tile-loaded', true);
31318 function error(d) {
31319 cache[d[3]] = false;
31327 function imageTransform(d) {
31328 var _ts = tileSize * Math.pow(2, z - d[2]);
31329 var scale = tileSizeAtZoom(d, z);
31330 return 'translate(' +
31331 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
31332 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
31333 'scale(' + scale + ',' + scale + ')';
31336 function debugTransform(d) {
31337 var _ts = tileSize * Math.pow(2, z - d[2]);
31338 var scale = tileSizeAtZoom(d, z);
31339 return 'translate(' +
31340 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0] + scale * (tileSize / 4)) + 'px,' +
31341 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1] + scale * (tileSize / 2)) + 'px)';
31344 var image = selection
31346 .data(requests, function(d) { return d[3]; });
31349 .style(transformProp, imageTransform)
31350 .classed('tile-removing', true)
31352 var tile = d3.select(this);
31353 window.setTimeout(function() {
31354 if (tile.classed('tile-removing')) {
31360 image.enter().append('img')
31361 .attr('class', 'tile')
31362 .attr('src', function(d) { return d[3]; })
31363 .on('error', error)
31367 .style(transformProp, imageTransform)
31368 .classed('tile-debug', showDebug)
31369 .classed('tile-removing', false);
31372 var debug = selection.selectAll('.tile-label-debug')
31373 .data(showDebug ? requests : [], function(d) { return d[3]; });
31380 .attr('class', 'tile-label-debug');
31383 .text(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; })
31384 .style(transformProp, debugTransform);
31387 background.projection = function(_) {
31388 if (!arguments.length) return projection;
31393 background.dimensions = function(_) {
31394 if (!arguments.length) return tile.size();
31399 background.source = function(_) {
31400 if (!arguments.length) return source;
31403 tile.scaleExtent(source.scaleExtent);
31410 PointTransform: function(projection) {
31411 return function(entity) {
31412 // http://jsperf.com/short-array-join
31413 var pt = projection(entity.loc);
31414 return 'translate(' + pt[0] + ',' + pt[1] + ')';
31418 Path: function(projection, graph, polygon) {
31420 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
31421 project = projection.stream,
31422 path = d3.geo.path()
31423 .projection({stream: function(output) { return polygon ? project(output) : project(clip(output)); }});
31425 return function(entity) {
31426 if (entity.id in cache) {
31427 return cache[entity.id];
31429 return cache[entity.id] = path(entity.asGeoJSON(graph));
31434 OneWaySegments: function(projection, graph, dt) {
31435 return function(entity) {
31441 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
31442 coordinates = graph.childNodes(entity).map(function(n) {
31446 if (entity.tags.oneway === '-1') coordinates.reverse();
31449 type: 'LineString',
31450 coordinates: coordinates
31451 }, projection.stream(clip({
31452 lineStart: function() {},
31453 lineEnd: function() {
31456 point: function(x, y) {
31460 var span = iD.geo.euclideanDistance(a, b) - offset;
31463 var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
31464 dx = dt * Math.cos(angle),
31465 dy = dt * Math.sin(angle),
31466 p = [a[0] + offset * Math.cos(angle),
31467 a[1] + offset * Math.sin(angle)];
31469 var segment = 'M' + a[0] + ',' + a[1] +
31470 'L' + p[0] + ',' + p[1];
31472 for (span -= dt; span >= 0; span -= dt) {
31475 segment += 'L' + p[0] + ',' + p[1];
31478 segment += 'L' + b[0] + ',' + b[1];
31479 segments.push({id: entity.id, index: i, d: segment});
31494 RelationMemberTags: function(graph) {
31495 return function(entity) {
31496 var tags = entity.tags;
31497 graph.parentRelations(entity).forEach(function(relation) {
31498 var type = relation.tags.type;
31499 if (type === 'multipolygon' || type === 'boundary') {
31500 tags = _.extend({}, relation.tags, tags);
31507 iD.svg.Areas = function(projection) {
31508 // Patterns only work in Firefox when set directly on element.
31509 // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
31511 wetland: 'wetland',
31514 construction: 'construction',
31515 military: 'construction',
31516 cemetery: 'cemetery',
31517 grave_yard: 'cemetery',
31520 farmland: 'farmland',
31524 var patternKeys = ['landuse', 'natural', 'amenity'];
31526 function setPattern(d) {
31527 for (var i = 0; i < patternKeys.length; i++) {
31528 if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
31529 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
31533 this.style.fill = this.style.stroke = '';
31536 return function drawAreas(surface, graph, entities, filter) {
31537 var path = iD.svg.Path(projection, graph, true),
31541 for (var i = 0; i < entities.length; i++) {
31542 var entity = entities[i];
31543 if (entity.geometry(graph) !== 'area') continue;
31545 multipolygon = iD.geo.isSimpleMultipolygonOuterMember(entity, graph);
31546 if (multipolygon) {
31547 areas[multipolygon.id] = {
31548 entity: multipolygon.mergeTags(entity.tags),
31549 area: Math.abs(entity.area(graph))
31551 } else if (!areas[entity.id]) {
31552 areas[entity.id] = {
31554 area: Math.abs(entity.area(graph))
31559 areas = d3.values(areas).filter(function hasPath(a) { return path(a.entity); });
31560 areas.sort(function areaSort(a, b) { return b.area - a.area; });
31561 areas = _.map(areas, 'entity');
31563 var strokes = areas.filter(function(area) {
31564 return area.type === 'way';
31574 var clipPaths = surface.selectAll('defs').selectAll('.clipPath')
31576 .data(data.clip, iD.Entity.key);
31579 .append('clipPath')
31580 .attr('class', 'clipPath')
31581 .attr('id', function(entity) { return entity.id + '-clippath'; })
31584 clipPaths.selectAll('path')
31590 var areagroup = surface
31591 .selectAll('.layer-areas')
31592 .selectAll('g.areagroup')
31593 .data(['fill', 'shadow', 'stroke']);
31597 .attr('class', function(d) { return 'layer areagroup area-' + d; });
31599 var paths = areagroup
31602 .data(function(layer) { return data[layer]; }, iD.Entity.key);
31604 // Remove exiting areas first, so they aren't included in the `fills`
31605 // array used for sorting below (https://github.com/openstreetmap/iD/issues/1903).
31609 var fills = surface.selectAll('.area-fill path.area')[0];
31611 var bisect = d3.bisector(function(node) {
31612 return -node.__data__.area(graph);
31615 function sortedByArea(entity) {
31616 if (this.__data__ === 'fill') {
31617 return fills[bisect(fills, -entity.area(graph))];
31622 .insert('path', sortedByArea)
31623 .each(function(entity) {
31624 var layer = this.parentNode.__data__;
31626 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
31628 if (layer === 'fill') {
31629 this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
31630 setPattern.apply(this, arguments);
31633 .call(iD.svg.TagClasses());
31640 A standalone SVG element that contains only a `defs` sub-element. To be
31641 used once globally, since defs IDs must be unique within a document.
31643 iD.svg.Defs = function(context) {
31645 function SVGSpriteDefinition(id, href) {
31646 return function(defs) {
31647 d3.xml(href, 'image/svg+xml', function(err, svg) {
31649 defs.node().appendChild(
31650 d3.select(svg.documentElement).attr('id', id).node()
31656 return function drawDefs(selection) {
31657 var defs = selection.append('defs');
31660 defs.append('marker')
31662 id: 'oneway-marker',
31663 viewBox: '0 0 10 10',
31668 markerUnits: 'strokeWidth',
31672 .attr('class', 'oneway')
31673 .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')
31674 .attr('stroke', 'none')
31675 .attr('fill', '#000')
31676 .attr('opacity', '0.5');
31679 var patterns = defs.selectAll('pattern')
31681 // pattern name, pattern image name
31682 ['wetland', 'wetland'],
31683 ['construction', 'construction'],
31684 ['cemetery', 'cemetery'],
31685 ['orchard', 'orchard'],
31686 ['farmland', 'farmland'],
31695 return 'pattern-' + d[0];
31699 patternUnits: 'userSpaceOnUse'
31702 patterns.append('rect')
31708 'class': function (d) {
31709 return 'pattern-color-' + d[0];
31713 patterns.append('image')
31720 .attr('xlink:href', function (d) {
31721 return context.imagePath('pattern/' + d[1] + '.png');
31726 .data([12, 18, 20, 32, 45])
31727 .enter().append('clipPath')
31728 .attr('id', function (d) {
31729 return 'clip-square-' + d;
31734 .attr('width', function (d) {
31737 .attr('height', function (d) {
31741 defs.call(SVGSpriteDefinition(
31743 context.imagePath('iD-sprite.svg')));
31745 defs.call(SVGSpriteDefinition(
31747 context.imagePath('maki-sprite.svg')));
31750 iD.svg.Gpx = function(projection, context, dispatch) {
31751 var showLabels = true,
31755 if (iD.svg.Gpx.initialized) return; // run once
31757 iD.svg.Gpx.geojson = {};
31758 iD.svg.Gpx.enabled = true;
31761 d3.event.stopPropagation();
31762 d3.event.preventDefault();
31763 d3.event.dataTransfer.dropEffect = 'copy';
31767 .attr('dropzone', 'copy')
31768 .on('drop.localgpx', function() {
31769 d3.event.stopPropagation();
31770 d3.event.preventDefault();
31771 if (!iD.detect().filedrop) return;
31772 drawGpx.files(d3.event.dataTransfer.files);
31774 .on('dragenter.localgpx', over)
31775 .on('dragexit.localgpx', over)
31776 .on('dragover.localgpx', over);
31778 iD.svg.Gpx.initialized = true;
31782 function drawGpx(surface) {
31783 var geojson = iD.svg.Gpx.geojson,
31784 enabled = iD.svg.Gpx.enabled;
31786 layer = surface.selectAll('.layer-gpx')
31787 .data(enabled ? [0] : []);
31791 .attr('class', 'layer-gpx');
31803 .attr('class', 'gpx');
31808 var path = d3.geo.path()
31809 .projection(projection);
31815 var labels = layer.selectAll('text')
31816 .data(showLabels && geojson.features ? geojson.features : []);
31820 .attr('class', 'gpx');
31826 .text(function(d) {
31827 return d.properties.desc || d.properties.name;
31829 .attr('x', function(d) {
31830 var centroid = path.centroid(d);
31831 return centroid[0] + 7;
31833 .attr('y', function(d) {
31834 var centroid = path.centroid(d);
31835 return centroid[1];
31840 function toDom(x) {
31841 return (new DOMParser()).parseFromString(x, 'text/xml');
31844 drawGpx.showLabels = function(_) {
31845 if (!arguments.length) return showLabels;
31850 drawGpx.enabled = function(_) {
31851 if (!arguments.length) return iD.svg.Gpx.enabled;
31852 iD.svg.Gpx.enabled = _;
31857 drawGpx.hasGpx = function() {
31858 var geojson = iD.svg.Gpx.geojson;
31859 return (!(_.isEmpty(geojson) || _.isEmpty(geojson.features)));
31862 drawGpx.geojson = function(gj) {
31863 if (!arguments.length) return iD.svg.Gpx.geojson;
31864 if (_.isEmpty(gj) || _.isEmpty(gj.features)) return this;
31865 iD.svg.Gpx.geojson = gj;
31870 drawGpx.url = function(url) {
31871 d3.text(url, function(err, data) {
31873 drawGpx.geojson(toGeoJSON.gpx(toDom(data)));
31879 drawGpx.files = function(fileList) {
31880 if (!fileList.length) return this;
31881 var f = fileList[0],
31882 reader = new FileReader();
31884 reader.onload = function(e) {
31885 drawGpx.geojson(toGeoJSON.gpx(toDom(e.target.result))).fitZoom();
31888 reader.readAsText(f);
31892 drawGpx.fitZoom = function() {
31893 if (!this.hasGpx()) return this;
31894 var geojson = iD.svg.Gpx.geojson;
31896 var map = context.map(),
31897 viewport = map.trimmedExtent().polygon(),
31898 coords = _.reduce(geojson.features, function(coords, feature) {
31899 var c = feature.geometry.coordinates;
31900 return _.union(coords, feature.geometry.type === 'Point' ? [c] : c);
31903 if (!iD.geo.polygonIntersectsPolygon(viewport, coords, true)) {
31904 var extent = iD.geo.Extent(d3.geo.bounds(geojson));
31905 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
31914 iD.svg.Icon = function(name, svgklass, useklass) {
31915 return function drawIcon(selection) {
31916 selection.selectAll('svg')
31920 .attr('class', 'icon ' + (svgklass || ''))
31922 .attr('xlink:href', name)
31923 .attr('class', useklass);
31926 iD.svg.Labels = function(projection, context) {
31927 var path = d3.geo.path().projection(projection);
31929 // Replace with dict and iterate over entities tags instead?
31930 var label_stack = [
31931 ['line', 'aeroway'],
31932 ['line', 'highway'],
31933 ['line', 'railway'],
31934 ['line', 'waterway'],
31935 ['area', 'aeroway'],
31936 ['area', 'amenity'],
31937 ['area', 'building'],
31938 ['area', 'historic'],
31939 ['area', 'leisure'],
31940 ['area', 'man_made'],
31941 ['area', 'natural'],
31943 ['area', 'tourism'],
31944 ['point', 'aeroway'],
31945 ['point', 'amenity'],
31946 ['point', 'building'],
31947 ['point', 'historic'],
31948 ['point', 'leisure'],
31949 ['point', 'man_made'],
31950 ['point', 'natural'],
31952 ['point', 'tourism'],
31958 var default_size = 12;
31960 var font_sizes = label_stack.map(function(d) {
31961 var style = iD.util.getStyle('text.' + d[0] + '.tag-' + d[1]),
31962 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
31963 if (m) return parseInt(m[1], 10);
31965 style = iD.util.getStyle('text.' + d[0]);
31966 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
31967 if (m) return parseInt(m[1], 10);
31969 return default_size;
31974 var pointOffsets = [
31975 [15, -11, 'start'], // right
31976 [10, -11, 'start'], // unused right now
31980 var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25,
31981 75, 20, 80, 15, 95, 10, 90, 5, 95];
31984 var noIcons = ['building', 'landuse', 'natural'];
31985 function blacklisted(preset) {
31986 return _.some(noIcons, function(s) {
31987 return preset.id.indexOf(s) >= 0;
31991 function get(array, prop) {
31992 return function(d, i) { return array[i][prop]; };
31995 var textWidthCache = {};
31997 function textWidth(text, size, elem) {
31998 var c = textWidthCache[size];
31999 if (!c) c = textWidthCache[size] = {};
32005 c[text] = elem.getComputedTextLength();
32009 var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
32010 if (str === null) {
32011 return size / 3 * 2 * text.length;
32013 return size / 3 * (2 * text.length + str.length);
32018 function drawLineLabels(group, entities, filter, classes, labels) {
32019 var texts = group.selectAll('text.' + classes)
32021 .data(entities, iD.Entity.key);
32025 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
32026 .append('textPath')
32027 .attr('class', 'textpath');
32030 texts.selectAll('.textpath')
32032 .data(entities, iD.Entity.key)
32034 'startOffset': '50%',
32035 'xlink:href': function(d) { return '#labelpath-' + d.id; }
32037 .text(iD.util.displayName);
32039 texts.exit().remove();
32042 function drawLinePaths(group, entities, filter, classes, labels) {
32043 var halos = group.selectAll('path')
32045 .data(entities, iD.Entity.key);
32049 .style('stroke-width', get(labels, 'font-size'))
32050 .attr('id', function(d) { return 'labelpath-' + d.id; })
32051 .attr('class', classes);
32053 halos.attr('d', get(labels, 'lineString'));
32055 halos.exit().remove();
32058 function drawPointLabels(group, entities, filter, classes, labels) {
32059 var texts = group.selectAll('text.' + classes)
32061 .data(entities, iD.Entity.key);
32065 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; });
32067 texts.attr('x', get(labels, 'x'))
32068 .attr('y', get(labels, 'y'))
32069 .style('text-anchor', get(labels, 'textAnchor'))
32070 .text(iD.util.displayName)
32071 .each(function(d, i) { textWidth(iD.util.displayName(d), labels[i].height, this); });
32073 texts.exit().remove();
32077 function drawAreaLabels(group, entities, filter, classes, labels) {
32078 entities = entities.filter(hasText);
32079 labels = labels.filter(hasText);
32080 return drawPointLabels(group, entities, filter, classes, labels);
32082 function hasText(d, i) {
32083 return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
32087 function drawAreaIcons(group, entities, filter, classes, labels) {
32088 var icons = group.selectAll('use')
32090 .data(entities, iD.Entity.key);
32094 .attr('class', 'icon areaicon')
32095 .attr('width', '18px')
32096 .attr('height', '18px');
32098 icons.attr('transform', get(labels, 'transform'))
32099 .attr('xlink:href', function(d) {
32100 var icon = context.presets().match(d, context.graph()).icon;
32101 return '#' + icon + (icon === 'hairdresser' ? '-24': '-18'); // workaround: maki hairdresser-18 broken?
32105 icons.exit().remove();
32108 function reverse(p) {
32109 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
32110 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
32113 function lineString(nodes) {
32114 return 'M' + nodes.join('L');
32117 function subpath(nodes, from, to) {
32118 function segmentLength(i) {
32119 var dx = nodes[i][0] - nodes[i + 1][0];
32120 var dy = nodes[i][1] - nodes[i + 1][1];
32121 return Math.sqrt(dx * dx + dy * dy);
32125 start, end, i0, i1;
32126 for (var i = 0; i < nodes.length - 1; i++) {
32127 var current = segmentLength(i);
32129 if (!start && sofar + current >= from) {
32130 portion = (from - sofar) / current;
32132 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
32133 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
32137 if (!end && sofar + current >= to) {
32138 portion = (to - sofar) / current;
32140 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
32141 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
32148 var ret = nodes.slice(i0, i1);
32149 ret.unshift(start);
32155 function hideOnMouseover() {
32156 var layers = d3.select(this)
32157 .selectAll('.layer-label, .layer-halo');
32159 layers.selectAll('.proximate')
32160 .classed('proximate', false);
32162 var mouse = context.mouse(),
32164 rect = [mouse[0] - pad, mouse[1] - pad, mouse[0] + pad, mouse[1] + pad],
32165 ids = _.map(rtree.search(rect), 'id');
32167 if (!ids.length) return;
32168 layers.selectAll('.' + ids.join(', .'))
32169 .classed('proximate', true);
32172 var rtree = rbush(),
32175 function drawLabels(surface, graph, entities, filter, dimensions, fullRedraw) {
32176 var hidePoints = !surface.selectAll('.node.point').node();
32178 var labelable = [], i, k, entity;
32179 for (i = 0; i < label_stack.length; i++) labelable.push([]);
32185 for (i = 0; i < entities.length; i++) {
32186 rtree.remove(rectangles[entities[i].id]);
32190 // Split entities into groups specified by label_stack
32191 for (i = 0; i < entities.length; i++) {
32192 entity = entities[i];
32193 var geometry = entity.geometry(graph);
32195 if (geometry === 'vertex')
32197 if (hidePoints && geometry === 'point')
32200 var preset = geometry === 'area' && context.presets().match(entity, graph),
32201 icon = preset && !blacklisted(preset) && preset.icon;
32203 if (!icon && !iD.util.displayName(entity))
32206 for (k = 0; k < label_stack.length; k++) {
32207 if (geometry === label_stack[k][0] && entity.tags[label_stack[k][1]]) {
32208 labelable[k].push(entity);
32226 // Try and find a valid label for labellable entities
32227 for (k = 0; k < labelable.length; k++) {
32228 var font_size = font_sizes[k];
32229 for (i = 0; i < labelable[k].length; i++) {
32230 entity = labelable[k][i];
32231 var name = iD.util.displayName(entity),
32232 width = name && textWidth(name, font_size),
32234 if (entity.geometry(graph) === 'point') {
32235 p = getPointLabel(entity, width, font_size);
32236 } else if (entity.geometry(graph) === 'line') {
32237 p = getLineLabel(entity, width, font_size);
32238 } else if (entity.geometry(graph) === 'area') {
32239 p = getAreaLabel(entity, width, font_size);
32242 p.classes = entity.geometry(graph) + ' tag-' + label_stack[k][1];
32243 positions[entity.geometry(graph)].push(p);
32244 labelled[entity.geometry(graph)].push(entity);
32249 function getPointLabel(entity, width, height) {
32250 var coord = projection(entity.loc),
32252 offset = pointOffsets[0],
32256 x: coord[0] + offset[0],
32257 y: coord[1] + offset[1],
32258 textAnchor: offset[2]
32260 var rect = [p.x - m, p.y - m, p.x + width + m, p.y + height + m];
32261 if (tryInsert(rect, entity.id)) return p;
32265 function getLineLabel(entity, width, height) {
32266 var nodes = _.map(graph.childNodes(entity), 'loc').map(projection),
32267 length = iD.geo.pathLength(nodes);
32268 if (length < width + 20) return;
32270 for (var i = 0; i < lineOffsets.length; i++) {
32271 var offset = lineOffsets[i],
32272 middle = offset / 100 * length,
32273 start = middle - width/2;
32274 if (start < 0 || start + width > length) continue;
32275 var sub = subpath(nodes, start, start + width),
32276 rev = reverse(sub),
32278 Math.min(sub[0][0], sub[sub.length - 1][0]) - 10,
32279 Math.min(sub[0][1], sub[sub.length - 1][1]) - 10,
32280 Math.max(sub[0][0], sub[sub.length - 1][0]) + 20,
32281 Math.max(sub[0][1], sub[sub.length - 1][1]) + 30
32283 if (rev) sub = sub.reverse();
32284 if (tryInsert(rect, entity.id)) return {
32285 'font-size': height + 2,
32286 lineString: lineString(sub),
32287 startOffset: offset + '%'
32292 function getAreaLabel(entity, width, height) {
32293 var centroid = path.centroid(entity.asGeoJSON(graph, true)),
32294 extent = entity.extent(graph),
32295 entitywidth = projection(extent[1])[0] - projection(extent[0])[0],
32298 if (isNaN(centroid[0]) || entitywidth < 20) return;
32300 var iconX = centroid[0] - (iconSize/2),
32301 iconY = centroid[1] - (iconSize/2),
32302 textOffset = iconSize + 5;
32305 transform: 'translate(' + iconX + ',' + iconY + ')'
32308 if (width && entitywidth >= width + 20) {
32310 p.y = centroid[1] + textOffset;
32311 p.textAnchor = 'middle';
32313 rect = [p.x - width/2, p.y, p.x + width/2, p.y + height + textOffset];
32315 rect = [iconX, iconY, iconX + iconSize, iconY + iconSize];
32318 if (tryInsert(rect, entity.id)) return p;
32322 function tryInsert(rect, id) {
32323 // Check that label is visible
32324 if (rect[0] < 0 || rect[1] < 0 || rect[2] > dimensions[0] ||
32325 rect[3] > dimensions[1]) return false;
32326 var v = rtree.search(rect).length === 0;
32329 rtree.insert(rect);
32330 rectangles[id] = rect;
32335 var label = surface.selectAll('.layer-label'),
32336 halo = surface.selectAll('.layer-halo');
32339 drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
32340 drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
32343 drawLinePaths(halo, labelled.line, filter, '', positions.line);
32344 drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
32345 drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
32348 drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
32349 drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
32350 drawAreaIcons(label, labelled.area, filter, 'arealabel-icon', positions.area);
32353 var showDebug = context.debugCollision();
32354 var debug = label.selectAll('.layer-label-debug')
32355 .data(showDebug ? [true] : []);
32359 .attr('class', 'layer-label-debug');
32365 var gj = rtree.all().map(function(d) {
32366 return { type: 'Polygon', coordinates: [[
32375 var debugboxes = debug.selectAll('.bbox').data(gj);
32379 .attr('class', 'bbox');
32385 .attr('d', d3.geo.path().projection(null));
32389 drawLabels.supersurface = function(supersurface) {
32391 .on('mousemove.hidelabels', hideOnMouseover)
32392 .on('mousedown.hidelabels', function () {
32393 supersurface.on('mousemove.hidelabels', null);
32395 .on('mouseup.hidelabels', function () {
32396 supersurface.on('mousemove.hidelabels', hideOnMouseover);
32402 iD.svg.Layers = function(projection, context) {
32403 var dispatch = d3.dispatch('change'),
32404 svg = d3.select(null),
32406 { id: 'osm', layer: iD.svg.Osm(projection, context, dispatch) },
32407 { id: 'gpx', layer: iD.svg.Gpx(projection, context, dispatch) },
32408 { id: 'mapillary-images', layer: iD.svg.MapillaryImages(projection, context, dispatch) },
32409 { id: 'mapillary-signs', layer: iD.svg.MapillarySigns(projection, context, dispatch) }
32413 function drawLayers(selection) {
32414 svg = selection.selectAll('.surface')
32419 .attr('class', 'surface')
32422 var groups = svg.selectAll('.data-layer')
32427 .attr('class', function(d) { return 'data-layer data-layer-' + d.id; });
32430 .each(function(d) { d3.select(this).call(d.layer); });
32436 drawLayers.all = function() {
32440 drawLayers.layer = function(id) {
32441 var obj = _.find(layers, function(o) {return o.id === id;});
32442 return obj && obj.layer;
32445 drawLayers.only = function(what) {
32446 var arr = [].concat(what);
32447 drawLayers.remove(_.difference(_.map(layers, 'id'), arr));
32451 drawLayers.remove = function(what) {
32452 var arr = [].concat(what);
32453 arr.forEach(function(id) {
32454 layers = _.reject(layers, function(o) {return o.id === id;});
32460 drawLayers.add = function(what) {
32461 var arr = [].concat(what);
32462 arr.forEach(function(obj) {
32463 if ('id' in obj && 'layer' in obj) {
32471 drawLayers.dimensions = function(_) {
32472 if (!arguments.length) return svg.dimensions();
32474 layers.forEach(function(obj) {
32475 if (obj.layer.dimensions) {
32476 obj.layer.dimensions(_);
32483 return d3.rebind(drawLayers, dispatch, 'on');
32485 iD.svg.Lines = function(projection) {
32487 var highway_stack = {
32502 function waystack(a, b) {
32503 var as = 0, bs = 0;
32505 if (a.tags.highway) { as -= highway_stack[a.tags.highway]; }
32506 if (b.tags.highway) { bs -= highway_stack[b.tags.highway]; }
32510 return function drawLines(surface, graph, entities, filter) {
32511 var ways = [], pathdata = {}, onewaydata = {},
32512 getPath = iD.svg.Path(projection, graph);
32514 for (var i = 0; i < entities.length; i++) {
32515 var entity = entities[i],
32516 outer = iD.geo.simpleMultipolygonOuterMember(entity, graph);
32518 ways.push(entity.mergeTags(outer.tags));
32519 } else if (entity.geometry(graph) === 'line') {
32524 ways = ways.filter(getPath);
32526 pathdata = _.groupBy(ways, function(way) { return way.layer(); });
32528 _.forOwn(pathdata, function(v, k) {
32529 onewaydata[k] = _(v)
32530 .filter(function(d) { return d.isOneWay(); })
32531 .map(iD.svg.OneWaySegments(projection, graph, 35))
32536 var layergroup = surface
32537 .selectAll('.layer-lines')
32538 .selectAll('g.layergroup')
32539 .data(d3.range(-10, 11));
32543 .attr('class', function(d) { return 'layer layergroup layer' + String(d); });
32546 var linegroup = layergroup
32547 .selectAll('g.linegroup')
32548 .data(['shadow', 'casing', 'stroke']);
32552 .attr('class', function(d) { return 'layer linegroup line-' + d; });
32555 var lines = linegroup
32559 function() { return pathdata[this.parentNode.parentNode.__data__] || []; },
32563 // Optimization: call simple TagClasses only on enter selection. This
32564 // works because iD.Entity.key is defined to include the entity v attribute.
32567 .attr('class', function(d) { return 'way line ' + this.parentNode.__data__ + ' ' + d.id; })
32568 .call(iD.svg.TagClasses());
32572 .attr('d', getPath)
32573 .call(iD.svg.TagClasses().tags(iD.svg.RelationMemberTags(graph)));
32579 var onewaygroup = layergroup
32580 .selectAll('g.onewaygroup')
32583 onewaygroup.enter()
32585 .attr('class', 'layer onewaygroup');
32588 var oneways = onewaygroup
32592 function() { return onewaydata[this.parentNode.parentNode.__data__] || []; },
32593 function(d) { return [d.id, d.index]; }
32598 .attr('class', 'oneway')
32599 .attr('marker-mid', 'url(#oneway-marker)');
32602 .attr('d', function(d) { return d.d; });
32604 if (iD.detect().ie) {
32605 oneways.each(function() { this.parentNode.insertBefore(this, this); });
32613 iD.svg.MapillaryImages = function(projection, context, dispatch) {
32614 var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000),
32616 layer = d3.select(null),
32621 if (iD.svg.MapillaryImages.initialized) return; // run once
32622 iD.svg.MapillaryImages.enabled = false;
32623 iD.svg.MapillaryImages.initialized = true;
32626 function getMapillary() {
32627 if (iD.services.mapillary && !_mapillary) {
32628 _mapillary = iD.services.mapillary().on('loadedImages', debouncedRedraw);
32629 } else if (!iD.services.mapillary && _mapillary) {
32635 function showThumbnail(image) {
32636 var mapillary = getMapillary();
32637 if (!mapillary) return;
32639 var thumb = mapillary.selectedThumbnail(),
32640 posX = projection(image.loc)[0],
32641 width = layer.dimensions()[0],
32642 position = (posX < width / 2) ? 'right' : 'left';
32645 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
32646 .classed('selected', function(d) { return d.key === thumb.key; });
32649 mapillary.showThumbnail(image.key, position);
32652 function hideThumbnail() {
32653 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
32654 .classed('selected', false);
32656 var mapillary = getMapillary();
32658 mapillary.hideThumbnail();
32662 function showLayer() {
32665 .style('opacity', 0)
32668 .style('opacity', 1)
32669 .each('end', debouncedRedraw);
32672 function hideLayer() {
32673 debouncedRedraw.cancel();
32678 .style('opacity', 0)
32679 .each('end', editOff);
32682 function editOn() {
32683 layer.style('display', 'block');
32686 function editOff() {
32687 layer.selectAll('.viewfield-group').remove();
32688 layer.style('display', 'none');
32691 function transform(d) {
32692 var t = iD.svg.PointTransform(projection)(d);
32693 if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
32697 function update() {
32698 var mapillary = getMapillary(),
32699 data = (mapillary ? mapillary.images(projection, layer.dimensions()) : []);
32701 var markers = layer.selectAll('.viewfield-group')
32702 .data(data, function(d) { return d.key; });
32705 var enter = markers.enter()
32707 .attr('class', 'viewfield-group');
32709 enter.append('path')
32710 .attr('class', 'viewfield')
32711 .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
32712 .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');
32714 enter.append('circle')
32725 .attr('transform', transform);
32728 function drawImages(selection) {
32729 var enabled = iD.svg.MapillaryImages.enabled,
32730 mapillary = getMapillary();
32732 layer = selection.selectAll('.layer-mapillary-images')
32733 .data(mapillary ? [0] : []);
32737 .attr('class', 'layer-mapillary-images')
32738 .style('display', enabled ? 'block' : 'none')
32739 .on('click', function() { // deselect/select
32740 var mapillary = getMapillary();
32741 if (!mapillary) return;
32742 var d = d3.event.target.__data__,
32743 thumb = mapillary.selectedThumbnail();
32744 if (thumb && thumb.key === d.key) {
32747 mapillary.selectedThumbnail(d);
32748 context.map().centerEase(d.loc);
32752 .on('mouseover', function() {
32753 var mapillary = getMapillary();
32754 if (!mapillary) return;
32755 showThumbnail(d3.event.target.__data__);
32757 .on('mouseout', function() {
32758 var mapillary = getMapillary();
32759 if (!mapillary) return;
32760 var thumb = mapillary.selectedThumbnail();
32762 showThumbnail(thumb);
32772 if (mapillary && ~~context.map().zoom() >= minZoom) {
32775 mapillary.loadImages(projection, layer.dimensions());
32782 drawImages.enabled = function(_) {
32783 if (!arguments.length) return iD.svg.MapillaryImages.enabled;
32784 iD.svg.MapillaryImages.enabled = _;
32785 if (iD.svg.MapillaryImages.enabled) {
32794 drawImages.supported = function() {
32795 return !!getMapillary();
32798 drawImages.dimensions = function(_) {
32799 if (!arguments.length) return layer.dimensions();
32800 layer.dimensions(_);
32807 iD.svg.MapillarySigns = function(projection, context, dispatch) {
32808 var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000),
32810 layer = d3.select(null),
32815 if (iD.svg.MapillarySigns.initialized) return; // run once
32816 iD.svg.MapillarySigns.enabled = false;
32817 iD.svg.MapillarySigns.initialized = true;
32820 function getMapillary() {
32821 if (iD.services.mapillary && !_mapillary) {
32822 _mapillary = iD.services.mapillary().on('loadedSigns', debouncedRedraw);
32823 } else if (!iD.services.mapillary && _mapillary) {
32829 function showThumbnail(image) {
32830 var mapillary = getMapillary();
32831 if (!mapillary) return;
32833 var thumb = mapillary.selectedThumbnail(),
32834 posX = projection(image.loc)[0],
32835 width = layer.dimensions()[0],
32836 position = (posX < width / 2) ? 'right' : 'left';
32839 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
32840 .classed('selected', function(d) { return d.key === thumb.key; });
32843 mapillary.showThumbnail(image.key, position);
32846 function hideThumbnail() {
32847 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
32848 .classed('selected', false);
32850 var mapillary = getMapillary();
32852 mapillary.hideThumbnail();
32856 function showLayer() {
32861 function hideLayer() {
32862 debouncedRedraw.cancel();
32867 function editOn() {
32868 layer.style('display', 'block');
32871 function editOff() {
32872 layer.selectAll('.icon-sign').remove();
32873 layer.style('display', 'none');
32876 function update() {
32877 var mapillary = getMapillary(),
32878 data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []);
32880 var signs = layer.selectAll('.icon-sign')
32881 .data(data, function(d) { return d.key; });
32884 var enter = signs.enter()
32885 .append('foreignObject')
32886 .attr('class', 'icon-sign')
32887 .attr('width', '32px') // for Firefox
32888 .attr('height', '32px'); // for Firefox
32891 .append('xhtml:body')
32892 .html(mapillary.signHTML);
32895 .on('click', function(d) { // deselect/select
32896 var mapillary = getMapillary();
32897 if (!mapillary) return;
32898 var thumb = mapillary.selectedThumbnail();
32899 if (thumb && thumb.key === d.key) {
32902 mapillary.selectedThumbnail(d);
32903 context.map().centerEase(d.loc);
32907 .on('mouseover', showThumbnail)
32908 .on('mouseout', function() {
32909 var mapillary = getMapillary();
32910 if (!mapillary) return;
32911 var thumb = mapillary.selectedThumbnail();
32913 showThumbnail(thumb);
32925 .attr('transform', iD.svg.PointTransform(projection));
32928 function drawSigns(selection) {
32929 var enabled = iD.svg.MapillarySigns.enabled,
32930 mapillary = getMapillary();
32932 layer = selection.selectAll('.layer-mapillary-signs')
32933 .data(mapillary ? [0] : []);
32937 .attr('class', 'layer-mapillary-signs')
32938 .style('display', enabled ? 'block' : 'none')
32939 .attr('transform', 'translate(-16, -16)'); // center signs on loc
32945 if (mapillary && ~~context.map().zoom() >= minZoom) {
32948 mapillary.loadSigns(context, projection, layer.dimensions());
32955 drawSigns.enabled = function(_) {
32956 if (!arguments.length) return iD.svg.MapillarySigns.enabled;
32957 iD.svg.MapillarySigns.enabled = _;
32958 if (iD.svg.MapillarySigns.enabled) {
32967 drawSigns.supported = function() {
32968 var mapillary = getMapillary();
32969 return (mapillary && mapillary.signsSupported());
32972 drawSigns.dimensions = function(_) {
32973 if (!arguments.length) return layer.dimensions();
32974 layer.dimensions(_);
32981 iD.svg.Midpoints = function(projection, context) {
32982 return function drawMidpoints(surface, graph, entities, filter, extent) {
32983 var poly = extent.polygon(),
32986 for (var i = 0; i < entities.length; i++) {
32987 var entity = entities[i];
32989 if (entity.type !== 'way')
32991 if (!filter(entity))
32993 if (context.selectedIDs().indexOf(entity.id) < 0)
32996 var nodes = graph.childNodes(entity);
32997 for (var j = 0; j < nodes.length - 1; j++) {
33001 id = [a.id, b.id].sort().join('-');
33003 if (midpoints[id]) {
33004 midpoints[id].parents.push(entity);
33006 if (iD.geo.euclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
33007 var point = iD.geo.interp(a.loc, b.loc, 0.5),
33010 if (extent.intersects(point)) {
33013 for (var k = 0; k < 4; k++) {
33014 point = iD.geo.lineIntersection([a.loc, b.loc], [poly[k], poly[k+1]]);
33016 iD.geo.euclideanDistance(projection(a.loc), projection(point)) > 20 &&
33017 iD.geo.euclideanDistance(projection(b.loc), projection(point)) > 20)
33030 edge: [a.id, b.id],
33039 function midpointFilter(d) {
33040 if (midpoints[d.id])
33043 for (var i = 0; i < d.parents.length; i++)
33044 if (filter(d.parents[i]))
33050 var groups = surface.selectAll('.layer-hit').selectAll('g.midpoint')
33051 .filter(midpointFilter)
33052 .data(_.values(midpoints), function(d) { return d.id; });
33054 var enter = groups.enter()
33055 .insert('g', ':first-child')
33056 .attr('class', 'midpoint');
33058 enter.append('polygon')
33059 .attr('points', '-6,8 10,0 -6,-8')
33060 .attr('class', 'shadow');
33062 enter.append('polygon')
33063 .attr('points', '-3,4 5,0 -3,-4')
33064 .attr('class', 'fill');
33067 .attr('transform', function(d) {
33068 var translate = iD.svg.PointTransform(projection),
33069 a = context.entity(d.edge[0]),
33070 b = context.entity(d.edge[1]),
33071 angle = Math.round(iD.geo.angle(a, b, projection) * (180 / Math.PI));
33072 return translate(d) + ' rotate(' + angle + ')';
33074 .call(iD.svg.TagClasses().tags(
33075 function(d) { return d.parents[0].tags; }
33078 // Propagate data bindings.
33079 groups.select('polygon.shadow');
33080 groups.select('polygon.fill');
33086 iD.svg.Osm = function() {
33087 return function drawOsm(selection) {
33088 var layers = selection.selectAll('.layer-osm')
33089 .data(['areas', 'lines', 'hit', 'halo', 'label']);
33091 layers.enter().append('g')
33092 .attr('class', function(d) { return 'layer-osm layer-' + d; });
33095 iD.svg.Points = function(projection, context) {
33096 function markerPath(selection, klass) {
33098 .attr('class', klass)
33099 .attr('transform', 'translate(-8, -23)')
33100 .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');
33103 function sortY(a, b) {
33104 return b.loc[1] - a.loc[1];
33107 return function drawPoints(surface, graph, entities, filter) {
33108 var wireframe = surface.classed('fill-wireframe'),
33109 points = wireframe ? [] : _.filter(entities, function(e) {
33110 return e.geometry(graph) === 'point';
33113 points.sort(sortY);
33115 var groups = surface.selectAll('.layer-hit').selectAll('g.point')
33117 .data(points, iD.Entity.key);
33119 var group = groups.enter()
33121 .attr('class', function(d) { return 'node point ' + d.id; })
33124 group.append('path')
33125 .call(markerPath, 'shadow');
33127 group.append('path')
33128 .call(markerPath, 'stroke');
33130 group.append('use')
33131 .attr('transform', 'translate(-6, -20)')
33132 .attr('class', 'icon')
33133 .attr('width', '12px')
33134 .attr('height', '12px');
33136 groups.attr('transform', iD.svg.PointTransform(projection))
33137 .call(iD.svg.TagClasses());
33139 // Selecting the following implicitly
33140 // sets the data (point entity) on the element
33141 groups.select('.shadow');
33142 groups.select('.stroke');
33143 groups.select('.icon')
33144 .attr('xlink:href', function(entity) {
33145 var preset = context.presets().match(entity, graph);
33146 return preset.icon ? '#' + preset.icon + '-12' : '';
33153 iD.svg.TagClasses = function() {
33155 'building', 'highway', 'railway', 'waterway', 'aeroway',
33156 'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
33160 'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
33161 'razed', 'demolished', 'obliterated'
33164 'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
33165 'surface', 'tracktype', 'crossing'
33167 tagClassRe = /^tag-/,
33168 tags = function(entity) { return entity.tags; };
33171 var tagClasses = function(selection) {
33172 selection.each(function tagClassesEach(entity) {
33173 var value = this.className,
33174 classes, primary, status;
33176 if (value.baseVal !== undefined) value = value.baseVal;
33178 classes = value.trim().split(/\s+/).filter(function(name) {
33179 return name.length && !tagClassRe.test(name);
33182 var t = tags(entity), i, k, v;
33184 // pick at most one primary classification tag..
33185 for (i = 0; i < primaries.length; i++) {
33188 if (!v || v === 'no') continue;
33191 if (statuses.indexOf(v) !== -1) { // e.g. `railway=abandoned`
33193 classes += ' tag-' + k;
33195 classes += ' tag-' + k + ' tag-' + k + '-' + v;
33201 // add at most one status tag, only if relates to primary tag..
33203 for (i = 0; i < statuses.length; i++) {
33206 if (!v || v === 'no') continue;
33208 if (v === 'yes') { // e.g. `railway=rail + abandoned=yes`
33211 else if (primary && primary === v) { // e.g. `railway=rail + abandoned=railway`
33213 } else if (!primary && primaries.indexOf(v) !== -1) { // e.g. `abandoned=railway`
33216 classes += ' tag-' + v;
33217 } // else ignore e.g. `highway=path + abandoned=railway`
33224 classes += ' tag-status tag-status-' + status;
33227 // add any secondary (structure) tags
33228 for (i = 0; i < secondaries.length; i++) {
33229 k = secondaries[i];
33231 if (!v || v === 'no') continue;
33232 classes += ' tag-' + k + ' tag-' + k + '-' + v;
33235 // For highways, look for surface tagging..
33236 if (primary === 'highway') {
33237 var paved = (t.highway !== 'track');
33240 if (k in iD.pavedTags) {
33241 paved = !!iD.pavedTags[k][v];
33246 classes += ' tag-unpaved';
33250 classes = classes.trim();
33252 if (classes !== value) {
33253 d3.select(this).attr('class', classes);
33258 tagClasses.tags = function(_) {
33259 if (!arguments.length) return tags;
33266 iD.svg.Turns = function(projection) {
33267 return function drawTurns(surface, graph, turns) {
33268 function key(turn) {
33269 return [turn.from.node + turn.via.node + turn.to.node].join('-');
33272 function icon(turn) {
33273 var u = turn.u ? '-u' : '';
33274 if (!turn.restriction)
33275 return '#turn-yes' + u;
33276 var restriction = graph.entity(turn.restriction).tags.restriction;
33278 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
33281 var groups = surface.selectAll('.layer-hit').selectAll('g.turn')
33285 var enter = groups.enter().append('g')
33286 .attr('class', 'turn');
33288 var nEnter = enter.filter(function (turn) { return !turn.u; });
33290 nEnter.append('rect')
33291 .attr('transform', 'translate(-22, -12)')
33292 .attr('width', '44')
33293 .attr('height', '24');
33295 nEnter.append('use')
33296 .attr('transform', 'translate(-22, -12)')
33297 .attr('width', '44')
33298 .attr('height', '24');
33301 var uEnter = enter.filter(function (turn) { return turn.u; });
33303 uEnter.append('circle')
33306 uEnter.append('use')
33307 .attr('transform', 'translate(-16, -16)')
33308 .attr('width', '32')
33309 .attr('height', '32');
33314 .attr('transform', function (turn) {
33315 var v = graph.entity(turn.via.node),
33316 t = graph.entity(turn.to.node),
33317 a = iD.geo.angle(v, t, projection),
33318 p = projection(v.loc),
33319 r = turn.u ? 0 : 60;
33321 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
33322 'rotate(' + a * 180 / Math.PI + ')';
33325 groups.select('use')
33326 .attr('xlink:href', icon);
33328 groups.select('rect');
33329 groups.select('circle');
33339 iD.svg.Vertices = function(projection, context) {
33341 // z16-, z17, z18+, tagged
33342 shadow: [6, 7.5, 7.5, 11.5],
33343 stroke: [2.5, 3.5, 3.5, 7],
33344 fill: [1, 1.5, 1.5, 1.5]
33349 function siblingAndChildVertices(ids, graph, extent) {
33352 function addChildVertices(entity) {
33353 if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
33355 if (entity.type === 'way') {
33356 for (i = 0; i < entity.nodes.length; i++) {
33357 addChildVertices(graph.entity(entity.nodes[i]));
33359 } else if (entity.type === 'relation') {
33360 for (i = 0; i < entity.members.length; i++) {
33361 var member = context.hasEntity(entity.members[i].id);
33363 addChildVertices(member);
33366 } else if (entity.intersects(extent, graph)) {
33367 vertices[entity.id] = entity;
33372 ids.forEach(function(id) {
33373 var entity = context.hasEntity(id);
33374 if (entity && entity.type === 'node') {
33375 vertices[entity.id] = entity;
33376 context.graph().parentWays(entity).forEach(function(entity) {
33377 addChildVertices(entity);
33379 } else if (entity) {
33380 addChildVertices(entity);
33387 function draw(selection, vertices, klass, graph, zoom) {
33389 z = (zoom < 17 ? 0 : zoom < 18 ? 1 : 2);
33391 var groups = selection
33392 .data(vertices, iD.Entity.key);
33394 function icon(entity) {
33395 if (entity.id in icons) return icons[entity.id];
33397 entity.hasInterestingTags() &&
33398 context.presets().match(entity, graph).icon;
33399 return icons[entity.id];
33402 function setClass(klass) {
33403 return function(entity) {
33404 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
33408 function setAttributes(selection) {
33409 ['shadow','stroke','fill'].forEach(function(klass) {
33410 var rads = radiuses[klass];
33411 selection.selectAll('.' + klass)
33412 .each(function(entity) {
33413 var i = z && icon(entity),
33415 r = rads[i ? 3 : z];
33416 this.setAttribute('cx', c);
33417 this.setAttribute('cy', -c);
33418 this.setAttribute('r', r);
33419 if (i && klass === 'fill') {
33420 this.setAttribute('visibility', 'hidden');
33422 this.removeAttribute('visibility');
33427 selection.selectAll('use')
33430 this.removeAttribute('visibility');
33432 this.setAttribute('visibility', 'hidden');
33437 var enter = groups.enter()
33439 .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
33441 enter.append('circle')
33442 .each(setClass('shadow'));
33444 enter.append('circle')
33445 .each(setClass('stroke'));
33447 // Vertices with icons get a `use`.
33448 enter.filter(function(d) { return icon(d); })
33450 .attr('transform', 'translate(-6, -6)')
33451 .attr('xlink:href', function(d) { return '#' + icon(d) + '-12'; })
33452 .attr('width', '12px')
33453 .attr('height', '12px')
33454 .each(setClass('icon'));
33456 // Vertices with tags get a fill.
33457 enter.filter(function(d) { return d.hasInterestingTags(); })
33459 .each(setClass('fill'));
33462 .attr('transform', iD.svg.PointTransform(projection))
33463 .classed('shared', function(entity) { return graph.isShared(entity); })
33464 .call(setAttributes);
33470 function drawVertices(surface, graph, entities, filter, extent, zoom) {
33471 var selected = siblingAndChildVertices(context.selectedIDs(), graph, extent),
33472 wireframe = surface.classed('fill-wireframe'),
33475 for (var i = 0; i < entities.length; i++) {
33476 var entity = entities[i],
33477 geometry = entity.geometry(graph);
33479 if (wireframe && geometry === 'point') {
33480 vertices.push(entity);
33484 if (geometry !== 'vertex')
33487 if (entity.id in selected ||
33488 entity.hasInterestingTags() ||
33489 entity.isIntersection(graph)) {
33490 vertices.push(entity);
33494 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-persistent')
33496 .call(draw, vertices, 'vertex-persistent', graph, zoom);
33498 drawHover(surface, graph, extent, zoom);
33501 function drawHover(surface, graph, extent, zoom) {
33502 var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent) : {};
33504 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-hover')
33505 .call(draw, d3.values(hovered), 'vertex-hover', graph, zoom);
33508 drawVertices.drawHover = function(surface, graph, target, extent, zoom) {
33509 if (target === hover) return;
33511 drawHover(surface, graph, extent, zoom);
33514 return drawVertices;
33516 iD.ui = function(context) {
33517 function render(container) {
33518 var map = context.map();
33520 if (iD.detect().opera) container.classed('opera', true);
33522 var hash = iD.behavior.Hash(context);
33526 if (!hash.hadHash) {
33527 map.centerZoom([0, 0], 2);
33530 container.append('svg')
33531 .attr('id', 'defs')
33532 .call(iD.svg.Defs(context));
33534 container.append('div')
33535 .attr('id', 'sidebar')
33536 .attr('class', 'col4')
33539 var content = container.append('div')
33540 .attr('id', 'content');
33542 var bar = content.append('div')
33544 .attr('class', 'fillD');
33546 content.append('div')
33551 .call(iD.ui.MapInMap(context));
33553 content.append('div')
33554 .call(iD.ui.Info(context));
33557 .attr('class', 'spacer col4');
33559 var limiter = bar.append('div')
33560 .attr('class', 'limiter');
33562 limiter.append('div')
33563 .attr('class', 'button-wrap joined col3')
33564 .call(iD.ui.Modes(context), limiter);
33566 limiter.append('div')
33567 .attr('class', 'button-wrap joined col1')
33568 .call(iD.ui.UndoRedo(context));
33570 limiter.append('div')
33571 .attr('class', 'button-wrap col1')
33572 .call(iD.ui.Save(context));
33575 .attr('class', 'full-screen')
33576 .call(iD.ui.FullScreen(context));
33579 .attr('class', 'spinner')
33580 .call(iD.ui.Spinner(context));
33582 var controls = bar.append('div')
33583 .attr('class', 'map-controls');
33585 controls.append('div')
33586 .attr('class', 'map-control zoombuttons')
33587 .call(iD.ui.Zoom(context));
33589 controls.append('div')
33590 .attr('class', 'map-control geolocate-control')
33591 .call(iD.ui.Geolocate(context));
33593 controls.append('div')
33594 .attr('class', 'map-control background-control')
33595 .call(iD.ui.Background(context));
33597 controls.append('div')
33598 .attr('class', 'map-control map-data-control')
33599 .call(iD.ui.MapData(context));
33601 controls.append('div')
33602 .attr('class', 'map-control help-control')
33603 .call(iD.ui.Help(context));
33605 var about = content.append('div')
33606 .attr('id', 'about');
33608 about.append('div')
33609 .attr('id', 'attrib')
33610 .call(iD.ui.Attribution(context));
33612 var footer = about.append('div')
33613 .attr('id', 'footer')
33614 .attr('class', 'fillD');
33616 footer.append('div')
33617 .attr('class', 'api-status')
33618 .call(iD.ui.Status(context));
33620 footer.append('div')
33621 .attr('id', 'scale-block')
33622 .call(iD.ui.Scale(context));
33624 var aboutList = footer.append('div')
33625 .attr('id', 'info-block')
33627 .attr('id', 'about-list');
33629 if (!context.embed()) {
33630 aboutList.call(iD.ui.Account(context));
33633 aboutList.append('li')
33635 .attr('target', '_blank')
33636 .attr('tabindex', -1)
33637 .attr('href', 'https://github.com/openstreetmap/iD')
33640 var issueLinks = aboutList.append('li');
33642 issueLinks.append('a')
33643 .attr('target', '_blank')
33644 .attr('tabindex', -1)
33645 .attr('href', 'https://github.com/openstreetmap/iD/issues')
33646 .call(iD.svg.Icon('#icon-bug', 'light'))
33647 .call(bootstrap.tooltip()
33648 .title(t('report_a_bug'))
33652 issueLinks.append('a')
33653 .attr('target', '_blank')
33654 .attr('tabindex', -1)
33655 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
33656 .call(iD.svg.Icon('#icon-translate', 'light'))
33657 .call(bootstrap.tooltip()
33658 .title(t('help_translate'))
33662 aboutList.append('li')
33663 .attr('class', 'feature-warning')
33664 .attr('tabindex', -1)
33665 .call(iD.ui.FeatureInfo(context));
33667 aboutList.append('li')
33668 .attr('class', 'user-list')
33669 .attr('tabindex', -1)
33670 .call(iD.ui.Contributors(context));
33672 window.onbeforeunload = function() {
33673 return context.save();
33676 window.onunload = function() {
33677 context.history().unlock();
33680 var mapDimensions = map.dimensions();
33682 d3.select(window).on('resize.editor', function() {
33683 mapDimensions = content.dimensions(null);
33684 map.dimensions(mapDimensions);
33688 return function() {
33689 d3.event.preventDefault();
33690 if (!context.inIntro()) context.pan(d);
33697 var keybinding = d3.keybinding('main')
33698 .on('⌫', function() { d3.event.preventDefault(); })
33699 .on('←', pan([pa, 0]))
33700 .on('↑', pan([0, pa]))
33701 .on('→', pan([-pa, 0]))
33702 .on('↓', pan([0, -pa]))
33703 .on('⇧←', pan([mapDimensions[0], 0]))
33704 .on('⇧↑', pan([0, mapDimensions[1]]))
33705 .on('⇧→', pan([-mapDimensions[0], 0]))
33706 .on('⇧↓', pan([0, -mapDimensions[1]]))
33707 .on(iD.ui.cmd('⌘←'), pan([mapDimensions[0], 0]))
33708 .on(iD.ui.cmd('⌘↑'), pan([0, mapDimensions[1]]))
33709 .on(iD.ui.cmd('⌘→'), pan([-mapDimensions[0], 0]))
33710 .on(iD.ui.cmd('⌘↓'), pan([0, -mapDimensions[1]]));
33712 d3.select(document)
33715 context.enter(iD.modes.Browse(context));
33717 context.container()
33718 .call(iD.ui.Splash(context))
33719 .call(iD.ui.Restore(context));
33721 var authenticating = iD.ui.Loading(context)
33722 .message(t('loading_auth'));
33724 context.connection()
33725 .on('authenticating.ui', function() {
33726 context.container()
33727 .call(authenticating);
33729 .on('authenticated.ui', function() {
33730 authenticating.close();
33734 function ui(container) {
33735 context.container(container);
33736 context.loadLocale(function() {
33741 ui.sidebar = iD.ui.Sidebar(context);
33746 iD.ui.tooltipHtml = function(text, key) {
33747 var s = '<span>' + text + '</span>';
33749 s += '<div class="keyhint-wrap">' +
33750 '<span> ' + (t('tooltip_keyhint')) + ' </span>' +
33751 '<span class="keyhint"> ' + key + '</span></div>';
33755 iD.ui.Account = function(context) {
33756 var connection = context.connection();
33758 function update(selection) {
33759 if (!connection.authenticated()) {
33760 selection.selectAll('#userLink, #logoutLink')
33761 .classed('hide', true);
33765 connection.userDetails(function(err, details) {
33766 var userLink = selection.select('#userLink'),
33767 logoutLink = selection.select('#logoutLink');
33770 logoutLink.html('');
33774 selection.selectAll('#userLink, #logoutLink')
33775 .classed('hide', false);
33778 userLink.append('a')
33779 .attr('href', connection.userURL(details.display_name))
33780 .attr('target', '_blank');
33782 // Add thumbnail or dont
33783 if (details.image_url) {
33784 userLink.append('img')
33785 .attr('class', 'icon pre-text user-icon')
33786 .attr('src', details.image_url);
33789 .call(iD.svg.Icon('#icon-avatar', 'pre-text light'));
33793 userLink.append('span')
33794 .attr('class', 'label')
33795 .text(details.display_name);
33797 logoutLink.append('a')
33798 .attr('class', 'logout')
33801 .on('click.logout', function() {
33802 d3.event.preventDefault();
33803 connection.logout();
33808 return function(selection) {
33809 selection.append('li')
33810 .attr('id', 'logoutLink')
33811 .classed('hide', true);
33813 selection.append('li')
33814 .attr('id', 'userLink')
33815 .classed('hide', true);
33817 connection.on('auth.account', function() { update(selection); });
33821 iD.ui.Attribution = function(context) {
33824 function attribution(data, klass) {
33825 var div = selection.selectAll('.' + klass)
33830 .attr('class', klass);
33832 var background = div.selectAll('.attribution')
33833 .data(data, function(d) { return d.name(); });
33837 .attr('class', 'attribution')
33838 .each(function(d) {
33839 if (d.terms_html) {
33841 .html(d.terms_html);
33845 var source = d.terms_text || d.id || d.name();
33848 source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
33854 .attr('href', d.terms_url)
33855 .attr('target', '_blank')
33866 var copyright = background.selectAll('.copyright-notice')
33867 .data(function(d) {
33868 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
33869 return notice ? [notice] : [];
33874 .attr('class', 'copyright-notice');
33876 copyright.text(String);
33882 function update() {
33883 attribution([context.background().baseLayerSource()], 'base-layer-attribution');
33884 attribution(context.background().overlayLayerSources().filter(function (s) {
33885 return s.validZoom(context.map().zoom());
33886 }), 'overlay-layer-attribution');
33889 return function(select) {
33890 selection = select;
33892 context.background()
33893 .on('change.attribution', update);
33896 .on('move.attribution', _.throttle(update, 400, {leading: false}));
33901 iD.ui.Background = function(context) {
33903 opacities = [1, 0.75, 0.5, 0.25],
33905 ['right', [0.5, 0]],
33906 ['top', [0, -0.5]],
33907 ['left', [-0.5, 0]],
33908 ['bottom', [0, 0.5]]],
33909 opacityDefault = (context.storage('background-opacity') !== null) ?
33910 (+context.storage('background-opacity')) : 1.0,
33911 customTemplate = context.storage('background-custom-template') || '',
33914 // Can be 0 from <1.3.0 use or due to issue #1923.
33915 if (opacityDefault === 0) opacityDefault = 1.0;
33918 function background(selection) {
33920 function sortSources(a, b) {
33921 return a.best() && !b.best() ? -1
33922 : b.best() && !a.best() ? 1
33923 : d3.descending(a.area(), b.area()) || d3.ascending(a.name(), b.name()) || 0;
33926 function setOpacity(d) {
33927 var bg = context.container().selectAll('.layer-background')
33929 .style('opacity', d)
33930 .attr('data-opacity', d);
33932 if (!iD.detect().opera) {
33933 iD.util.setTransform(bg, 0, 0);
33936 opacityList.selectAll('li')
33937 .classed('active', function(_) { return _ === d; });
33939 context.storage('background-opacity', d);
33942 function setTooltips(selection) {
33943 selection.each(function(d) {
33944 var item = d3.select(this);
33945 if (d === previous) {
33946 item.call(bootstrap.tooltip()
33948 .title(function() {
33949 var tip = '<div>' + t('background.switch') + '</div>';
33950 return iD.ui.tooltipHtml(tip, iD.ui.cmd('⌘B'));
33954 } else if (d.description) {
33955 item.call(bootstrap.tooltip()
33956 .title(d.description)
33960 item.call(bootstrap.tooltip().destroy);
33965 function selectLayer() {
33966 function active(d) {
33967 return context.background().showsLayer(d);
33970 content.selectAll('.layer, .custom_layer')
33971 .classed('active', active)
33972 .classed('switch', function(d) { return d === previous; })
33974 .selectAll('input')
33975 .property('checked', active);
33978 function clickSetSource(d) {
33979 previous = context.background().baseLayerSource();
33980 d3.event.preventDefault();
33981 context.background().baseLayerSource(d);
33983 document.activeElement.blur();
33986 function editCustom() {
33987 d3.event.preventDefault();
33988 var template = window.prompt(t('background.custom_prompt'), customTemplate);
33990 template.indexOf('google.com') !== -1 ||
33991 template.indexOf('googleapis.com') !== -1 ||
33992 template.indexOf('google.ru') !== -1) {
33996 setCustom(template);
33999 function setCustom(template) {
34000 context.background().baseLayerSource(iD.BackgroundSource.Custom(template));
34002 context.storage('background-custom-template', template);
34005 function clickSetOverlay(d) {
34006 d3.event.preventDefault();
34007 context.background().toggleOverlayLayer(d);
34009 document.activeElement.blur();
34012 function drawList(layerList, type, change, filter) {
34013 var sources = context.background()
34014 .sources(context.map().extent())
34017 var layerLinks = layerList.selectAll('li.layer')
34018 .data(sources, function(d) { return d.name(); });
34020 var enter = layerLinks.enter()
34021 .insert('li', '.custom_layer')
34022 .attr('class', 'layer')
34023 .classed('best', function(d) { return d.best(); });
34025 enter.filter(function(d) { return d.best(); })
34027 .attr('class', 'best')
34028 .call(bootstrap.tooltip()
34029 .title(t('background.best_imagery'))
34030 .placement('left'))
34034 var label = enter.append('label');
34036 label.append('input')
34037 .attr('type', type)
34038 .attr('name', 'layers')
34039 .on('change', change);
34041 label.append('span')
34042 .text(function(d) { return d.name(); });
34048 layerList.selectAll('li.layer')
34050 .style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
34053 function update() {
34054 backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
34055 overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
34059 var source = context.background().baseLayerSource();
34060 if (source.id === 'custom') {
34061 customTemplate = source.template;
34067 function updateOffsetVal() {
34068 var meters = iD.geo.offsetToMeters(context.background().offset()),
34069 x = +meters[0].toFixed(2),
34070 y = +meters[1].toFixed(2);
34072 d3.selectAll('.nudge-inner-rect')
34074 .classed('error', false)
34075 .property('value', x + ', ' + y);
34077 d3.selectAll('.nudge-reset')
34078 .classed('disabled', function() {
34079 return (x === 0 && y === 0);
34083 function resetOffset() {
34084 context.background().offset([0, 0]);
34088 function nudge(d) {
34089 context.background().nudge(d, context.map().zoom());
34093 function buttonOffset(d) {
34094 var timeout = window.setTimeout(function() {
34095 interval = window.setInterval(nudge.bind(null, d), 100);
34099 d3.select(window).on('mouseup', function() {
34100 window.clearInterval(interval);
34101 window.clearTimeout(timeout);
34102 d3.select(window).on('mouseup', null);
34108 function inputOffset() {
34109 var input = d3.select(this);
34110 var d = input.node().value;
34112 if (d === '') return resetOffset();
34114 d = d.replace(/;/g, ',').split(',').map(function(n) {
34115 // if n is NaN, it will always get mapped to false.
34116 return !isNaN(n) && n;
34119 if (d.length !== 2 || !d[0] || !d[1]) {
34120 input.classed('error', true);
34124 context.background().offset(iD.geo.metersToOffset(d));
34128 function dragOffset() {
34129 var origin = [d3.event.clientX, d3.event.clientY];
34131 context.container()
34133 .attr('class', 'nudge-surface');
34136 .on('mousemove.offset', function() {
34137 var latest = [d3.event.clientX, d3.event.clientY];
34139 -(origin[0] - latest[0]) / 4,
34140 -(origin[1] - latest[1]) / 4
34146 .on('mouseup.offset', function() {
34147 d3.selectAll('.nudge-surface')
34151 .on('mousemove.offset', null)
34152 .on('mouseup.offset', null);
34155 d3.event.preventDefault();
34162 function toggle() {
34163 if (d3.event) d3.event.preventDefault();
34164 tooltip.hide(button);
34165 setVisible(!button.classed('active'));
34168 function quickSwitch() {
34170 clickSetSource(previous);
34174 function setVisible(show) {
34175 if (show !== shown) {
34176 button.classed('active', show);
34180 selection.on('mousedown.background-inside', function() {
34181 return d3.event.stopPropagation();
34183 content.style('display', 'block')
34184 .style('right', '-300px')
34187 .style('right', '0px');
34189 content.style('display', 'block')
34190 .style('right', '0px')
34193 .style('right', '-300px')
34194 .each('end', function() {
34195 d3.select(this).style('display', 'none');
34197 selection.on('mousedown.background-inside', null);
34203 var content = selection.append('div')
34204 .attr('class', 'fillL map-overlay col3 content hide'),
34205 tooltip = bootstrap.tooltip()
34208 .title(iD.ui.tooltipHtml(t('background.description'), key)),
34209 button = selection.append('button')
34210 .attr('tabindex', -1)
34211 .on('click', toggle)
34212 .call(iD.svg.Icon('#icon-layers', 'light'))
34217 /* opacity switcher */
34219 var opa = content.append('div')
34220 .attr('class', 'opacity-options-wrapper');
34223 .text(t('background.title'));
34225 var opacityList = opa.append('ul')
34226 .attr('class', 'opacity-options');
34228 opacityList.selectAll('div.opacity')
34232 .attr('data-original-title', function(d) {
34233 return t('background.percent_brightness', { opacity: (d * 100) });
34235 .on('click.set-opacity', setOpacity)
34236 .html('<div class="select-box"></div>')
34237 .call(bootstrap.tooltip()
34238 .placement('left'))
34240 .attr('class', 'opacity')
34241 .style('opacity', function(d) { return 1.25 - d; });
34244 /* background switcher */
34246 var backgroundList = content.append('ul')
34247 .attr('class', 'layer-list');
34249 var custom = backgroundList.append('li')
34250 .attr('class', 'custom_layer')
34251 .datum(iD.BackgroundSource.Custom());
34253 custom.append('button')
34254 .attr('class', 'layer-browse')
34255 .call(bootstrap.tooltip()
34256 .title(t('background.custom_button'))
34257 .placement('left'))
34258 .on('click', editCustom)
34259 .call(iD.svg.Icon('#icon-search'));
34261 var label = custom.append('label');
34263 label.append('input')
34264 .attr('type', 'radio')
34265 .attr('name', 'layers')
34266 .on('change', function () {
34267 if (customTemplate) {
34268 setCustom(customTemplate);
34274 label.append('span')
34275 .text(t('background.custom'));
34277 content.append('div')
34278 .attr('class', 'imagery-faq')
34280 .attr('target', '_blank')
34281 .attr('tabindex', -1)
34282 .call(iD.svg.Icon('#icon-out-link', 'inline'))
34283 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
34285 .text(t('background.imagery_source_faq'));
34287 var overlayList = content.append('ul')
34288 .attr('class', 'layer-list');
34290 var controls = content.append('div')
34291 .attr('class', 'controls-list');
34294 /* minimap toggle */
34296 var minimapLabel = controls
34298 .call(bootstrap.tooltip()
34300 .title(iD.ui.tooltipHtml(t('background.minimap.tooltip'), '/'))
34304 minimapLabel.classed('minimap-toggle', true)
34306 .attr('type', 'checkbox')
34307 .on('change', function() {
34308 iD.ui.MapInMap.toggle();
34309 d3.event.preventDefault();
34312 minimapLabel.append('span')
34313 .text(t('background.minimap.description'));
34316 /* imagery offset controls */
34318 var adjustments = content.append('div')
34319 .attr('class', 'adjustments');
34321 adjustments.append('a')
34322 .text(t('background.fix_misalignment'))
34324 .classed('hide-toggle', true)
34325 .classed('expanded', false)
34326 .on('click', function() {
34327 var exp = d3.select(this).classed('expanded');
34328 nudgeContainer.style('display', exp ? 'none' : 'block');
34329 d3.select(this).classed('expanded', !exp);
34330 d3.event.preventDefault();
34333 var nudgeContainer = adjustments.append('div')
34334 .attr('class', 'nudge-container cf')
34335 .style('display', 'none');
34337 nudgeContainer.append('div')
34338 .attr('class', 'nudge-instructions')
34339 .text(t('background.offset'));
34341 var nudgeRect = nudgeContainer.append('div')
34342 .attr('class', 'nudge-outer-rect')
34343 .on('mousedown', dragOffset);
34345 nudgeRect.append('div')
34346 .attr('class', 'nudge-inner-rect')
34348 .on('change', inputOffset)
34349 .on('mousedown', function() {
34350 d3.event.stopPropagation();
34353 nudgeContainer.append('div')
34354 .selectAll('button')
34355 .data(directions).enter()
34357 .attr('class', function(d) { return d[0] + ' nudge'; })
34358 .on('mousedown', function(d) {
34359 buttonOffset(d[1]);
34362 nudgeContainer.append('button')
34363 .attr('title', t('background.reset'))
34364 .attr('class', 'nudge-reset disabled')
34365 .on('click', resetOffset)
34366 .call(iD.svg.Icon('#icon-undo'));
34369 .on('move.background-update', _.debounce(update, 1000));
34371 context.background()
34372 .on('change.background-update', update);
34376 setOpacity(opacityDefault);
34378 var keybinding = d3.keybinding('background')
34380 .on(iD.ui.cmd('⌘B'), quickSwitch)
34384 d3.select(document)
34387 context.surface().on('mousedown.background-outside', hide);
34388 context.container().on('mousedown.background-outside', hide);
34393 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
34394 // For example, ⌘Z -> Ctrl+Z
34395 iD.ui.cmd = function(code) {
34396 if (iD.detect().os === 'mac') {
34400 if (iD.detect().os === 'win') {
34401 if (code === '⌘⇧Z') return 'Ctrl+Y';
34413 for (var i = 0; i < code.length; i++) {
34414 if (code[i] in replacements) {
34415 result += replacements[code[i]] + '+';
34423 iD.ui.Commit = function(context) {
34424 var dispatch = d3.dispatch('cancel', 'save');
34426 function commit(selection) {
34427 var changes = context.history().changes(),
34428 summary = context.history().difference().summary();
34430 function zoomToEntity(change) {
34431 var entity = change.entity;
34432 if (change.changeType !== 'deleted' &&
34433 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
34434 context.map().zoomTo(entity);
34435 context.surface().selectAll(
34436 iD.util.entityOrMemberSelector([entity.id], context.graph()))
34437 .classed('hover', true);
34441 var header = selection.append('div')
34442 .attr('class', 'header fillL');
34444 header.append('h3')
34445 .text(t('commit.title'));
34447 var body = selection.append('div')
34448 .attr('class', 'body');
34452 var commentSection = body.append('div')
34453 .attr('class', 'modal-section form-field commit-form');
34455 commentSection.append('label')
34456 .attr('class', 'form-label')
34457 .text(t('commit.message_label'));
34459 var commentField = commentSection.append('textarea')
34460 .attr('placeholder', t('commit.description_placeholder'))
34461 .attr('maxlength', 255)
34462 .property('value', context.storage('comment') || '')
34463 .on('input.save', checkComment)
34464 .on('change.save', checkComment)
34465 .on('blur.save', function() {
34466 context.storage('comment', this.value);
34469 function checkComment() {
34470 d3.selectAll('.save-section .save-button')
34471 .attr('disabled', (this.value.length ? null : true));
34473 var googleWarning = clippyArea
34476 .data(this.value.match(/google/i) ? [true] : []);
34478 googleWarning.exit().remove();
34480 googleWarning.enter()
34482 .attr('target', '_blank')
34483 .attr('tabindex', -1)
34484 .call(iD.svg.Icon('#icon-alert', 'inline'))
34485 .attr('href', t('commit.google_warning_link'))
34487 .text(t('commit.google_warning'));
34490 commentField.node().select();
34492 context.connection().userChangesets(function (err, changesets) {
34497 for (var i = 0; i < changesets.length; i++) {
34498 if (changesets[i].tags.comment) {
34500 title: changesets[i].tags.comment,
34501 value: changesets[i].tags.comment
34506 commentField.call(d3.combobox().caseSensitive(true).data(comments));
34509 var clippyArea = commentSection.append('div')
34510 .attr('class', 'clippy-area');
34513 var changeSetInfo = commentSection.append('div')
34514 .attr('class', 'changeset-info');
34516 changeSetInfo.append('a')
34517 .attr('target', '_blank')
34518 .attr('tabindex', -1)
34519 .call(iD.svg.Icon('#icon-out-link', 'inline'))
34520 .attr('href', t('commit.about_changeset_comments_link'))
34522 .text(t('commit.about_changeset_comments'));
34525 var warnings = body.selectAll('div.warning-section')
34526 .data([context.history().validate(changes)])
34529 .attr('class', 'modal-section warning-section fillL2')
34530 .style('display', function(d) { return _.isEmpty(d) ? 'none' : null; })
34531 .style('background', '#ffb');
34533 warnings.append('h3')
34534 .text(t('commit.warnings'));
34536 var warningLi = warnings.append('ul')
34537 .attr('class', 'changeset-list')
34539 .data(function(d) { return d; })
34543 .on('mouseover', mouseover)
34544 .on('mouseout', mouseout)
34545 .on('click', warningClick);
34548 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
34551 .append('strong').text(function(d) {
34555 warningLi.filter(function(d) { return d.tooltip; })
34556 .call(bootstrap.tooltip()
34557 .title(function(d) { return d.tooltip; })
34562 // Upload Explanation
34563 var saveSection = body.append('div')
34564 .attr('class','modal-section save-section fillL cf');
34566 var prose = saveSection.append('p')
34567 .attr('class', 'commit-info')
34568 .html(t('commit.upload_explanation'));
34570 context.connection().userDetails(function(err, user) {
34573 var userLink = d3.select(document.createElement('div'));
34575 if (user.image_url) {
34576 userLink.append('img')
34577 .attr('src', user.image_url)
34578 .attr('class', 'icon pre-text user-icon');
34581 userLink.append('a')
34582 .attr('class','user-info')
34583 .text(user.display_name)
34584 .attr('href', context.connection().userURL(user.display_name))
34585 .attr('tabindex', -1)
34586 .attr('target', '_blank');
34588 prose.html(t('commit.upload_explanation_with_user', {user: userLink.html()}));
34593 var buttonSection = saveSection.append('div')
34594 .attr('class','buttons fillL cf');
34596 var cancelButton = buttonSection.append('button')
34597 .attr('class', 'secondary-action col5 button cancel-button')
34598 .on('click.cancel', function() { dispatch.cancel(); });
34600 cancelButton.append('span')
34601 .attr('class', 'label')
34602 .text(t('commit.cancel'));
34604 var saveButton = buttonSection.append('button')
34605 .attr('class', 'action col5 button save-button')
34606 .attr('disabled', function() {
34607 var n = d3.select('.commit-form textarea').node();
34608 return (n && n.value.length) ? null : true;
34610 .on('click.save', function() {
34612 comment: commentField.node().value
34616 saveButton.append('span')
34617 .attr('class', 'label')
34618 .text(t('commit.save'));
34622 var changeSection = body.selectAll('div.commit-section')
34626 .attr('class', 'commit-section modal-section fillL2');
34628 changeSection.append('h3')
34629 .text(t('commit.changes', {count: summary.length}));
34631 var li = changeSection.append('ul')
34632 .attr('class', 'changeset-list')
34637 .on('mouseover', mouseover)
34638 .on('mouseout', mouseout)
34639 .on('click', zoomToEntity);
34641 li.each(function(d) {
34643 .call(iD.svg.Icon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
34647 .attr('class', 'change-type')
34648 .text(function(d) {
34649 return t('commit.' + d.changeType) + ' ';
34652 li.append('strong')
34653 .attr('class', 'entity-type')
34654 .text(function(d) {
34655 return context.presets().match(d.entity, d.graph).name();
34659 .attr('class', 'entity-name')
34660 .text(function(d) {
34661 var name = iD.util.displayName(d.entity) || '',
34663 if (name !== '') string += ':';
34664 return string += ' ' + name;
34667 li.style('opacity', 0)
34669 .style('opacity', 1);
34672 function mouseover(d) {
34674 context.surface().selectAll(
34675 iD.util.entityOrMemberSelector([d.entity.id], context.graph())
34676 ).classed('hover', true);
34680 function mouseout() {
34681 context.surface().selectAll('.hover')
34682 .classed('hover', false);
34685 function warningClick(d) {
34687 context.map().zoomTo(d.entity);
34689 iD.modes.Select(context, [d.entity.id])
34690 .suppressMenu(true));
34694 // Call checkComment off the bat, in case a changeset
34695 // comment is recovered from localStorage
34696 commentField.trigger('input');
34699 return d3.rebind(commit, dispatch, 'on');
34701 iD.ui.confirm = function(selection) {
34702 var modal = iD.ui.modal(selection);
34704 modal.select('.modal')
34705 .classed('modal-alert', true);
34707 var section = modal.select('.content');
34709 section.append('div')
34710 .attr('class', 'modal-section header');
34712 section.append('div')
34713 .attr('class', 'modal-section message-text');
34715 var buttons = section.append('div')
34716 .attr('class', 'modal-section buttons cf');
34718 modal.okButton = function() {
34721 .attr('class', 'action col4')
34722 .on('click.confirm', function() {
34725 .text(t('confirm.okay'));
34732 iD.ui.Conflicts = function(context) {
34733 var dispatch = d3.dispatch('download', 'cancel', 'save'),
34736 function conflicts(selection) {
34737 var header = selection
34739 .attr('class', 'header fillL');
34743 .attr('class', 'fr')
34744 .on('click', function() { dispatch.cancel(); })
34745 .call(iD.svg.Icon('#icon-close'));
34749 .text(t('save.conflict.header'));
34751 var body = selection
34753 .attr('class', 'body fillL');
34757 .attr('class', 'conflicts-help')
34758 .text(t('save.conflict.help'))
34760 .attr('class', 'conflicts-download')
34761 .text(t('save.conflict.download_changes'))
34762 .on('click.download', function() { dispatch.download(); });
34766 .attr('class', 'conflict-container fillL3')
34767 .call(showConflict, 0);
34771 .attr('class', 'conflicts-done')
34772 .attr('opacity', 0)
34773 .style('display', 'none')
34774 .text(t('save.conflict.done'));
34778 .attr('class','buttons col12 joined conflicts-buttons');
34782 .attr('disabled', list.length > 1)
34783 .attr('class', 'action conflicts-button col6')
34784 .text(t('save.title'))
34785 .on('click.try_again', function() { dispatch.save(); });
34789 .attr('class', 'secondary-action conflicts-button col6')
34790 .text(t('confirm.cancel'))
34791 .on('click.cancel', function() { dispatch.cancel(); });
34795 function showConflict(selection, index) {
34796 if (index < 0 || index >= list.length) return;
34798 var parent = d3.select(selection.node().parentNode);
34800 // enable save button if this is the last conflict being reviewed..
34801 if (index === list.length - 1) {
34802 window.setTimeout(function() {
34803 parent.select('.conflicts-button')
34804 .attr('disabled', null);
34806 parent.select('.conflicts-done')
34808 .attr('opacity', 1)
34809 .style('display', 'block');
34813 var item = selection
34814 .selectAll('.conflict')
34815 .data([list[index]]);
34817 var enter = item.enter()
34819 .attr('class', 'conflict');
34823 .attr('class', 'conflict-count')
34824 .text(t('save.conflict.count', { num: index + 1, total: list.length }));
34828 .attr('class', 'conflict-description')
34830 .text(function(d) { return d.name; })
34831 .on('click', function(d) {
34832 zoomToEntity(d.id);
34833 d3.event.preventDefault();
34836 var details = enter
34838 .attr('class', 'conflict-detail-container');
34842 .attr('class', 'conflict-detail-list')
34844 .data(function(d) { return d.details || []; })
34847 .attr('class', 'conflict-detail-item')
34848 .html(function(d) { return d; });
34852 .attr('class', 'conflict-choices')
34857 .attr('class', 'conflict-nav-buttons joined cf')
34858 .selectAll('button')
34859 .data(['previous', 'next'])
34862 .text(function(d) { return t('save.conflict.' + d); })
34863 .attr('class', 'conflict-nav-button action col6')
34864 .attr('disabled', function(d, i) {
34865 return (i === 0 && index === 0) ||
34866 (i === 1 && index === list.length - 1) || null;
34868 .on('click', function(d, i) {
34869 var container = parent.select('.conflict-container'),
34870 sign = (i === 0 ? -1 : 1);
34873 .selectAll('.conflict')
34877 .call(showConflict, index + sign);
34879 d3.event.preventDefault();
34887 function addChoices(selection) {
34888 var choices = selection
34890 .attr('class', 'layer-list')
34892 .data(function(d) { return d.choices || []; });
34894 var enter = choices.enter()
34896 .attr('class', 'layer');
34903 .attr('type', 'radio')
34904 .attr('name', function(d) { return d.id; })
34905 .on('change', function(d, i) {
34906 var ul = this.parentNode.parentNode.parentNode;
34907 ul.__data__.chosen = i;
34913 .text(function(d) { return d.text; });
34916 .each(function(d, i) {
34917 var ul = this.parentNode;
34918 if (ul.__data__.chosen === i) choose(ul, d);
34922 function choose(ul, datum) {
34923 if (d3.event) d3.event.preventDefault();
34927 .classed('active', function(d) { return d === datum; })
34928 .selectAll('input')
34929 .property('checked', function(d) { return d === datum; });
34931 var extent = iD.geo.Extent(),
34934 entity = context.graph().hasEntity(datum.id);
34935 if (entity) extent._extend(entity.extent(context.graph()));
34939 entity = context.graph().hasEntity(datum.id);
34940 if (entity) extent._extend(entity.extent(context.graph()));
34942 zoomToEntity(datum.id, extent);
34945 function zoomToEntity(id, extent) {
34946 context.surface().selectAll('.hover')
34947 .classed('hover', false);
34949 var entity = context.graph().hasEntity(id);
34952 context.map().trimmedExtent(extent);
34954 context.map().zoomTo(entity);
34956 context.surface().selectAll(
34957 iD.util.entityOrMemberSelector([entity.id], context.graph()))
34958 .classed('hover', true);
34963 // The conflict list should be an array of objects like:
34966 // name: entityName(local),
34967 // details: merge.conflicts(),
34970 // choice(id, keepMine, forceLocal),
34971 // choice(id, keepTheirs, forceRemote)
34974 conflicts.list = function(_) {
34975 if (!arguments.length) return list;
34980 return d3.rebind(conflicts, dispatch, 'on');
34982 iD.ui.Contributors = function(context) {
34983 var debouncedUpdate = _.debounce(function() { update(); }, 1000),
34986 wrap = d3.select(null);
34988 function update() {
34990 entities = context.intersects(context.map().extent());
34992 entities.forEach(function(entity) {
34993 if (entity && entity.user) users[entity.user] = true;
34996 var u = Object.keys(users),
34997 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
35000 .call(iD.svg.Icon('#icon-nearby', 'pre-text light'));
35002 var userList = d3.select(document.createElement('span'));
35004 userList.selectAll()
35008 .attr('class', 'user-link')
35009 .attr('href', function(d) { return context.connection().userURL(d); })
35010 .attr('target', '_blank')
35011 .attr('tabindex', -1)
35014 if (u.length > limit) {
35015 var count = d3.select(document.createElement('span'));
35018 .attr('target', '_blank')
35019 .attr('tabindex', -1)
35020 .attr('href', function() {
35021 return context.connection().changesetsURL(context.map().center(), context.map().zoom());
35023 .text(u.length - limit + 1);
35025 wrap.append('span')
35026 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
35029 wrap.append('span')
35030 .html(t('contributors.list', { users: userList.html() }));
35037 .style('opacity', 0);
35039 } else if (hidden) {
35042 .style('opacity', 1);
35046 return function(selection) {
35050 context.connection().on('loaded.contributors', debouncedUpdate);
35051 context.map().on('move.contributors', debouncedUpdate);
35054 iD.ui.Disclosure = function() {
35055 var dispatch = d3.dispatch('toggled'),
35058 content = function () {};
35060 var disclosure = function(selection) {
35061 var $link = selection.selectAll('.hide-toggle')
35064 $link.enter().append('a')
35066 .attr('class', 'hide-toggle');
35069 .on('click', toggle)
35070 .classed('expanded', expanded);
35072 var $body = selection.selectAll('div')
35075 $body.enter().append('div');
35077 $body.classed('hide', !expanded)
35080 function toggle() {
35081 expanded = !expanded;
35082 $link.classed('expanded', expanded);
35083 $body.call(iD.ui.Toggle(expanded));
35084 dispatch.toggled(expanded);
35088 disclosure.title = function(_) {
35089 if (!arguments.length) return title;
35094 disclosure.expanded = function(_) {
35095 if (!arguments.length) return expanded;
35100 disclosure.content = function(_) {
35101 if (!arguments.length) return content;
35106 return d3.rebind(disclosure, dispatch, 'on');
35108 iD.ui.EntityEditor = function(context) {
35109 var dispatch = d3.dispatch('choose'),
35111 coalesceChanges = false,
35118 var presetEditor = iD.ui.preset(context)
35119 .on('change', changeTags);
35120 var rawTagEditor = iD.ui.RawTagEditor(context)
35121 .on('change', changeTags);
35123 function entityEditor(selection) {
35124 var entity = context.entity(id),
35125 tags = _.clone(entity.tags);
35127 var $header = selection.selectAll('.header')
35131 var $enter = $header.enter().append('div')
35132 .attr('class', 'header fillL cf');
35134 $enter.append('button')
35135 .attr('class', 'fl preset-reset preset-choose')
35139 $enter.append('button')
35140 .attr('class', 'fr preset-close')
35141 .call(iD.svg.Icon(modified ? '#icon-apply' : '#icon-close'));
35143 $enter.append('h3');
35146 $header.select('h3')
35147 .text(t('inspector.edit'));
35149 $header.select('.preset-close')
35150 .on('click', function() {
35151 context.enter(iD.modes.Browse(context));
35154 var $body = selection.selectAll('.inspector-body')
35158 $enter = $body.enter().append('div')
35159 .attr('class', 'inspector-body');
35161 $enter.append('div')
35162 .attr('class', 'preset-list-item inspector-inner')
35164 .attr('class', 'preset-list-button-wrap')
35166 .attr('class', 'preset-list-button preset-reset')
35167 .call(bootstrap.tooltip()
35168 .title(t('inspector.back_tooltip'))
35169 .placement('bottom'))
35171 .attr('class', 'label');
35173 $body.select('.preset-list-button-wrap')
35174 .call(reference.button);
35176 $body.select('.preset-list-item')
35177 .call(reference.body);
35179 $enter.append('div')
35180 .attr('class', 'inspector-border inspector-preset');
35182 $enter.append('div')
35183 .attr('class', 'inspector-border raw-tag-editor inspector-inner');
35185 $enter.append('div')
35186 .attr('class', 'inspector-border raw-member-editor inspector-inner');
35188 $enter.append('div')
35189 .attr('class', 'raw-membership-editor inspector-inner');
35191 selection.selectAll('.preset-reset')
35192 .on('click', function() {
35193 dispatch.choose(preset);
35197 $body.select('.preset-list-item button')
35198 .call(iD.ui.PresetIcon()
35199 .geometry(context.geometry(id))
35202 $body.select('.preset-list-item .label')
35203 .text(preset.name());
35205 $body.select('.inspector-preset')
35212 $body.select('.raw-tag-editor')
35219 if (entity.type === 'relation') {
35220 $body.select('.raw-member-editor')
35221 .style('display', 'block')
35222 .call(iD.ui.RawMemberEditor(context)
35225 $body.select('.raw-member-editor')
35226 .style('display', 'none');
35229 $body.select('.raw-membership-editor')
35230 .call(iD.ui.RawMembershipEditor(context)
35233 function historyChanged() {
35234 if (state === 'hide') return;
35236 var entity = context.hasEntity(id),
35237 graph = context.graph();
35238 if (!entity) return;
35240 entityEditor.preset(context.presets().match(entity, graph));
35241 entityEditor.modified(base !== graph);
35242 entityEditor(selection);
35246 .on('change.entity-editor', historyChanged);
35249 function clean(o) {
35251 function cleanVal(k, v) {
35252 function keepSpaces(k) {
35253 var whitelist = ['opening_hours', 'service_times', 'collection_times',
35254 'operating_times', 'smoking_hours', 'happy_hours'];
35255 return _.some(whitelist, function(s) { return k.indexOf(s) !== -1; });
35258 var blacklist = ['description', 'note', 'fixme'];
35259 if (_.some(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
35261 var cleaned = v.split(';')
35262 .map(function(s) { return s.trim(); })
35263 .join(keepSpaces(k) ? '; ' : ';');
35265 // The code below is not intended to validate websites and emails.
35266 // It is only intended to prevent obvious copy-paste errors. (#2323)
35268 // clean website- and email-like tags
35269 if (k.indexOf('website') !== -1 ||
35270 k.indexOf('email') !== -1 ||
35271 cleaned.indexOf('http') === 0) {
35273 .replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
35280 var out = {}, k, v;
35282 if (k && (v = o[k]) !== undefined) {
35283 out[k] = cleanVal(k, v);
35289 // Tag changes that fire on input can all get coalesced into a single
35290 // history operation when the user leaves the field. #2342
35291 function changeTags(changed, onInput) {
35292 var entity = context.entity(id),
35293 annotation = t('operations.change_tags.annotation'),
35294 tags = _.extend({}, entity.tags, changed);
35297 tags = clean(tags);
35299 if (!_.isEqual(entity.tags, tags)) {
35300 if (coalesceChanges) {
35301 context.overwrite(iD.actions.ChangeTags(id, tags), annotation);
35303 context.perform(iD.actions.ChangeTags(id, tags), annotation);
35304 coalesceChanges = !!onInput;
35309 entityEditor.modified = function(_) {
35310 if (!arguments.length) return modified;
35312 d3.selectAll('button.preset-close use')
35313 .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
35316 entityEditor.state = function(_) {
35317 if (!arguments.length) return state;
35319 return entityEditor;
35322 entityEditor.entityID = function(_) {
35323 if (!arguments.length) return id;
35325 base = context.graph();
35326 entityEditor.preset(context.presets().match(context.entity(id), base));
35327 entityEditor.modified(false);
35328 coalesceChanges = false;
35329 return entityEditor;
35332 entityEditor.preset = function(_) {
35333 if (!arguments.length) return preset;
35334 if (_ !== preset) {
35336 reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context)
35339 return entityEditor;
35342 return d3.rebind(entityEditor, dispatch, 'on');
35344 iD.ui.FeatureInfo = function(context) {
35345 function update(selection) {
35346 var features = context.features(),
35347 stats = features.stats(),
35349 hiddenList = _.compact(_.map(features.hidden(), function(k) {
35352 return String(stats[k]) + ' ' + t('feature.' + k + '.description');
35356 selection.html('');
35358 if (hiddenList.length) {
35359 var tooltip = bootstrap.tooltip()
35362 .title(function() {
35363 return iD.ui.tooltipHtml(hiddenList.join('<br/>'));
35366 var warning = selection.append('a')
35368 .attr('tabindex', -1)
35369 .html(t('feature_info.hidden_warning', { count: count }))
35371 .on('click', function() {
35372 tooltip.hide(warning);
35373 // open map data panel?
35374 d3.event.preventDefault();
35379 .classed('hide', !hiddenList.length);
35382 return function(selection) {
35385 context.features().on('change.feature_info', function() {
35390 iD.ui.FeatureList = function(context) {
35391 var geocodeResults;
35393 function featureList(selection) {
35394 var header = selection.append('div')
35395 .attr('class', 'header fillL cf');
35397 header.append('h3')
35398 .text(t('inspector.feature_list'));
35400 function keypress() {
35401 var q = search.property('value'),
35402 items = list.selectAll('.feature-list-item');
35403 if (d3.event.keyCode === 13 && q.length && items.size()) {
35404 click(items.datum());
35408 function inputevent() {
35409 geocodeResults = undefined;
35413 var searchWrap = selection.append('div')
35414 .attr('class', 'search-header');
35416 var search = searchWrap.append('input')
35417 .attr('placeholder', t('inspector.search'))
35418 .attr('type', 'search')
35419 .on('keypress', keypress)
35420 .on('input', inputevent);
35423 .call(iD.svg.Icon('#icon-search', 'pre-text'));
35425 var listWrap = selection.append('div')
35426 .attr('class', 'inspector-body');
35428 var list = listWrap.append('div')
35429 .attr('class', 'feature-list cf');
35432 .on('exit.feature-list', clearSearch);
35434 .on('drawn.feature-list', mapDrawn);
35436 function clearSearch() {
35437 search.property('value', '');
35441 function mapDrawn(e) {
35447 function features() {
35450 graph = context.graph(),
35451 q = search.property('value').toLowerCase();
35453 if (!q) return result;
35455 var idMatch = q.match(/^([nwr])([0-9]+)$/);
35460 geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
35461 type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
35466 var locationMatch = sexagesimal.pair(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
35468 if (locationMatch) {
35469 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
35473 type: t('inspector.location'),
35474 name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
35479 function addEntity(entity) {
35480 if (entity.id in entities || result.length > 200)
35483 entities[entity.id] = true;
35485 var name = iD.util.displayName(entity) || '';
35486 if (name.toLowerCase().indexOf(q) >= 0) {
35490 geometry: context.geometry(entity.id),
35491 type: context.presets().match(entity, graph).name(),
35496 graph.parentRelations(entity).forEach(function(parent) {
35501 var visible = context.surface().selectAll('.point, .line, .area')[0];
35502 for (var i = 0; i < visible.length && result.length <= 200; i++) {
35503 addEntity(visible[i].__data__);
35506 (geocodeResults || []).forEach(function(d) {
35507 // https://github.com/openstreetmap/iD/issues/1890
35508 if (d.osm_type && d.osm_id) {
35510 id: iD.Entity.id.fromOSM(d.osm_type, d.osm_id),
35511 geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
35512 type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
35513 : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
35514 name: d.display_name,
35515 extent: new iD.geo.Extent(
35516 [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
35517 [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
35525 function drawList() {
35526 var value = search.property('value'),
35527 results = features();
35529 list.classed('filtered', value.length);
35531 var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
35533 var resultsIndicator = list.selectAll('.no-results-item')
35535 .enter().append('button')
35536 .property('disabled', true)
35537 .attr('class', 'no-results-item')
35538 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
35540 resultsIndicator.append('span')
35541 .attr('class', 'entity-name');
35543 list.selectAll('.no-results-item .entity-name')
35544 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
35546 list.selectAll('.geocode-item')
35548 .enter().append('button')
35549 .attr('class', 'geocode-item')
35550 .on('click', geocode)
35552 .attr('class', 'label')
35554 .attr('class', 'entity-name')
35555 .text(t('geocoder.search'));
35557 list.selectAll('.no-results-item')
35558 .style('display', (value.length && !results.length) ? 'block' : 'none');
35560 list.selectAll('.geocode-item')
35561 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
35563 list.selectAll('.feature-list-item')
35567 var items = list.selectAll('.feature-list-item')
35568 .data(results, function(d) { return d.id; });
35570 var enter = items.enter()
35571 .insert('button', '.geocode-item')
35572 .attr('class', 'feature-list-item')
35573 .on('mouseover', mouseover)
35574 .on('mouseout', mouseout)
35575 .on('click', click);
35579 .attr('class', 'label');
35581 label.each(function(d) {
35583 .call(iD.svg.Icon('#icon-' + d.geometry, 'pre-text'));
35586 label.append('span')
35587 .attr('class', 'entity-type')
35588 .text(function(d) { return d.type; });
35590 label.append('span')
35591 .attr('class', 'entity-name')
35592 .text(function(d) { return d.name; });
35594 enter.style('opacity', 0)
35596 .style('opacity', 1);
35604 function mouseover(d) {
35605 if (d.id === -1) return;
35607 context.surface().selectAll(iD.util.entityOrMemberSelector([d.id], context.graph()))
35608 .classed('hover', true);
35611 function mouseout() {
35612 context.surface().selectAll('.hover')
35613 .classed('hover', false);
35616 function click(d) {
35617 d3.event.preventDefault();
35619 context.map().centerZoom([d.location[1], d.location[0]], 20);
35621 else if (d.entity) {
35622 if (d.entity.type === 'node') {
35623 context.map().center(d.entity.loc);
35624 } else if (d.entity.type === 'way') {
35625 var center = context.projection(context.map().center()),
35626 edge = iD.geo.chooseEdge(context.childNodes(d.entity), center, context.projection);
35627 context.map().center(edge.loc);
35629 context.enter(iD.modes.Select(context, [d.entity.id]).suppressMenu(true));
35631 context.zoomToEntity(d.id);
35635 function geocode() {
35636 var searchVal = encodeURIComponent(search.property('value'));
35637 d3.json('https://nominatim.openstreetmap.org/search/' + searchVal + '?limit=10&format=json', function(err, resp) {
35638 geocodeResults = resp || [];
35644 return featureList;
35646 iD.ui.flash = function(selection) {
35647 var modal = iD.ui.modal(selection);
35649 modal.select('.modal').classed('modal-flash', true);
35651 modal.select('.content')
35652 .classed('modal-section', true)
35654 .attr('class', 'description');
35656 modal.on('click.flash', function() { modal.remove(); });
35658 setTimeout(function() {
35665 iD.ui.FullScreen = function(context) {
35666 var element = context.container().node(),
35667 keybinding = d3.keybinding('full-screen');
35670 function getFullScreenFn() {
35671 if (element.requestFullscreen) {
35672 return element.requestFullscreen;
35673 } else if (element.msRequestFullscreen) {
35674 return element.msRequestFullscreen;
35675 } else if (element.mozRequestFullScreen) {
35676 return element.mozRequestFullScreen;
35677 } else if (element.webkitRequestFullscreen) {
35678 return element.webkitRequestFullscreen;
35682 function getExitFullScreenFn() {
35683 if (document.exitFullscreen) {
35684 return document.exitFullscreen;
35685 } else if (document.msExitFullscreen) {
35686 return document.msExitFullscreen;
35687 } else if (document.mozCancelFullScreen) {
35688 return document.mozCancelFullScreen;
35689 } else if (document.webkitExitFullscreen) {
35690 return document.webkitExitFullscreen;
35694 function isFullScreen() {
35695 return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement ||
35696 document.msFullscreenElement;
35699 function isSupported() {
35700 return !!getFullScreenFn();
35703 function fullScreen() {
35704 d3.event.preventDefault();
35705 if (!isFullScreen()) {
35706 // button.classed('active', true);
35707 getFullScreenFn().apply(element);
35709 // button.classed('active', false);
35710 getExitFullScreenFn().apply(document);
35714 return function() { // selection) {
35715 if (!isSupported())
35718 // var tooltip = bootstrap.tooltip()
35719 // .placement('left');
35721 // button = selection.append('button')
35722 // .attr('title', t('full_screen'))
35723 // .attr('tabindex', -1)
35724 // .on('click', fullScreen)
35727 // button.append('span')
35728 // .attr('class', 'icon full-screen');
35731 .on('f11', fullScreen)
35732 .on(iD.ui.cmd('⌘⇧F'), fullScreen);
35734 d3.select(document)
35738 iD.ui.Geolocate = function(context) {
35739 var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
35740 locating = iD.ui.Loading(context).message(t('geolocate.locating')).blocking(true),
35744 context.enter(iD.modes.Browse(context));
35745 context.container().call(locating);
35746 navigator.geolocation.getCurrentPosition(success, error, geoOptions);
35748 // This timeout ensures that we still call finish() even if
35749 // the user declines to share their location in Firefox
35750 timeoutId = setTimeout(finish, 10000 /* 10sec */ );
35753 function success(position) {
35754 var map = context.map(),
35755 extent = iD.geo.Extent([position.coords.longitude, position.coords.latitude])
35756 .padByMeters(position.coords.accuracy);
35758 map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
35766 function finish() {
35767 locating.close(); // unblock ui
35768 if (timeoutId) { clearTimeout(timeoutId); }
35769 timeoutId = undefined;
35772 return function(selection) {
35773 if (!navigator.geolocation) return;
35775 selection.append('button')
35776 .attr('tabindex', -1)
35777 .attr('title', t('geolocate.title'))
35778 .on('click', click)
35779 .call(iD.svg.Icon('#icon-geolocate', 'light'))
35780 .call(bootstrap.tooltip()
35781 .placement('left'));
35784 iD.ui.Help = function(context) {
35789 'help.editing_saving',
35798 var docs = docKeys.map(function(key) {
35801 title: text.split('\n')[0].replace('#', '').trim(),
35802 html: marked(text.split('\n').slice(1).join('\n'))
35806 function help(selection) {
35812 function toggle() {
35813 if (d3.event) d3.event.preventDefault();
35814 tooltip.hide(button);
35815 setVisible(!button.classed('active'));
35818 function setVisible(show) {
35819 if (show !== shown) {
35820 button.classed('active', show);
35824 selection.on('mousedown.help-inside', function() {
35825 return d3.event.stopPropagation();
35827 pane.style('display', 'block')
35828 .style('right', '-500px')
35831 .style('right', '0px');
35833 pane.style('right', '0px')
35836 .style('right', '-500px')
35837 .each('end', function() {
35838 d3.select(this).style('display', 'none');
35840 selection.on('mousedown.help-inside', null);
35845 function clickHelp(d, i) {
35846 pane.property('scrollTop', 0);
35847 doctitle.html(d.title);
35849 body.selectAll('a')
35850 .attr('target', '_blank');
35851 menuItems.classed('selected', function(m) {
35852 return m.title === d.title;
35858 var prevLink = nav.append('a')
35859 .attr('class', 'previous')
35860 .on('click', function() {
35861 clickHelp(docs[i - 1], i - 1);
35863 prevLink.append('span').html('◄ ' + docs[i - 1].title);
35865 if (i < docs.length - 1) {
35866 var nextLink = nav.append('a')
35867 .attr('class', 'next')
35868 .on('click', function() {
35869 clickHelp(docs[i + 1], i + 1);
35871 nextLink.append('span').html(docs[i + 1].title + ' ►');
35875 function clickWalkthrough() {
35876 d3.select(document.body).call(iD.ui.intro(context));
35881 var pane = selection.append('div')
35882 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
35883 tooltip = bootstrap.tooltip()
35886 .title(iD.ui.tooltipHtml(t('help.title'), key)),
35887 button = selection.append('button')
35888 .attr('tabindex', -1)
35889 .on('click', toggle)
35890 .call(iD.svg.Icon('#icon-help', 'light'))
35895 var toc = pane.append('ul')
35896 .attr('class', 'toc');
35898 var menuItems = toc.selectAll('li')
35903 .html(function(d) { return d.title; })
35904 .on('click', clickHelp);
35907 .attr('class','walkthrough')
35909 .text(t('splash.walkthrough'))
35910 .on('click', clickWalkthrough);
35912 var content = pane.append('div')
35913 .attr('class', 'left-content');
35915 var doctitle = content.append('h2')
35916 .text(t('help.title'));
35918 var body = content.append('div')
35919 .attr('class', 'body');
35921 var nav = content.append('div')
35922 .attr('class', 'nav');
35924 clickHelp(docs[0], 0);
35926 var keybinding = d3.keybinding('help')
35931 d3.select(document)
35934 context.surface().on('mousedown.help-outside', hide);
35935 context.container().on('mousedown.help-outside', hide);
35940 iD.ui.Info = function(context) {
35941 var key = iD.ui.cmd('⌘I'),
35942 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
35945 function info(selection) {
35946 function radiansToMeters(r) {
35947 // using WGS84 authalic radius (6371007.1809 m)
35948 return r * 6371007.1809;
35951 function steradiansToSqmeters(r) {
35952 // http://gis.stackexchange.com/a/124857/40446
35953 return r / 12.56637 * 510065621724000;
35956 function toLineString(feature) {
35957 if (feature.type === 'LineString') return feature;
35959 var result = { type: 'LineString', coordinates: [] };
35960 if (feature.type === 'Polygon') {
35961 result.coordinates = feature.coordinates[0];
35962 } else if (feature.type === 'MultiPolygon') {
35963 result.coordinates = feature.coordinates[0][0];
35969 function displayLength(m) {
35970 var d = m * (imperial ? 3.28084 : 1),
35989 // drop unnecessary precision
35990 p = d > 1000 ? 0 : d > 100 ? 1 : 2;
35992 return String(d.toFixed(p)) + ' ' + unit;
35995 function displayArea(m2) {
35996 var d = m2 * (imperial ? 10.7639111056 : 1),
35997 d1, d2, p1, p2, unit1, unit2;
36000 if (d >= 6969600) { // > 0.25mi² show mi²
36008 if (d > 4356 && d < 43560000) { // 0.1 - 1000 acres
36014 if (d >= 250000) { // > 0.25km² show km²
36022 if (d > 1000 && d < 10000000) { // 0.1 - 1000 hectares
36028 // drop unnecessary precision
36029 p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
36030 p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
36032 return String(d1.toFixed(p1)) + ' ' + unit1 +
36033 (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
36037 function redraw() {
36038 if (hidden) return;
36040 var resolver = context.graph(),
36041 selected = _.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
36042 singular = selected.length === 1 ? selected[0] : null,
36043 extent = iD.geo.Extent(),
36048 .attr('class', 'infobox-heading fillD')
36049 .text(singular || t('infobox.selected', { n: selected.length }));
36051 if (!selected.length) return;
36054 for (var i = 0; i < selected.length; i++) {
36055 entity = context.entity(selected[i]);
36056 extent._extend(entity.extent(resolver));
36058 center = extent.center();
36061 var list = wrap.append('ul');
36063 // multiple wrap, just display extent center..
36066 .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
36070 // single wrap, display details..
36071 if (!entity) return;
36072 var geometry = entity.geometry(resolver);
36074 if (geometry === 'line' || geometry === 'area') {
36075 var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
36076 feature = entity.asGeoJSON(resolver),
36077 length = radiansToMeters(d3.geo.length(toLineString(feature))),
36078 lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')),
36079 centroid = d3.geo.centroid(feature);
36082 .text(t('infobox.geometry') + ': ' +
36083 (closed ? t('infobox.closed') + ' ' : '') + t('geometry.' + geometry) );
36086 var area = steradiansToSqmeters(entity.area(resolver));
36088 .text(t('infobox.area') + ': ' + displayArea(area));
36092 .text(lengthLabel + ': ' + displayLength(length));
36095 .text(t('infobox.centroid') + ': ' + centroid[0].toFixed(5) + ', ' + centroid[1].toFixed(5));
36098 var toggle = imperial ? 'imperial' : 'metric';
36100 .text(t('infobox.' + toggle))
36102 .attr('class', 'button')
36103 .on('click', function() {
36104 d3.event.preventDefault();
36105 imperial = !imperial;
36110 var centerLabel = t('infobox.' + (entity.type === 'node' ? 'location' : 'center'));
36113 .text(t('infobox.geometry') + ': ' + t('geometry.' + geometry));
36116 .text(centerLabel + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
36121 function toggle() {
36122 if (d3.event) d3.event.preventDefault();
36128 .style('display', 'block')
36129 .style('opacity', 1)
36132 .style('opacity', 0)
36133 .each('end', function() {
36134 d3.select(this).style('display', 'none');
36138 .style('display', 'block')
36139 .style('opacity', 0)
36142 .style('opacity', 1);
36149 var wrap = selection.selectAll('.infobox')
36154 .attr('class', 'infobox fillD2')
36155 .style('display', (hidden ? 'none' : 'block'));
36158 .on('drawn.info', redraw);
36162 var keybinding = d3.keybinding('info')
36165 d3.select(document)
36171 iD.ui.Inspector = function(context) {
36172 var presetList = iD.ui.PresetList(context),
36173 entityEditor = iD.ui.EntityEditor(context),
36176 newFeature = false;
36178 function inspector(selection) {
36180 .entityID(entityID)
36181 .autofocus(newFeature)
36182 .on('choose', setPreset);
36186 .entityID(entityID)
36187 .on('choose', showList);
36189 var $wrap = selection.selectAll('.panewrap')
36192 var $enter = $wrap.enter().append('div')
36193 .attr('class', 'panewrap');
36195 $enter.append('div')
36196 .attr('class', 'preset-list-pane pane');
36198 $enter.append('div')
36199 .attr('class', 'entity-editor-pane pane');
36201 var $presetPane = $wrap.select('.preset-list-pane');
36202 var $editorPane = $wrap.select('.entity-editor-pane');
36204 var graph = context.graph(),
36205 entity = context.entity(entityID),
36206 showEditor = state === 'hover' ||
36207 entity.isUsed(graph) ||
36208 entity.isHighwayIntersection(graph);
36211 $wrap.style('right', '0%');
36212 $editorPane.call(entityEditor);
36214 $wrap.style('right', '-100%');
36215 $presetPane.call(presetList);
36218 var $footer = selection.selectAll('.footer')
36221 $footer.enter().append('div')
36222 .attr('class', 'footer');
36224 selection.select('.footer')
36225 .call(iD.ui.ViewOnOSM(context)
36226 .entityID(entityID));
36228 function showList(preset) {
36230 .styleTween('right', function() { return d3.interpolate('0%', '-100%'); });
36232 $presetPane.call(presetList
36237 function setPreset(preset) {
36239 .styleTween('right', function() { return d3.interpolate('-100%', '0%'); });
36241 $editorPane.call(entityEditor
36246 inspector.state = function(_) {
36247 if (!arguments.length) return state;
36249 entityEditor.state(state);
36253 inspector.entityID = function(_) {
36254 if (!arguments.length) return entityID;
36259 inspector.newFeature = function(_) {
36260 if (!arguments.length) return newFeature;
36267 iD.ui.intro = function(context) {
36270 function intro(selection) {
36272 function localizedName(id) {
36274 n2140018997: 'city_hall',
36275 n367813436: 'fire_department',
36276 w203988286: 'memory_isle_park',
36277 w203972937: 'riverwalk_trail',
36278 w203972938: 'riverwalk_trail',
36279 w203972940: 'riverwalk_trail',
36280 w41785752: 'w_michigan_ave',
36281 w134150789: 'w_michigan_ave',
36282 w134150795: 'w_michigan_ave',
36283 w134150800: 'w_michigan_ave',
36284 w134150811: 'w_michigan_ave',
36285 w134150802: 'e_michigan_ave',
36286 w134150836: 'e_michigan_ave',
36287 w41074896: 'e_michigan_ave',
36288 w17965834: 'spring_st',
36289 w203986457: 'scidmore_park',
36290 w203049587: 'petting_zoo',
36291 w17967397: 'n_andrews_st',
36292 w17967315: 's_andrews_st',
36293 w17967326: 'n_constantine_st',
36294 w17966400: 's_constantine_st',
36295 w170848823: 'rocky_river',
36296 w170848824: 'rocky_river',
36297 w170848331: 'rocky_river',
36298 w17967752: 'railroad_dr',
36299 w17965998: 'conrail_rr',
36300 w134150845: 'conrail_rr',
36301 w170989131: 'st_joseph_river',
36302 w143497377: 'n_main_st',
36303 w134150801: 's_main_st',
36304 w134150830: 's_main_st',
36305 w17966462: 's_main_st',
36306 w17967734: 'water_st',
36307 w17964996: 'foster_st',
36308 w170848330: 'portage_river',
36309 w17965351: 'flower_st',
36310 w17965502: 'elm_st',
36311 w17965402: 'walnut_st',
36312 w17964793: 'morris_ave',
36313 w17967444: 'east_st',
36314 w17966984: 'portage_ave'
36316 return features[id] && t('intro.graph.' + features[id]);
36319 context.enter(iD.modes.Browse(context));
36321 // Save current map state
36322 var history = context.history().toJSON(),
36323 hash = window.location.hash,
36324 center = context.map().center(),
36325 zoom = context.map().zoom(),
36326 background = context.background().baseLayerSource(),
36327 opacity = d3.selectAll('#map .layer-background').style('opacity'),
36328 loadedTiles = context.connection().loadedTiles(),
36329 baseEntities = context.history().graph().base().entities,
36333 context.inIntro(true);
36335 // Load semi-real data used in intro
36336 context.connection().toggle(false).flush();
36337 context.history().reset();
36339 introGraph = JSON.parse(iD.introGraph);
36340 for (var key in introGraph) {
36341 introGraph[key] = iD.Entity(introGraph[key]);
36342 name = localizedName(key);
36344 introGraph[key].tags.name = name;
36347 context.history().merge(d3.values(iD.Graph().load(introGraph).entities));
36348 context.background().bing();
36350 d3.selectAll('#map .layer-background').style('opacity', 1);
36352 var curtain = d3.curtain();
36353 selection.call(curtain);
36355 function reveal(box, text, options) {
36356 options = options || {};
36357 if (text) curtain.reveal(box, text, options.tooltipClass, options.duration);
36358 else curtain.reveal(box, '', '', options.duration);
36361 var steps = ['navigation', 'point', 'area', 'line', 'startEditing'].map(function(step, i) {
36362 var s = iD.ui.intro[step](context, reveal)
36363 .on('done', function() {
36364 entered.filter(function(d) {
36365 return d.title === s.title;
36366 }).classed('finished', true);
36367 enter(steps[i + 1]);
36372 steps[steps.length - 1].on('startEditing', function() {
36375 d3.selectAll('#map .layer-background').style('opacity', opacity);
36376 context.connection().toggle(true).flush().loadedTiles(loadedTiles);
36377 context.history().reset().merge(d3.values(baseEntities));
36378 context.background().baseLayerSource(background);
36379 if (history) context.history().fromJSON(history, false);
36380 context.map().centerZoom(center, zoom);
36381 window.location.replace(hash);
36382 context.inIntro(false);
36385 var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
36387 var buttonwrap = navwrap.append('div')
36388 .attr('class', 'joined')
36389 .selectAll('button.step');
36391 var entered = buttonwrap
36395 .attr('class', 'step')
36396 .on('click', enter);
36399 .call(iD.svg.Icon('#icon-apply', 'pre-text'));
36403 .text(function(d) { return t(d.title); });
36407 function enter (newStep) {
36408 if (step) { step.exit(); }
36410 context.enter(iD.modes.Browse(context));
36415 entered.classed('active', function(d) {
36416 return d.title === step.title;
36424 iD.ui.intro.pointBox = function(point, context) {
36425 var rect = context.surfaceRect();
36426 point = context.projection(point);
36428 left: point[0] + rect.left - 30,
36429 top: point[1] + rect.top - 50,
36435 iD.ui.intro.pad = function(box, padding, context) {
36436 if (box instanceof Array) {
36437 var rect = context.surfaceRect();
36438 box = context.projection(box);
36440 left: box[0] + rect.left,
36441 top: box[1] + rect.top
36445 left: box.left - padding,
36446 top: box.top - padding,
36447 width: (box.width || 0) + 2 * padding,
36448 height: (box.width || 0) + 2 * padding
36452 iD.ui.intro.icon = function(name, svgklass) {
36453 return '<svg class="icon ' + (svgklass || '') + '">' +
36454 '<use xlink:href="' + name + '"></use></svg>';
36456 iD.ui.Lasso = function(context) {
36457 var group, polygon;
36459 lasso.coordinates = [];
36461 function lasso(selection) {
36463 context.container().classed('lasso', true);
36465 group = selection.append('g')
36466 .attr('class', 'lasso hide');
36468 polygon = group.append('path')
36469 .attr('class', 'lasso-path');
36471 group.call(iD.ui.Toggle(true));
36477 polygon.data([lasso.coordinates])
36478 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
36482 lasso.extent = function () {
36483 return lasso.coordinates.reduce(function(extent, point) {
36484 return extent.extend(iD.geo.Extent(point));
36485 }, iD.geo.Extent());
36488 lasso.p = function(_) {
36489 if (!arguments.length) return lasso;
36490 lasso.coordinates.push(_);
36495 lasso.close = function() {
36497 group.call(iD.ui.Toggle(false, function() {
36498 d3.select(this).remove();
36501 context.container().classed('lasso', false);
36506 iD.ui.Loading = function(context) {
36511 var loading = function(selection) {
36512 modal = iD.ui.modal(selection, blocking);
36514 var loadertext = modal.select('.content')
36515 .classed('loading-modal', true)
36517 .attr('class', 'modal-section fillL');
36519 loadertext.append('img')
36520 .attr('class', 'loader')
36521 .attr('src', context.imagePath('loader-white.gif'));
36523 loadertext.append('h3')
36526 modal.select('button.close')
36527 .attr('class', 'hide');
36532 loading.message = function(_) {
36533 if (!arguments.length) return message;
36538 loading.blocking = function(_) {
36539 if (!arguments.length) return blocking;
36544 loading.close = function() {
36550 iD.ui.MapData = function(context) {
36552 features = context.features().keys(),
36553 layers = context.layers(),
36554 fills = ['wireframe', 'partial', 'full'],
36555 fillDefault = context.storage('area-fill') || 'partial',
36556 fillSelected = fillDefault;
36559 function map_data(selection) {
36561 function showsFeature(d) {
36562 return context.features().enabled(d);
36565 function autoHiddenFeature(d) {
36566 return context.features().autoHidden(d);
36569 function clickFeature(d) {
36570 context.features().toggle(d);
36574 function showsFill(d) {
36575 return fillSelected === d;
36578 function setFill(d) {
36579 _.each(fills, function(opt) {
36580 context.surface().classed('fill-' + opt, Boolean(opt === d));
36584 if (d !== 'wireframe') {
36586 context.storage('area-fill', d);
36591 function toggleLayer(which) {
36592 var layer = layers.layer(which);
36594 layer.enabled(!layer.enabled());
36599 function clickGpx() {
36600 toggleLayer('gpx');
36603 function clickMapillaryImages() {
36604 toggleLayer('mapillary-images');
36607 function clickMapillarySigns() {
36608 toggleLayer('mapillary-signs');
36612 function drawMapillaryItems(selection) {
36613 var mapillaryImages = layers.layer('mapillary-images'),
36614 mapillarySigns = layers.layer('mapillary-signs'),
36615 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
36616 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
36617 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
36618 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
36620 var mapillaryList = selection
36621 .selectAll('.layer-list-mapillary')
36628 .attr('class', 'layer-list layer-list-mapillary');
36630 var mapillaryImageLayerItem = mapillaryList
36631 .selectAll('.list-item-mapillary-images')
36632 .data(supportsMapillaryImages ? [0] : []);
36634 var enterImages = mapillaryImageLayerItem.enter()
36636 .attr('class', 'list-item-mapillary-images');
36638 var labelImages = enterImages.append('label')
36639 .call(bootstrap.tooltip()
36640 .title(t('mapillary_images.tooltip'))
36641 .placement('top'));
36643 labelImages.append('input')
36644 .attr('type', 'checkbox')
36645 .on('change', clickMapillaryImages);
36647 labelImages.append('span')
36648 .text(t('mapillary_images.title'));
36651 var mapillarySignLayerItem = mapillaryList
36652 .selectAll('.list-item-mapillary-signs')
36653 .data(supportsMapillarySigns ? [0] : []);
36655 var enterSigns = mapillarySignLayerItem.enter()
36657 .attr('class', 'list-item-mapillary-signs');
36659 var labelSigns = enterSigns.append('label')
36660 .call(bootstrap.tooltip()
36661 .title(t('mapillary_signs.tooltip'))
36662 .placement('top'));
36664 labelSigns.append('input')
36665 .attr('type', 'checkbox')
36666 .on('change', clickMapillarySigns);
36668 labelSigns.append('span')
36669 .text(t('mapillary_signs.title'));
36672 mapillaryImageLayerItem
36673 .classed('active', showsMapillaryImages)
36674 .selectAll('input')
36675 .property('checked', showsMapillaryImages);
36677 mapillarySignLayerItem
36678 .classed('active', showsMapillarySigns)
36679 .selectAll('input')
36680 .property('checked', showsMapillarySigns);
36683 mapillaryImageLayerItem.exit()
36685 mapillarySignLayerItem.exit()
36690 function drawGpxItem(selection) {
36691 var gpx = layers.layer('gpx'),
36692 hasGpx = gpx && gpx.hasGpx(),
36693 showsGpx = hasGpx && gpx.enabled();
36695 var gpxLayerItem = selection
36696 .selectAll('.layer-list-gpx')
36697 .data(gpx ? [0] : []);
36700 var enter = gpxLayerItem.enter()
36702 .attr('class', 'layer-list layer-list-gpx')
36704 .classed('list-item-gpx', true);
36706 enter.append('button')
36707 .attr('class', 'list-item-gpx-extent')
36708 .call(bootstrap.tooltip()
36709 .title(t('gpx.zoom'))
36710 .placement('left'))
36711 .on('click', function() {
36712 d3.event.preventDefault();
36713 d3.event.stopPropagation();
36716 .call(iD.svg.Icon('#icon-search'));
36718 enter.append('button')
36719 .attr('class', 'list-item-gpx-browse')
36720 .call(bootstrap.tooltip()
36721 .title(t('gpx.browse'))
36722 .placement('left'))
36723 .on('click', function() {
36724 d3.select(document.createElement('input'))
36725 .attr('type', 'file')
36726 .on('change', function() {
36727 gpx.files(d3.event.target.files);
36731 .call(iD.svg.Icon('#icon-geolocate'));
36733 var labelGpx = enter.append('label')
36734 .call(bootstrap.tooltip()
36735 .title(t('gpx.drag_drop'))
36736 .placement('top'));
36738 labelGpx.append('input')
36739 .attr('type', 'checkbox')
36740 .on('change', clickGpx);
36742 labelGpx.append('span')
36743 .text(t('gpx.local_layer'));
36747 .classed('active', showsGpx)
36748 .selectAll('input')
36749 .property('disabled', !hasGpx)
36750 .property('checked', showsGpx);
36753 gpxLayerItem.exit()
36758 function drawList(selection, data, type, name, change, active) {
36759 var items = selection.selectAll('li')
36763 var enter = items.enter()
36765 .attr('class', 'layer')
36766 .call(bootstrap.tooltip()
36768 .title(function(d) {
36769 var tip = t(name + '.' + d + '.tooltip'),
36770 key = (d === 'wireframe' ? 'W' : null);
36772 if (name === 'feature' && autoHiddenFeature(d)) {
36773 tip += '<div>' + t('map_data.autohidden') + '</div>';
36775 return iD.ui.tooltipHtml(tip, key);
36780 var label = enter.append('label');
36782 label.append('input')
36783 .attr('type', type)
36784 .attr('name', name)
36785 .on('change', change);
36787 label.append('span')
36788 .text(function(d) { return t(name + '.' + d + '.description'); });
36792 .classed('active', active)
36793 .selectAll('input')
36794 .property('checked', active)
36795 .property('indeterminate', function(d) {
36796 return (name === 'feature' && autoHiddenFeature(d));
36805 function update() {
36806 dataLayerContainer.call(drawMapillaryItems);
36807 dataLayerContainer.call(drawGpxItem);
36809 fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
36811 featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
36814 function hidePanel() {
36818 function togglePanel() {
36819 if (d3.event) d3.event.preventDefault();
36820 tooltip.hide(button);
36821 setVisible(!button.classed('active'));
36824 function toggleWireframe() {
36826 d3.event.preventDefault();
36827 d3.event.stopPropagation();
36829 setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
36830 context.map().pan([0,0]); // trigger a redraw
36833 function setVisible(show) {
36834 if (show !== shown) {
36835 button.classed('active', show);
36840 selection.on('mousedown.map_data-inside', function() {
36841 return d3.event.stopPropagation();
36843 content.style('display', 'block')
36844 .style('right', '-300px')
36847 .style('right', '0px');
36849 content.style('display', 'block')
36850 .style('right', '0px')
36853 .style('right', '-300px')
36854 .each('end', function() {
36855 d3.select(this).style('display', 'none');
36857 selection.on('mousedown.map_data-inside', null);
36863 var content = selection.append('div')
36864 .attr('class', 'fillL map-overlay col3 content hide'),
36865 tooltip = bootstrap.tooltip()
36868 .title(iD.ui.tooltipHtml(t('map_data.description'), key)),
36869 button = selection.append('button')
36870 .attr('tabindex', -1)
36871 .on('click', togglePanel)
36872 .call(iD.svg.Icon('#icon-data', 'light'))
36876 content.append('h4')
36877 .text(t('map_data.title'));
36881 content.append('a')
36882 .text(t('map_data.data_layers'))
36884 .classed('hide-toggle', true)
36885 .classed('expanded', true)
36886 .on('click', function() {
36887 var exp = d3.select(this).classed('expanded');
36888 dataLayerContainer.style('display', exp ? 'none' : 'block');
36889 d3.select(this).classed('expanded', !exp);
36890 d3.event.preventDefault();
36893 var dataLayerContainer = content.append('div')
36894 .attr('class', 'data-data-layers')
36895 .style('display', 'block');
36899 content.append('a')
36900 .text(t('map_data.fill_area'))
36902 .classed('hide-toggle', true)
36903 .classed('expanded', false)
36904 .on('click', function() {
36905 var exp = d3.select(this).classed('expanded');
36906 fillContainer.style('display', exp ? 'none' : 'block');
36907 d3.select(this).classed('expanded', !exp);
36908 d3.event.preventDefault();
36911 var fillContainer = content.append('div')
36912 .attr('class', 'data-area-fills')
36913 .style('display', 'none');
36915 var fillList = fillContainer.append('ul')
36916 .attr('class', 'layer-list layer-fill-list');
36920 content.append('a')
36921 .text(t('map_data.map_features'))
36923 .classed('hide-toggle', true)
36924 .classed('expanded', false)
36925 .on('click', function() {
36926 var exp = d3.select(this).classed('expanded');
36927 featureContainer.style('display', exp ? 'none' : 'block');
36928 d3.select(this).classed('expanded', !exp);
36929 d3.event.preventDefault();
36932 var featureContainer = content.append('div')
36933 .attr('class', 'data-feature-filters')
36934 .style('display', 'none');
36936 var featureList = featureContainer.append('ul')
36937 .attr('class', 'layer-list layer-feature-list');
36941 .on('change.map_data-update', update);
36943 setFill(fillDefault);
36945 var keybinding = d3.keybinding('features')
36946 .on(key, togglePanel)
36947 .on('W', toggleWireframe)
36948 .on('B', hidePanel)
36949 .on('H', hidePanel);
36951 d3.select(document)
36954 context.surface().on('mousedown.map_data-outside', hidePanel);
36955 context.container().on('mousedown.map_data-outside', hidePanel);
36960 iD.ui.MapInMap = function(context) {
36963 function map_in_map(selection) {
36964 var backgroundLayer = iD.TileLayer(context),
36965 overlayLayers = {},
36966 projection = iD.geo.RawMercator(),
36967 gpxLayer = iD.svg.Gpx(projection, context).showLabels(false),
36968 zoom = d3.behavior.zoom()
36969 .scaleExtent([ztok(0.5), ztok(24)])
36970 .on('zoom', zoomPan),
36971 transformed = false,
36974 zDiff = 6, // by default, minimap renders at (main zoom - 6)
36975 tStart, tLast, tCurr, kLast, kCurr, tiles, svg, timeoutId;
36977 function ztok(z) { return 256 * Math.pow(2, z); }
36978 function ktoz(k) { return Math.log(k) / Math.LN2 - 8; }
36981 function startMouse() {
36982 context.surface().on('mouseup.map-in-map-outside', endMouse);
36983 context.container().on('mouseup.map-in-map-outside', endMouse);
36985 tStart = tLast = tCurr = projection.translate();
36990 function zoomPan() {
36991 var e = d3.event.sourceEvent,
36992 t = d3.event.translate,
36993 k = d3.event.scale,
36994 zMain = ktoz(context.projection.scale() * 2 * Math.PI),
36997 // restrict minimap zoom to < (main zoom - 3)
36998 if (zMini > zMain - 3) {
37000 zoom.scale(kCurr).translate(tCurr); // restore last good values
37006 zDiff = zMain - zMini;
37008 var scale = kCurr / kLast,
37009 tX = (tCurr[0] / scale - tLast[0]) * scale,
37010 tY = (tCurr[1] / scale - tLast[1]) * scale;
37012 iD.util.setTransform(tiles, tX, tY, scale);
37013 iD.util.setTransform(svg, 0, 0, scale);
37014 transformed = true;
37018 e.preventDefault();
37019 e.stopPropagation();
37023 function endMouse() {
37024 context.surface().on('mouseup.map-in-map-outside', null);
37025 context.container().on('mouseup.map-in-map-outside', null);
37027 updateProjection();
37030 if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) {
37031 var dMini = wrap.dimensions(),
37032 cMini = [ dMini[0] / 2, dMini[1] / 2 ];
37034 context.map().center(projection.invert(cMini));
37039 function updateProjection() {
37040 var loc = context.map().center(),
37041 dMini = wrap.dimensions(),
37042 cMini = [ dMini[0] / 2, dMini[1] / 2 ],
37043 tMain = context.projection.translate(),
37044 kMain = context.projection.scale(),
37045 zMain = ktoz(kMain * 2 * Math.PI),
37046 zMini = Math.max(zMain - zDiff, 0.5),
37047 kMini = ztok(zMini);
37051 .scale(kMini / (2 * Math.PI));
37053 var s = projection(loc),
37054 mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0],
37056 cMini[0] - s[0] + tMain[0] + mouse[0],
37057 cMini[1] - s[1] + tMain[1] + mouse[1]
37062 .clipExtent([[0, 0], dMini]);
37069 tLast = tCurr = tMini;
37070 kLast = kCurr = kMini;
37073 iD.util.setTransform(tiles, 0, 0);
37074 iD.util.setTransform(svg, 0, 0);
37075 transformed = false;
37080 function redraw() {
37081 if (hidden) return;
37083 updateProjection();
37085 var dMini = wrap.dimensions(),
37086 zMini = ktoz(projection.scale() * 2 * Math.PI);
37088 // setup tile container
37090 .selectAll('.map-in-map-tiles')
37096 .attr('class', 'map-in-map-tiles');
37098 // redraw background
37100 .source(context.background().baseLayerSource())
37101 .projection(projection)
37102 .dimensions(dMini);
37104 var background = tiles
37105 .selectAll('.map-in-map-background')
37110 .attr('class', 'map-in-map-background');
37113 .call(backgroundLayer);
37117 var overlaySources = context.background().overlayLayerSources();
37118 var activeOverlayLayers = [];
37119 for (var i = 0; i < overlaySources.length; i++) {
37120 if (overlaySources[i].validZoom(zMini)) {
37121 if (!overlayLayers[i]) overlayLayers[i] = iD.TileLayer(context);
37122 activeOverlayLayers.push(overlayLayers[i]
37123 .source(overlaySources[i])
37124 .projection(projection)
37125 .dimensions(dMini));
37129 var overlay = tiles
37130 .selectAll('.map-in-map-overlay')
37135 .attr('class', 'map-in-map-overlay');
37137 var overlays = overlay
37139 .data(activeOverlayLayers, function(d) { return d.source().name(); });
37141 overlays.enter().append('div');
37142 overlays.each(function(layer) {
37143 d3.select(this).call(layer);
37151 .selectAll('.map-in-map-gpx')
37152 .data(gpxLayer.enabled() ? [0] : []);
37156 .attr('class', 'map-in-map-gpx');
37161 gpx.call(gpxLayer);
37164 // redraw bounding box
37166 var getPath = d3.geo.path().projection(projection),
37167 bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
37169 svg = wrap.selectAll('.map-in-map-svg')
37174 .attr('class', 'map-in-map-svg');
37176 var path = svg.selectAll('.map-in-map-bbox')
37181 .attr('class', 'map-in-map-bbox');
37184 .attr('d', getPath)
37185 .classed('thick', function(d) { return getPath.area(d) < 30; });
37190 function queueRedraw() {
37191 clearTimeout(timeoutId);
37192 timeoutId = setTimeout(function() { redraw(); }, 300);
37196 function toggle() {
37197 if (d3.event) d3.event.preventDefault();
37201 var label = d3.select('.minimap-toggle');
37202 label.classed('active', !hidden)
37203 .select('input').property('checked', !hidden);
37207 .style('display', 'block')
37208 .style('opacity', 1)
37211 .style('opacity', 0)
37212 .each('end', function() {
37213 d3.select(this).style('display', 'none');
37217 .style('display', 'block')
37218 .style('opacity', 0)
37221 .style('opacity', 1);
37227 iD.ui.MapInMap.toggle = toggle;
37229 var wrap = selection.selectAll('.map-in-map')
37234 .attr('class', 'map-in-map')
37235 .style('display', (hidden ? 'none' : 'block'))
37236 .on('mousedown.map-in-map', startMouse)
37237 .on('mouseup.map-in-map', endMouse)
37239 .on('dblclick.zoom', null);
37242 .on('drawn.map-in-map', function(drawn) {
37243 if (drawn.full === true) redraw();
37248 var keybinding = d3.keybinding('map-in-map')
37251 d3.select(document)
37257 iD.ui.modal = function(selection, blocking) {
37258 var keybinding = d3.keybinding('modal');
37259 var previous = selection.select('div.modal');
37260 var animate = previous.empty();
37262 previous.transition()
37264 .style('opacity', 0)
37267 var shaded = selection
37269 .attr('class', 'shaded')
37270 .style('opacity', 0);
37272 shaded.close = function() {
37276 .style('opacity',0)
37281 .style('top','0px');
37287 var modal = shaded.append('div')
37288 .attr('class', 'modal fillL col6');
37291 shaded.on('click.remove-modal', function() {
37292 if (d3.event.target === this) {
37297 modal.append('button')
37298 .attr('class', 'close')
37299 .on('click', shaded.close)
37300 .call(iD.svg.Icon('#icon-close'));
37303 .on('⌫', shaded.close)
37304 .on('⎋', shaded.close);
37306 d3.select(document).call(keybinding);
37309 modal.append('div')
37310 .attr('class', 'content');
37313 shaded.transition().style('opacity', 1);
37315 shaded.style('opacity', 1);
37320 iD.ui.Modes = function(context) {
37322 iD.modes.AddPoint(context),
37323 iD.modes.AddLine(context),
37324 iD.modes.AddArea(context)];
37326 function editable() {
37327 return context.editable() && context.mode().id !== 'save';
37330 return function(selection) {
37331 var buttons = selection.selectAll('button.add-button')
37334 buttons.enter().append('button')
37335 .attr('tabindex', -1)
37336 .attr('class', function(mode) { return mode.id + ' add-button col4'; })
37337 .on('click.mode-buttons', function(mode) {
37338 if (mode.id === context.mode().id) {
37339 context.enter(iD.modes.Browse(context));
37341 context.enter(mode);
37344 .call(bootstrap.tooltip()
37345 .placement('bottom')
37347 .title(function(mode) {
37348 return iD.ui.tooltipHtml(mode.description, mode.key);
37352 .on('move.modes', _.debounce(update, 500));
37355 .on('enter.modes', update);
37357 buttons.each(function(d) {
37359 .call(iD.svg.Icon('#icon-' + d.button, 'pre-text'));
37362 buttons.append('span')
37363 .attr('class', 'label')
37364 .text(function(mode) { return mode.title; });
37366 context.on('enter.editor', function(entered) {
37367 buttons.classed('active', function(mode) { return entered.button === mode.button; });
37368 context.container()
37369 .classed('mode-' + entered.id, true);
37372 context.on('exit.editor', function(exited) {
37373 context.container()
37374 .classed('mode-' + exited.id, false);
37377 var keybinding = d3.keybinding('mode-buttons');
37379 modes.forEach(function(m) {
37380 keybinding.on(m.key, function() { if (editable()) context.enter(m); });
37383 d3.select(document)
37386 function update() {
37387 buttons.property('disabled', !editable());
37391 iD.ui.Notice = function(context) {
37392 return function(selection) {
37393 var div = selection.append('div')
37394 .attr('class', 'notice');
37396 var button = div.append('button')
37397 .attr('class', 'zoom-to notice')
37398 .on('click', function() { context.map().zoom(context.minEditableZoom()); });
37401 .call(iD.svg.Icon('#icon-plus', 'pre-text'))
37403 .attr('class', 'label')
37404 .text(t('zoom_in_edit'));
37406 function disableTooHigh() {
37407 div.style('display', context.editable() ? 'none' : 'block');
37411 .on('move.notice', _.debounce(disableTooHigh, 500));
37416 iD.ui.PresetIcon = function() {
37417 var preset, geometry;
37419 function presetIcon(selection) {
37420 selection.each(render);
37423 function render() {
37424 var selection = d3.select(this),
37425 p = preset.apply(this, arguments),
37426 geom = geometry.apply(this, arguments),
37427 icon = p.icon || (geom === 'line' ? 'other-line' : 'marker-stroked'),
37428 maki = iD.data.featureIcons.hasOwnProperty(icon + '-24');
37430 if (icon === 'dentist') maki = true; // workaround for dentist icon missing in `maki-sprite.json`
37432 function tag_classes(p) {
37434 for (var i in p.tags) {
37436 if (p.tags[i] !== '*') {
37437 s += ' tag-' + i + '-' + p.tags[i];
37443 var $fill = selection.selectAll('.preset-icon-fill')
37446 $fill.enter().append('div');
37448 $fill.attr('class', function() {
37449 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
37452 var $frame = selection.selectAll('.preset-icon-frame')
37457 .call(iD.svg.Icon('#preset-icon-frame'));
37459 $frame.attr('class', function() {
37460 return 'preset-icon-frame ' + (geom === 'area' ? '' : 'hide');
37464 var $icon = selection.selectAll('.preset-icon')
37469 .attr('class', 'preset-icon')
37470 .call(iD.svg.Icon(''));
37473 .attr('class', 'preset-icon preset-icon-' + (maki ? '32' : (geom === 'area' ? '44' : '60')));
37475 $icon.selectAll('svg')
37476 .attr('class', function() {
37477 return 'icon ' + icon + tag_classes(p);
37480 $icon.selectAll('use') // workaround: maki parking-24 broken?
37481 .attr('href', '#' + icon + (maki ? ( icon === 'parking' ? '-18' : '-24') : ''));
37484 presetIcon.preset = function(_) {
37485 if (!arguments.length) return preset;
37486 preset = d3.functor(_);
37490 presetIcon.geometry = function(_) {
37491 if (!arguments.length) return geometry;
37492 geometry = d3.functor(_);
37498 iD.ui.preset = function(context) {
37499 var event = d3.dispatch('change'),
37506 function UIField(field, entity, show) {
37507 field = _.clone(field);
37509 field.input = iD.ui.preset[field.type](field, context)
37510 .on('change', event.change);
37512 if (field.input.entity) field.input.entity(entity);
37514 field.keys = field.keys || [field.key];
37518 field.shown = function() {
37519 return field.id === 'name' || field.show || _.some(field.keys, function(key) { return !!tags[key]; });
37522 field.modified = function() {
37523 var original = context.graph().base().entities[entity.id];
37524 return _.some(field.keys, function(key) {
37525 return original ? tags[key] !== original.tags[key] : tags[key];
37529 field.revert = function() {
37530 var original = context.graph().base().entities[entity.id],
37532 field.keys.forEach(function(key) {
37533 t[key] = original ? original.tags[key] : undefined;
37538 field.present = function() {
37539 return _.some(field.keys, function(key) {
37544 field.remove = function() {
37546 field.keys.forEach(function(key) {
37547 t[key] = undefined;
37555 function fieldKey(field) {
37559 function presets(selection) {
37560 selection.call(iD.ui.Disclosure()
37561 .title(t('inspector.all_fields'))
37562 .expanded(context.storage('preset_fields.expanded') !== 'false')
37563 .on('toggled', toggled)
37564 .content(content));
37566 function toggled(expanded) {
37567 context.storage('preset_fields.expanded', expanded);
37571 function content(selection) {
37573 var entity = context.entity(id),
37574 geometry = context.geometry(id);
37576 fields = [UIField(context.presets().field('name'), entity)];
37578 preset.fields.forEach(function(field) {
37579 if (field.matchGeometry(geometry)) {
37580 fields.push(UIField(field, entity, true));
37584 if (entity.isHighwayIntersection(context.graph())) {
37585 fields.push(UIField(context.presets().field('restrictions'), entity, true));
37588 context.presets().universal().forEach(function(field) {
37589 if (preset.fields.indexOf(field) < 0) {
37590 fields.push(UIField(field, entity));
37595 var shown = fields.filter(function(field) { return field.shown(); }),
37596 notShown = fields.filter(function(field) { return !field.shown(); });
37598 var $form = selection.selectAll('.preset-form')
37601 $form.enter().append('div')
37602 .attr('class', 'preset-form inspector-inner fillL3');
37604 var $fields = $form.selectAll('.form-field')
37605 .data(shown, fieldKey);
37609 var $enter = $fields.enter()
37611 .attr('class', function(field) {
37612 return 'form-field form-field-' + field.id;
37615 var $label = $enter.append('label')
37616 .attr('class', 'form-label')
37617 .attr('for', function(field) { return 'preset-input-' + field.id; })
37618 .text(function(field) { return field.label(); });
37620 var wrap = $label.append('div')
37621 .attr('class', 'form-label-button-wrap');
37623 wrap.append('button')
37624 .attr('class', 'remove-icon')
37625 .attr('tabindex', -1)
37626 .call(iD.svg.Icon('#operation-delete'));
37628 wrap.append('button')
37629 .attr('class', 'modified-icon')
37630 .attr('tabindex', -1)
37631 .call(iD.svg.Icon('#icon-undo'));
37635 $fields.select('.form-label-button-wrap .remove-icon')
37636 .on('click', remove);
37638 $fields.select('.modified-icon')
37639 .on('click', revert);
37643 .classed('modified', function(field) {
37644 return field.modified();
37646 .classed('present', function(field) {
37647 return field.present();
37649 .each(function(field) {
37650 var reference = iD.ui.TagReference(field.reference || {key: field.key}, context);
37652 if (state === 'hover') {
37653 reference.showing(false);
37658 .selectAll('input')
37659 .on('keydown', function() {
37660 // if user presses enter, and combobox is not active, accept edits..
37661 if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) {
37662 context.enter(iD.modes.Browse(context));
37665 .call(reference.body)
37666 .select('.form-label-button-wrap')
37667 .call(reference.button);
37669 field.input.tags(tags);
37675 notShown = notShown.map(function(field) {
37677 title: field.label(),
37678 value: field.label(),
37683 var $more = selection.selectAll('.more-fields')
37684 .data((notShown.length > 0) ? [0] : []);
37686 $more.enter().append('div')
37687 .attr('class', 'more-fields')
37689 .text(t('inspector.add_fields'));
37691 var $input = $more.selectAll('.value')
37694 $input.enter().append('input')
37695 .attr('class', 'value')
37696 .attr('type', 'text');
37699 .attr('placeholder', function() {
37700 var placeholder = [];
37701 for (var field in notShown) {
37702 placeholder.push(notShown[field].title);
37704 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
37706 .call(d3.combobox().data(notShown)
37708 .on('accept', show));
37716 function show(field) {
37717 field = field.field;
37719 content(selection);
37720 field.input.focus();
37723 function revert(field) {
37724 d3.event.stopPropagation();
37725 d3.event.preventDefault();
37726 event.change(field.revert());
37729 function remove(field) {
37730 d3.event.stopPropagation();
37731 d3.event.preventDefault();
37732 event.change(field.remove());
37736 presets.preset = function(_) {
37737 if (!arguments.length) return preset;
37738 if (preset && preset.id === _.id) return presets;
37744 presets.state = function(_) {
37745 if (!arguments.length) return state;
37750 presets.tags = function(_) {
37751 if (!arguments.length) return tags;
37753 // Don't reset fields here.
37757 presets.entityID = function(_) {
37758 if (!arguments.length) return id;
37759 if (id === _) return presets;
37765 return d3.rebind(presets, event, 'on');
37767 iD.ui.PresetList = function(context) {
37768 var event = d3.dispatch('choose'),
37773 function presetList(selection) {
37774 var geometry = context.geometry(id),
37775 presets = context.presets().matchGeometry(geometry);
37777 selection.html('');
37779 var messagewrap = selection.append('div')
37780 .attr('class', 'header fillL cf');
37782 var message = messagewrap.append('h3')
37783 .text(t('inspector.choose'));
37785 if (context.entity(id).isUsed(context.graph())) {
37786 messagewrap.append('button')
37787 .attr('class', 'preset-choose')
37788 .on('click', function() { event.choose(currentPreset); })
37792 messagewrap.append('button')
37793 .attr('class', 'close')
37794 .on('click', function() {
37795 context.enter(iD.modes.Browse(context));
37797 .call(iD.svg.Icon('#icon-close'));
37800 function keydown() {
37801 // hack to let delete shortcut work when search is autofocused
37802 if (search.property('value').length === 0 &&
37803 (d3.event.keyCode === d3.keybinding.keyCodes['⌫'] ||
37804 d3.event.keyCode === d3.keybinding.keyCodes['⌦'])) {
37805 d3.event.preventDefault();
37806 d3.event.stopPropagation();
37807 iD.operations.Delete([id], context)();
37808 } else if (search.property('value').length === 0 &&
37809 (d3.event.ctrlKey || d3.event.metaKey) &&
37810 d3.event.keyCode === d3.keybinding.keyCodes.z) {
37811 d3.event.preventDefault();
37812 d3.event.stopPropagation();
37814 } else if (!d3.event.ctrlKey && !d3.event.metaKey) {
37815 d3.select(this).on('keydown', null);
37819 function keypress() {
37821 var value = search.property('value');
37822 if (d3.event.keyCode === 13 && value.length) {
37823 list.selectAll('.preset-list-item:first-child').datum().choose();
37827 function inputevent() {
37828 var value = search.property('value');
37829 list.classed('filtered', value.length);
37830 if (value.length) {
37831 var results = presets.search(value, geometry);
37832 message.text(t('inspector.results', {
37833 n: results.collection.length,
37836 list.call(drawList, results);
37838 list.call(drawList, context.presets().defaults(geometry, 36));
37839 message.text(t('inspector.choose'));
37843 var searchWrap = selection.append('div')
37844 .attr('class', 'search-header');
37846 var search = searchWrap.append('input')
37847 .attr('class', 'preset-search-input')
37848 .attr('placeholder', t('inspector.search'))
37849 .attr('type', 'search')
37850 .on('keydown', keydown)
37851 .on('keypress', keypress)
37852 .on('input', inputevent);
37855 .call(iD.svg.Icon('#icon-search', 'pre-text'));
37858 search.node().focus();
37861 var listWrap = selection.append('div')
37862 .attr('class', 'inspector-body');
37864 var list = listWrap.append('div')
37865 .attr('class', 'preset-list fillL cf')
37866 .call(drawList, context.presets().defaults(geometry, 36));
37869 function drawList(list, presets) {
37870 var collection = presets.collection.map(function(preset) {
37871 return preset.members ? CategoryItem(preset) : PresetItem(preset);
37874 var items = list.selectAll('.preset-list-item')
37875 .data(collection, function(d) { return d.preset.id; });
37877 items.enter().append('div')
37878 .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
37879 .classed('current', function(item) { return item.preset === currentPreset; })
37880 .each(function(item) {
37881 d3.select(this).call(item);
37883 .style('opacity', 0)
37885 .style('opacity', 1);
37893 function CategoryItem(preset) {
37894 var box, sublist, shown = false;
37896 function item(selection) {
37897 var wrap = selection.append('div')
37898 .attr('class', 'preset-list-button-wrap category col12');
37900 wrap.append('button')
37901 .attr('class', 'preset-list-button')
37902 .classed('expanded', false)
37903 .call(iD.ui.PresetIcon()
37904 .geometry(context.geometry(id))
37906 .on('click', function() {
37907 var isExpanded = d3.select(this).classed('expanded');
37908 var triangle = isExpanded ? '▶ ' : '▼ ';
37909 d3.select(this).classed('expanded', !isExpanded);
37910 d3.select(this).selectAll('.label').text(triangle + preset.name());
37914 .attr('class', 'label')
37916 return '▶ ' + preset.name();
37919 box = selection.append('div')
37920 .attr('class', 'subgrid col12')
37921 .style('max-height', '0px')
37922 .style('opacity', 0);
37925 .attr('class', 'arrow');
37927 sublist = box.append('div')
37928 .attr('class', 'preset-list fillL3 cf fl');
37931 item.choose = function() {
37932 if (!box || !sublist) return;
37938 .style('opacity', '0')
37939 .style('max-height', '0px')
37940 .style('padding-bottom', '0px');
37943 sublist.call(drawList, preset.members);
37946 .style('opacity', '1')
37947 .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
37948 .style('padding-bottom', '20px');
37952 item.preset = preset;
37957 function PresetItem(preset) {
37958 function item(selection) {
37959 var wrap = selection.append('div')
37960 .attr('class', 'preset-list-button-wrap col12');
37962 wrap.append('button')
37963 .attr('class', 'preset-list-button')
37964 .call(iD.ui.PresetIcon()
37965 .geometry(context.geometry(id))
37967 .on('click', item.choose)
37969 .attr('class', 'label')
37970 .text(preset.name());
37972 wrap.call(item.reference.button);
37973 selection.call(item.reference.body);
37976 item.choose = function() {
37977 context.presets().choose(preset);
37980 iD.actions.ChangePreset(id, currentPreset, preset),
37981 t('operations.change_tags.annotation'));
37983 event.choose(preset);
37986 item.help = function() {
37987 d3.event.stopPropagation();
37988 item.reference.toggle();
37991 item.preset = preset;
37992 item.reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context);
37997 presetList.autofocus = function(_) {
37998 if (!arguments.length) return autofocus;
38003 presetList.entityID = function(_) {
38004 if (!arguments.length) return id;
38006 presetList.preset(context.presets().match(context.entity(id), context.graph()));
38010 presetList.preset = function(_) {
38011 if (!arguments.length) return currentPreset;
38016 return d3.rebind(presetList, event, 'on');
38018 iD.ui.RadialMenu = function(context, operations) {
38023 var radialMenu = function(selection) {
38024 if (!operations.length)
38027 selection.node().parentNode.focus();
38029 function click(operation) {
38030 d3.event.stopPropagation();
38031 if (operation.disabled())
38034 radialMenu.close();
38037 menu = selection.append('g')
38038 .attr('class', 'radial-menu')
38039 .attr('transform', 'translate(' + center + ')')
38040 .attr('opacity', 0);
38043 .attr('opacity', 1);
38048 a1 = a0 + (operations.length - 1) * a;
38050 menu.append('path')
38051 .attr('class', 'radial-menu-background')
38052 .attr('d', 'M' + r * Math.sin(a0) + ',' +
38054 ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
38055 (r * Math.sin(a1) + 1e-3) + ',' +
38056 (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
38057 .attr('stroke-width', 50)
38058 .attr('stroke-linecap', 'round');
38060 var button = menu.selectAll()
38064 .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
38065 .classed('disabled', function(d) { return d.disabled(); })
38066 .attr('transform', function(d, i) {
38067 return 'translate(' + iD.geo.roundCoords([
38068 r * Math.sin(a0 + i * a),
38069 r * Math.cos(a0 + i * a)]).join(',') + ')';
38072 button.append('circle')
38074 .on('click', click)
38075 .on('mousedown', mousedown)
38076 .on('mouseover', mouseover)
38077 .on('mouseout', mouseout);
38079 button.append('use')
38080 .attr('transform', 'translate(-10,-10)')
38081 .attr('width', '20')
38082 .attr('height', '20')
38083 .attr('xlink:href', function(d) { return '#operation-' + d.id; });
38085 tooltip = d3.select(document.body)
38087 .attr('class', 'tooltip-inner radial-menu-tooltip');
38089 function mousedown() {
38090 d3.event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
38093 function mouseover(d, i) {
38094 var rect = context.surfaceRect(),
38095 angle = a0 + i * a,
38096 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
38097 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
38098 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
38099 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
38102 .style('top', null)
38103 .style('left', null)
38104 .style('bottom', null)
38105 .style('right', null)
38106 .style('display', 'block')
38107 .html(iD.ui.tooltipHtml(d.tooltip(), d.keys[0]));
38111 .style('right', right)
38112 .style('top', top);
38113 } else if (i >= 4) {
38115 .style('left', left)
38116 .style('bottom', bottom);
38119 .style('left', left)
38120 .style('top', top);
38124 function mouseout() {
38125 tooltip.style('display', 'none');
38129 radialMenu.close = function() {
38132 .style('pointer-events', 'none')
38134 .attr('opacity', 0)
38143 radialMenu.center = function(_) {
38144 if (!arguments.length) return center;
38151 iD.ui.RawMemberEditor = function(context) {
38154 function selectMember(d) {
38155 d3.event.preventDefault();
38156 context.enter(iD.modes.Select(context, [d.id]));
38159 function changeRole(d) {
38160 var role = d3.select(this).property('value');
38161 var member = {id: d.id, type: d.type, role: role};
38163 iD.actions.ChangeMember(d.relation.id, member, d.index),
38164 t('operations.change_role.annotation'));
38167 function deleteMember(d) {
38169 iD.actions.DeleteMember(d.relation.id, d.index),
38170 t('operations.delete_member.annotation'));
38172 if (!context.hasEntity(d.relation.id)) {
38173 context.enter(iD.modes.Browse(context));
38177 function rawMemberEditor(selection) {
38178 var entity = context.entity(id),
38181 entity.members.forEach(function(member, index) {
38188 member: context.hasEntity(member.id)
38192 selection.call(iD.ui.Disclosure()
38193 .title(t('inspector.all_members') + ' (' + memberships.length + ')')
38195 .on('toggled', toggled)
38196 .content(content));
38198 function toggled(expanded) {
38200 selection.node().parentNode.scrollTop += 200;
38204 function content($wrap) {
38205 var $list = $wrap.selectAll('.member-list')
38208 $list.enter().append('ul')
38209 .attr('class', 'member-list');
38211 var $items = $list.selectAll('li')
38212 .data(memberships, function(d) {
38213 return iD.Entity.key(d.relation) + ',' + d.index + ',' +
38214 (d.member ? iD.Entity.key(d.member) : 'incomplete');
38217 var $enter = $items.enter().append('li')
38218 .attr('class', 'member-row form-field')
38219 .classed('member-incomplete', function(d) { return !d.member; });
38221 $enter.each(function(d) {
38223 var $label = d3.select(this).append('label')
38224 .attr('class', 'form-label')
38227 .on('click', selectMember);
38229 $label.append('span')
38230 .attr('class', 'member-entity-type')
38231 .text(function(d) { return context.presets().match(d.member, context.graph()).name(); });
38233 $label.append('span')
38234 .attr('class', 'member-entity-name')
38235 .text(function(d) { return iD.util.displayName(d.member); });
38238 d3.select(this).append('label')
38239 .attr('class', 'form-label')
38240 .text(t('inspector.incomplete'));
38244 $enter.append('input')
38245 .attr('class', 'member-role')
38246 .property('type', 'text')
38247 .attr('maxlength', 255)
38248 .attr('placeholder', t('inspector.role'))
38249 .property('value', function(d) { return d.role; })
38250 .on('change', changeRole);
38252 $enter.append('button')
38253 .attr('tabindex', -1)
38254 .attr('class', 'remove button-input-action member-delete minor')
38255 .on('click', deleteMember)
38256 .call(iD.svg.Icon('#operation-delete'));
38263 rawMemberEditor.entityID = function(_) {
38264 if (!arguments.length) return id;
38266 return rawMemberEditor;
38269 return rawMemberEditor;
38271 iD.ui.RawMembershipEditor = function(context) {
38274 function selectRelation(d) {
38275 d3.event.preventDefault();
38276 context.enter(iD.modes.Select(context, [d.relation.id]));
38279 function changeRole(d) {
38280 var role = d3.select(this).property('value');
38282 iD.actions.ChangeMember(d.relation.id, _.extend({}, d.member, {role: role}), d.index),
38283 t('operations.change_role.annotation'));
38286 function addMembership(d, role) {
38291 iD.actions.AddMember(d.relation.id, {id: id, type: context.entity(id).type, role: role}),
38292 t('operations.add_member.annotation'));
38295 var relation = iD.Relation();
38298 iD.actions.AddEntity(relation),
38299 iD.actions.AddMember(relation.id, {id: id, type: context.entity(id).type, role: role}),
38300 t('operations.add.annotation.relation'));
38302 context.enter(iD.modes.Select(context, [relation.id]));
38306 function deleteMembership(d) {
38308 iD.actions.DeleteMember(d.relation.id, d.index),
38309 t('operations.delete_member.annotation'));
38312 function relations(q) {
38313 var newRelation = {
38315 value: t('inspector.new_relation')
38318 graph = context.graph();
38320 context.intersects(context.extent()).forEach(function(entity) {
38321 if (entity.type !== 'relation' || entity.id === id)
38324 var presetName = context.presets().match(entity, graph).name(),
38325 entityName = iD.util.displayName(entity) || '';
38327 var value = presetName + ' ' + entityName;
38328 if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
38337 result.sort(function(a, b) {
38338 return iD.Relation.creationOrder(a.relation, b.relation);
38341 // Dedupe identical names by appending relation id - see #2891
38342 var dupeGroups = _(result)
38344 .filter(function(v) { return v.length > 1; })
38347 dupeGroups.forEach(function(group) {
38348 group.forEach(function(obj) {
38349 obj.value += ' ' + obj.relation.id;
38353 result.unshift(newRelation);
38358 function rawMembershipEditor(selection) {
38359 var entity = context.entity(id),
38362 context.graph().parentRelations(entity).forEach(function(relation) {
38363 relation.members.forEach(function(member, index) {
38364 if (member.id === entity.id) {
38365 memberships.push({relation: relation, member: member, index: index});
38370 selection.call(iD.ui.Disclosure()
38371 .title(t('inspector.all_relations') + ' (' + memberships.length + ')')
38373 .on('toggled', toggled)
38374 .content(content));
38376 function toggled(expanded) {
38378 selection.node().parentNode.scrollTop += 200;
38382 function content($wrap) {
38383 var $list = $wrap.selectAll('.member-list')
38386 $list.enter().append('ul')
38387 .attr('class', 'member-list');
38389 var $items = $list.selectAll('li.member-row-normal')
38390 .data(memberships, function(d) { return iD.Entity.key(d.relation) + ',' + d.index; });
38392 var $enter = $items.enter().append('li')
38393 .attr('class', 'member-row member-row-normal form-field');
38395 var $label = $enter.append('label')
38396 .attr('class', 'form-label')
38399 .on('click', selectRelation);
38401 $label.append('span')
38402 .attr('class', 'member-entity-type')
38403 .text(function(d) { return context.presets().match(d.relation, context.graph()).name(); });
38405 $label.append('span')
38406 .attr('class', 'member-entity-name')
38407 .text(function(d) { return iD.util.displayName(d.relation); });
38409 $enter.append('input')
38410 .attr('class', 'member-role')
38411 .property('type', 'text')
38412 .attr('maxlength', 255)
38413 .attr('placeholder', t('inspector.role'))
38414 .property('value', function(d) { return d.member.role; })
38415 .on('change', changeRole);
38417 $enter.append('button')
38418 .attr('tabindex', -1)
38419 .attr('class', 'remove button-input-action member-delete minor')
38420 .on('click', deleteMembership)
38421 .call(iD.svg.Icon('#operation-delete'));
38427 var $new = $list.selectAll('.member-row-new')
38430 $enter = $new.enter().append('li')
38431 .attr('class', 'member-row member-row-new form-field');
38433 $enter.append('input')
38434 .attr('type', 'text')
38435 .attr('class', 'member-entity-input')
38436 .call(d3.combobox()
38438 .fetcher(function(value, callback) {
38439 callback(relations(value));
38441 .on('accept', function(d) {
38442 addMembership(d, $new.select('.member-role').property('value'));
38445 $enter.append('input')
38446 .attr('class', 'member-role')
38447 .property('type', 'text')
38448 .attr('maxlength', 255)
38449 .attr('placeholder', t('inspector.role'))
38450 .on('change', changeRole);
38452 $enter.append('button')
38453 .attr('tabindex', -1)
38454 .attr('class', 'remove button-input-action member-delete minor')
38455 .on('click', deleteMembership)
38456 .call(iD.svg.Icon('#operation-delete'));
38459 $list.selectAll('.member-row-new')
38463 var $add = $wrap.selectAll('.add-relation')
38468 .attr('class', 'add-relation')
38469 .call(iD.svg.Icon('#icon-plus', 'light'));
38471 $wrap.selectAll('.add-relation')
38472 .on('click', function() {
38475 $list.selectAll('.member-entity-input').node().focus();
38480 rawMembershipEditor.entityID = function(_) {
38481 if (!arguments.length) return id;
38483 return rawMembershipEditor;
38486 return rawMembershipEditor;
38488 iD.ui.RawTagEditor = function(context) {
38489 var event = d3.dispatch('change'),
38496 function rawTagEditor(selection) {
38497 var count = Object.keys(tags).filter(function(d) { return d; }).length;
38499 selection.call(iD.ui.Disclosure()
38500 .title(t('inspector.all_tags') + ' (' + count + ')')
38501 .expanded(context.storage('raw_tag_editor.expanded') === 'true' || preset.isFallback())
38502 .on('toggled', toggled)
38503 .content(content));
38505 function toggled(expanded) {
38506 context.storage('raw_tag_editor.expanded', expanded);
38508 selection.node().parentNode.scrollTop += 200;
38513 function content($wrap) {
38514 var entries = d3.entries(tags);
38516 if (!entries.length || showBlank) {
38518 entries.push({key: '', value: ''});
38521 var $list = $wrap.selectAll('.tag-list')
38524 $list.enter().append('ul')
38525 .attr('class', 'tag-list');
38527 var $newTag = $wrap.selectAll('.add-tag')
38532 .attr('class', 'add-tag')
38533 .call(iD.svg.Icon('#icon-plus', 'light'));
38535 $newTag.on('click', addTag);
38537 var $items = $list.selectAll('li')
38538 .data(entries, function(d) { return d.key; });
38542 var $enter = $items.enter().append('li')
38543 .attr('class', 'tag-row cf');
38545 $enter.append('div')
38546 .attr('class', 'key-wrap')
38548 .property('type', 'text')
38549 .attr('class', 'key')
38550 .attr('maxlength', 255);
38552 $enter.append('div')
38553 .attr('class', 'input-wrap-position')
38555 .property('type', 'text')
38556 .attr('class', 'value')
38557 .attr('maxlength', 255);
38559 $enter.append('button')
38560 .attr('tabindex', -1)
38561 .attr('class', 'remove minor')
38562 .call(iD.svg.Icon('#operation-delete'));
38564 if (context.taginfo()) {
38565 $enter.each(bindTypeahead);
38572 $items.each(function(tag) {
38573 var isRelation = (context.entity(id).type === 'relation'),
38575 if (isRelation && tag.key === 'type')
38576 reference = iD.ui.TagReference({rtype: tag.value}, context);
38578 reference = iD.ui.TagReference({key: tag.key, value: tag.value}, context);
38580 if (state === 'hover') {
38581 reference.showing(false);
38585 .call(reference.button)
38586 .call(reference.body);
38589 $items.select('input.key')
38590 .attr('title', function(d) { return d.key; })
38591 .value(function(d) { return d.key; })
38592 .on('blur', keyChange)
38593 .on('change', keyChange);
38595 $items.select('input.value')
38596 .attr('title', function(d) { return d.value; })
38597 .value(function(d) { return d.value; })
38598 .on('blur', valueChange)
38599 .on('change', valueChange)
38600 .on('keydown.push-more', pushMore);
38602 $items.select('button.remove')
38603 .on('click', removeTag);
38609 function pushMore() {
38610 if (d3.event.keyCode === 9 && !d3.event.shiftKey &&
38611 $list.selectAll('li:last-child input.value').node() === this) {
38616 function bindTypeahead() {
38617 var row = d3.select(this),
38618 key = row.selectAll('input.key'),
38619 value = row.selectAll('input.value');
38621 function sort(value, data) {
38622 var sameletter = [],
38624 for (var i = 0; i < data.length; i++) {
38625 if (data[i].value.substring(0, value.length) === value) {
38626 sameletter.push(data[i]);
38628 other.push(data[i]);
38631 return sameletter.concat(other);
38634 key.call(d3.combobox()
38635 .fetcher(function(value, callback) {
38636 context.taginfo().keys({
38638 geometry: context.geometry(id),
38640 }, function(err, data) {
38641 if (!err) callback(sort(value, data));
38645 value.call(d3.combobox()
38646 .fetcher(function(value, callback) {
38647 context.taginfo().values({
38650 geometry: context.geometry(id),
38652 }, function(err, data) {
38653 if (!err) callback(sort(value, data));
38658 function unbind() {
38659 var row = d3.select(this);
38661 row.selectAll('input.key')
38662 .call(d3.combobox.off);
38664 row.selectAll('input.value')
38665 .call(d3.combobox.off);
38668 function keyChange(d) {
38670 kNew = this.value.trim(),
38673 if (kNew && kNew !== kOld) {
38674 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
38676 suffix = +(match[2] || 1);
38677 while (tags[kNew]) { // rename key if already in use
38678 kNew = base + '_' + suffix++;
38681 tag[kOld] = undefined;
38682 tag[kNew] = d.value;
38683 d.key = kNew; // Maintain DOM identity through the subsequent update.
38688 function valueChange(d) {
38690 tag[d.key] = this.value;
38694 function removeTag(d) {
38696 tag[d.key] = undefined;
38698 d3.select(this.parentNode).remove();
38701 function addTag() {
38702 // Wrapped in a setTimeout in case it's being called from a blur
38703 // handler. Without the setTimeout, the call to `content` would
38704 // wipe out the pending value change.
38705 setTimeout(function() {
38708 $list.selectAll('li:last-child input.key').node().focus();
38713 rawTagEditor.state = function(_) {
38714 if (!arguments.length) return state;
38716 return rawTagEditor;
38719 rawTagEditor.preset = function(_) {
38720 if (!arguments.length) return preset;
38722 return rawTagEditor;
38725 rawTagEditor.tags = function(_) {
38726 if (!arguments.length) return tags;
38728 return rawTagEditor;
38731 rawTagEditor.entityID = function(_) {
38732 if (!arguments.length) return id;
38734 return rawTagEditor;
38737 return d3.rebind(rawTagEditor, event, 'on');
38739 iD.ui.Restore = function(context) {
38740 return function(selection) {
38741 if (!context.history().lock() || !context.history().restorableChanges())
38744 var modal = iD.ui.modal(selection, true);
38746 modal.select('.modal')
38747 .attr('class', 'modal fillL col6');
38749 var introModal = modal.select('.content');
38751 introModal.attr('class','cf');
38753 introModal.append('div')
38754 .attr('class', 'modal-section')
38756 .text(t('restore.heading'));
38758 introModal.append('div')
38759 .attr('class','modal-section')
38761 .text(t('restore.description'));
38763 var buttonWrap = introModal.append('div')
38764 .attr('class', 'modal-actions cf');
38766 var restore = buttonWrap.append('button')
38767 .attr('class', 'restore col6')
38768 .text(t('restore.restore'))
38769 .on('click', function() {
38770 context.history().restore();
38774 buttonWrap.append('button')
38775 .attr('class', 'reset col6')
38776 .text(t('restore.reset'))
38777 .on('click', function() {
38778 context.history().clearSaved();
38782 restore.node().focus();
38785 iD.ui.Save = function(context) {
38786 var history = context.history(),
38787 key = iD.ui.cmd('⌘S');
38790 function saving() {
38791 return context.mode().id === 'save';
38795 d3.event.preventDefault();
38796 if (!context.inIntro() && !saving() && history.hasChanges()) {
38797 context.enter(iD.modes.Save(context));
38801 function getBackground(numChanges) {
38803 if (numChanges === 0) {
38805 } else if (numChanges <= 50) {
38806 step = numChanges / 50;
38807 return d3.interpolateRgb('#fff', '#ff8')(step); // white -> yellow
38809 step = Math.min((numChanges - 50) / 50, 1.0);
38810 return d3.interpolateRgb('#ff8', '#f88')(step); // yellow -> red
38814 return function(selection) {
38815 var tooltip = bootstrap.tooltip()
38816 .placement('bottom')
38818 .title(iD.ui.tooltipHtml(t('save.no_changes'), key));
38820 var button = selection.append('button')
38821 .attr('class', 'save col12 disabled')
38822 .attr('tabindex', -1)
38826 button.append('span')
38827 .attr('class', 'label')
38828 .text(t('save.title'));
38830 button.append('span')
38831 .attr('class', 'count')
38834 var keybinding = d3.keybinding('undo-redo')
38835 .on(key, save, true);
38837 d3.select(document)
38840 var numChanges = 0;
38842 context.history().on('change.save', function() {
38843 var _ = history.difference().summary().length;
38844 if (_ === numChanges)
38848 tooltip.title(iD.ui.tooltipHtml(t(numChanges > 0 ?
38849 'save.help' : 'save.no_changes'), key));
38851 var background = getBackground(numChanges);
38854 .classed('disabled', numChanges === 0)
38855 .classed('has-count', numChanges > 0)
38856 .style('background', background);
38858 button.select('span.count')
38860 .style('background', background)
38861 .style('border-color', background);
38864 context.on('enter.save', function() {
38865 button.property('disabled', saving());
38866 if (saving()) button.call(tooltip.hide);
38870 iD.ui.Scale = function(context) {
38871 var projection = context.projection,
38872 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
38876 function scaleDefs(loc1, loc2) {
38877 var lat = (loc2[1] + loc1[1]) / 2,
38878 conversion = (imperial ? 3.28084 : 1),
38879 dist = iD.geo.lonToMeters(loc2[0] - loc1[0], lat) * conversion,
38880 scale = { dist: 0, px: 0, text: '' },
38881 buckets, i, val, dLon;
38884 buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
38886 buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
38889 // determine a user-friendly endpoint for the scale
38890 for (i = 0; i < buckets.length; i++) {
38893 scale.dist = Math.floor(dist / val) * val;
38898 dLon = iD.geo.metersToLon(scale.dist / conversion, lat);
38899 scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
38902 if (scale.dist >= 5280) {
38903 scale.dist /= 5280;
38904 scale.text = String(scale.dist) + ' mi';
38906 scale.text = String(scale.dist) + ' ft';
38909 if (scale.dist >= 1000) {
38910 scale.dist /= 1000;
38911 scale.text = String(scale.dist) + ' km';
38913 scale.text = String(scale.dist) + ' m';
38920 function update(selection) {
38921 // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
38922 var dims = context.map().dimensions(),
38923 loc1 = projection.invert([0, dims[1]]),
38924 loc2 = projection.invert([maxLength, dims[1]]),
38925 scale = scaleDefs(loc1, loc2);
38927 selection.select('#scalepath')
38928 .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
38930 selection.select('#scaletext')
38931 .attr('x', scale.px + 8)
38932 .attr('y', tickHeight)
38937 return function(selection) {
38938 function switchUnits() {
38939 imperial = !imperial;
38940 selection.call(update);
38943 var g = selection.append('svg')
38944 .attr('id', 'scale')
38945 .on('click', switchUnits)
38947 .attr('transform', 'translate(10,11)');
38949 g.append('path').attr('id', 'scalepath');
38950 g.append('text').attr('id', 'scaletext');
38952 selection.call(update);
38954 context.map().on('move.scale', function() {
38959 iD.ui.SelectionList = function(context, selectedIDs) {
38961 function selectEntity(entity) {
38962 context.enter(iD.modes.Select(context, [entity.id]).suppressMenu(true));
38966 function selectionList(selection) {
38967 selection.classed('selection-list-pane', true);
38969 var header = selection.append('div')
38970 .attr('class', 'header fillL cf');
38972 header.append('h3')
38973 .text(t('inspector.multiselect'));
38975 var listWrap = selection.append('div')
38976 .attr('class', 'inspector-body');
38978 var list = listWrap.append('div')
38979 .attr('class', 'feature-list cf');
38981 context.history().on('change.selection-list', drawList);
38984 function drawList() {
38985 var entities = selectedIDs
38986 .map(function(id) { return context.hasEntity(id); })
38987 .filter(function(entity) { return entity; });
38989 var items = list.selectAll('.feature-list-item')
38990 .data(entities, iD.Entity.key);
38992 var enter = items.enter().append('button')
38993 .attr('class', 'feature-list-item')
38994 .on('click', selectEntity);
38997 var label = enter.append('div')
38998 .attr('class', 'label')
38999 .call(iD.svg.Icon('', 'pre-text'));
39001 label.append('span')
39002 .attr('class', 'entity-type');
39004 label.append('span')
39005 .attr('class', 'entity-name');
39008 items.selectAll('use')
39009 .attr('href', function() {
39010 var entity = this.parentNode.parentNode.__data__;
39011 return '#icon-' + context.geometry(entity.id);
39014 items.selectAll('.entity-type')
39015 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
39017 items.selectAll('.entity-name')
39018 .text(function(entity) { return iD.util.displayName(entity); });
39026 return selectionList;
39029 iD.ui.Sidebar = function(context) {
39030 var inspector = iD.ui.Inspector(context),
39033 function sidebar(selection) {
39034 var featureListWrap = selection.append('div')
39035 .attr('class', 'feature-list-pane')
39036 .call(iD.ui.FeatureList(context));
39038 selection.call(iD.ui.Notice(context));
39040 var inspectorWrap = selection.append('div')
39041 .attr('class', 'inspector-hidden inspector-wrap fr');
39043 function hover(id) {
39044 if (!current && context.hasEntity(id)) {
39045 featureListWrap.classed('inspector-hidden', true);
39046 inspectorWrap.classed('inspector-hidden', false)
39047 .classed('inspector-hover', true);
39049 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
39054 inspectorWrap.call(inspector);
39056 } else if (!current) {
39057 featureListWrap.classed('inspector-hidden', false);
39058 inspectorWrap.classed('inspector-hidden', true);
39059 inspector.state('hide');
39063 sidebar.hover = _.throttle(hover, 200);
39065 sidebar.select = function(id, newFeature) {
39066 if (!current && id) {
39067 featureListWrap.classed('inspector-hidden', true);
39068 inspectorWrap.classed('inspector-hidden', false)
39069 .classed('inspector-hover', false);
39071 if (inspector.entityID() !== id || inspector.state() !== 'select') {
39075 .newFeature(newFeature);
39077 inspectorWrap.call(inspector);
39079 } else if (!current) {
39080 featureListWrap.classed('inspector-hidden', false);
39081 inspectorWrap.classed('inspector-hidden', true);
39082 inspector.state('hide');
39086 sidebar.show = function(component) {
39087 featureListWrap.classed('inspector-hidden', true);
39088 inspectorWrap.classed('inspector-hidden', true);
39089 if (current) current.remove();
39090 current = selection.append('div')
39091 .attr('class', 'sidebar-component')
39095 sidebar.hide = function() {
39096 featureListWrap.classed('inspector-hidden', false);
39097 inspectorWrap.classed('inspector-hidden', true);
39098 if (current) current.remove();
39103 sidebar.hover = function() {};
39104 sidebar.hover.cancel = function() {};
39105 sidebar.select = function() {};
39106 sidebar.show = function() {};
39107 sidebar.hide = function() {};
39111 iD.ui.SourceSwitch = function(context) {
39115 d3.event.preventDefault();
39117 if (context.history().hasChanges() &&
39118 !window.confirm(t('source_switch.lose_changes'))) return;
39120 var live = d3.select(this)
39123 context.connection()
39124 .switch(live ? keys[1] : keys[0]);
39126 context.enter(iD.modes.Browse(context));
39130 .text(live ? t('source_switch.dev') : t('source_switch.live'))
39131 .classed('live', !live);
39134 var sourceSwitch = function(selection) {
39135 selection.append('a')
39137 .text(t('source_switch.live'))
39138 .classed('live', true)
39139 .attr('tabindex', -1)
39140 .on('click', click);
39143 sourceSwitch.keys = function(_) {
39144 if (!arguments.length) return keys;
39146 return sourceSwitch;
39149 return sourceSwitch;
39151 iD.ui.Spinner = function(context) {
39152 var connection = context.connection();
39154 return function(selection) {
39155 var img = selection.append('img')
39156 .attr('src', context.imagePath('loader-black.gif'))
39157 .style('opacity', 0);
39159 connection.on('loading.spinner', function() {
39161 .style('opacity', 1);
39164 connection.on('loaded.spinner', function() {
39166 .style('opacity', 0);
39170 iD.ui.Splash = function(context) {
39171 return function(selection) {
39172 if (context.storage('sawSplash'))
39175 context.storage('sawSplash', true);
39177 var modal = iD.ui.modal(selection);
39179 modal.select('.modal')
39180 .attr('class', 'modal-splash modal col6');
39182 var introModal = modal.select('.content')
39184 .attr('class', 'fillL');
39186 introModal.append('div')
39187 .attr('class','modal-section cf')
39188 .append('h3').text(t('splash.welcome'));
39190 introModal.append('div')
39191 .attr('class','modal-section')
39193 .html(t('splash.text', {
39194 version: iD.version,
39195 website: '<a href="http://ideditor.com/">ideditor.com</a>',
39196 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
39199 var buttons = introModal.append('div').attr('class', 'modal-actions cf');
39201 buttons.append('button')
39202 .attr('class', 'col6 walkthrough')
39203 .text(t('splash.walkthrough'))
39204 .on('click', function() {
39205 d3.select(document.body).call(iD.ui.intro(context));
39209 buttons.append('button')
39210 .attr('class', 'col6 start')
39211 .text(t('splash.start'))
39212 .on('click', modal.close);
39214 modal.select('button.close').attr('class','hide');
39218 iD.ui.Status = function(context) {
39219 var connection = context.connection(),
39222 return function(selection) {
39224 function update() {
39226 connection.status(function(err, apiStatus) {
39228 selection.html('');
39230 if (err && errCount++ < 2) return;
39233 selection.text(t('status.error'));
39235 } else if (apiStatus === 'readonly') {
39236 selection.text(t('status.readonly'));
39238 } else if (apiStatus === 'offline') {
39239 selection.text(t('status.offline'));
39242 selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
39243 if (!err) errCount = 0;
39248 connection.on('auth', function() { update(selection); });
39249 window.setInterval(update, 90000);
39253 iD.ui.Success = function(context) {
39254 var dispatch = d3.dispatch('cancel'),
39257 function success(selection) {
39258 var message = (changeset.comment || t('success.edited_osm')).substring(0, 130) +
39259 ' ' + context.connection().changesetURL(changeset.id);
39261 var header = selection.append('div')
39262 .attr('class', 'header fillL');
39264 header.append('button')
39265 .attr('class', 'fr')
39266 .on('click', function() { dispatch.cancel(); })
39267 .call(iD.svg.Icon('#icon-close'));
39269 header.append('h3')
39270 .text(t('success.just_edited'));
39272 var body = selection.append('div')
39273 .attr('class', 'body save-success fillL');
39276 .html(t('success.help_html'));
39279 .attr('class', 'details')
39280 .attr('target', '_blank')
39281 .attr('tabindex', -1)
39282 .call(iD.svg.Icon('#icon-out-link', 'inline'))
39283 .attr('href', t('success.help_link_url'))
39285 .text(t('success.help_link_text'));
39287 var changesetURL = context.connection().changesetURL(changeset.id);
39290 .attr('class', 'button col12 osm')
39291 .attr('target', '_blank')
39292 .attr('href', changesetURL)
39293 .text(t('success.view_on_osm'));
39296 facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
39297 twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
39298 google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
39301 body.selectAll('.button.social')
39302 .data(d3.entries(sharing))
39305 .attr('class', 'button social col4')
39306 .attr('target', '_blank')
39307 .attr('href', function(d) { return d.value; })
39308 .call(bootstrap.tooltip()
39309 .title(function(d) { return t('success.' + d.key); })
39310 .placement('bottom'))
39311 .each(function(d) { d3.select(this).call(iD.svg.Icon('#logo-' + d.key, 'social')); });
39314 success.changeset = function(_) {
39315 if (!arguments.length) return changeset;
39320 return d3.rebind(success, dispatch, 'on');
39322 iD.ui.TagReference = function(tag, context) {
39323 var tagReference = {},
39329 function findLocal(data) {
39330 var locale = iD.detect().locale.toLowerCase(),
39333 localized = _.find(data, function(d) {
39334 return d.lang.toLowerCase() === locale;
39336 if (localized) return localized;
39338 // try the non-regional version of a language, like
39339 // 'en' if the language is 'en-US'
39340 if (locale.indexOf('-') !== -1) {
39341 var first = locale.split('-')[0];
39342 localized = _.find(data, function(d) {
39343 return d.lang.toLowerCase() === first;
39345 if (localized) return localized;
39348 // finally fall back to english
39349 return _.find(data, function(d) {
39350 return d.lang.toLowerCase() === 'en';
39354 function load(param) {
39355 button.classed('tag-reference-loading', true);
39357 context.taginfo().docs(param, function show(err, data) {
39359 if (!err && data) {
39360 docs = findLocal(data);
39365 if (!docs || !docs.description) {
39366 if (param.hasOwnProperty('value')) {
39367 load(_.omit(param, 'value')); // retry with key only
39369 body.append('p').text(t('inspector.no_documentation_key'));
39375 if (docs.image && docs.image.thumb_url_prefix) {
39378 .attr('class', 'wiki-image')
39379 .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
39380 .on('load', function() { done(); })
39381 .on('error', function() { d3.select(this).remove(); done(); });
39388 .text(docs.description);
39392 .attr('target', '_blank')
39393 .attr('tabindex', -1)
39394 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
39395 .call(iD.svg.Icon('#icon-out-link', 'inline'))
39397 .text(t('inspector.reference'));
39404 button.classed('tag-reference-loading', false);
39408 .style('max-height', '200px')
39409 .style('opacity', '1');
39414 function hide(selection) {
39415 selection = selection || body.transition().duration(200);
39418 .style('max-height', '0px')
39419 .style('opacity', '0');
39424 tagReference.button = function(selection) {
39425 button = selection.selectAll('.tag-reference-button')
39430 .attr('class', 'tag-reference-button')
39431 .attr('tabindex', -1)
39432 .call(iD.svg.Icon('#icon-inspect'));
39434 button.on('click', function () {
39435 d3.event.stopPropagation();
39436 d3.event.preventDefault();
39439 } else if (loaded) {
39442 if (context.taginfo()) {
39449 tagReference.body = function(selection) {
39450 body = selection.selectAll('.tag-reference-body')
39453 body.enter().append('div')
39454 .attr('class', 'tag-reference-body cf')
39455 .style('max-height', '0')
39456 .style('opacity', '0');
39458 if (showing === false) {
39463 tagReference.showing = function(_) {
39464 if (!arguments.length) return showing;
39466 return tagReference;
39469 return tagReference;
39471 // toggles the visibility of ui elements, using a combination of the
39472 // hide class, which sets display=none, and a d3 transition for opacity.
39473 // this will cause blinking when called repeatedly, so check that the
39474 // value actually changes between calls.
39475 iD.ui.Toggle = function(show, callback) {
39476 return function(selection) {
39478 .style('opacity', show ? 0 : 1)
39479 .classed('hide', false)
39481 .style('opacity', show ? 1 : 0)
39482 .each('end', function() {
39484 .classed('hide', !show)
39485 .style('opacity', null);
39486 if (callback) callback.apply(this);
39490 iD.ui.UndoRedo = function(context) {
39493 cmd: iD.ui.cmd('⌘Z'),
39494 action: function() { if (!(context.inIntro() || saving())) context.undo(); },
39495 annotation: function() { return context.history().undoAnnotation(); }
39498 cmd: iD.ui.cmd('⌘⇧Z'),
39499 action: function() {if (!(context.inIntro() || saving())) context.redo(); },
39500 annotation: function() { return context.history().redoAnnotation(); }
39503 function saving() {
39504 return context.mode().id === 'save';
39507 return function(selection) {
39508 var tooltip = bootstrap.tooltip()
39509 .placement('bottom')
39511 .title(function (d) {
39512 return iD.ui.tooltipHtml(d.annotation() ?
39513 t(d.id + '.tooltip', {action: d.annotation()}) :
39514 t(d.id + '.nothing'), d.cmd);
39517 var buttons = selection.selectAll('button')
39519 .enter().append('button')
39520 .attr('class', 'col6 disabled')
39521 .on('click', function(d) { return d.action(); })
39524 buttons.each(function(d) {
39526 .call(iD.svg.Icon('#icon-' + d.id));
39529 var keybinding = d3.keybinding('undo')
39530 .on(commands[0].cmd, function() { d3.event.preventDefault(); commands[0].action(); })
39531 .on(commands[1].cmd, function() { d3.event.preventDefault(); commands[1].action(); });
39533 d3.select(document)
39537 .on('change.undo_redo', update);
39540 .on('enter.undo_redo', update);
39542 function update() {
39544 .property('disabled', saving())
39545 .classed('disabled', function(d) { return !d.annotation(); })
39547 var selection = d3.select(this);
39548 if (selection.property('tooltipVisible')) {
39549 selection.call(tooltip.show);
39555 iD.ui.ViewOnOSM = function(context) {
39558 function viewOnOSM(selection) {
39559 var entity = context.entity(id);
39561 selection.style('display', entity.isNew() ? 'none' : null);
39563 var $link = selection.selectAll('.view-on-osm')
39568 .attr('class', 'view-on-osm')
39569 .attr('target', '_blank')
39570 .call(iD.svg.Icon('#icon-out-link', 'inline'))
39572 .text(t('inspector.view_on_osm'));
39575 .attr('href', context.connection().entityURL(entity));
39578 viewOnOSM.entityID = function(_) {
39579 if (!arguments.length) return id;
39586 iD.ui.Zoom = function(context) {
39590 title: t('zoom.in'),
39591 action: context.zoomIn,
39596 title: t('zoom.out'),
39597 action: context.zoomOut,
39601 function zoomIn() {
39602 d3.event.preventDefault();
39603 if (!context.inIntro()) context.zoomIn();
39606 function zoomOut() {
39607 d3.event.preventDefault();
39608 if (!context.inIntro()) context.zoomOut();
39611 function zoomInFurther() {
39612 d3.event.preventDefault();
39613 if (!context.inIntro()) context.zoomInFurther();
39616 function zoomOutFurther() {
39617 d3.event.preventDefault();
39618 if (!context.inIntro()) context.zoomOutFurther();
39622 return function(selection) {
39623 var button = selection.selectAll('button')
39625 .enter().append('button')
39626 .attr('tabindex', -1)
39627 .attr('class', function(d) { return d.id; })
39628 .on('click.editor', function(d) { d.action(); })
39629 .call(bootstrap.tooltip()
39632 .title(function(d) {
39633 return iD.ui.tooltipHtml(d.title, d.key);
39636 button.each(function(d) {
39638 .call(iD.svg.Icon('#icon-' + d.icon, 'light'));
39641 var keybinding = d3.keybinding('zoom');
39643 _.each(['=','ffequals','plus','ffplus'], function(key) {
39644 keybinding.on(key, zoomIn);
39645 keybinding.on('⇧' + key, zoomIn);
39646 keybinding.on(iD.ui.cmd('⌘' + key), zoomInFurther);
39647 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomInFurther);
39649 _.each(['-','ffminus','_','dash'], function(key) {
39650 keybinding.on(key, zoomOut);
39651 keybinding.on('⇧' + key, zoomOut);
39652 keybinding.on(iD.ui.cmd('⌘' + key), zoomOutFurther);
39653 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomOutFurther);
39656 d3.select(document)
39660 iD.ui.preset.access = function(field) {
39661 var dispatch = d3.dispatch('change'),
39664 function access(selection) {
39665 var wrap = selection.selectAll('.preset-input-wrap')
39668 wrap.enter().append('div')
39669 .attr('class', 'cf preset-input-wrap')
39672 items = wrap.select('ul').selectAll('li')
39677 var enter = items.enter().append('li')
39678 .attr('class', function(d) { return 'cf preset-access-' + d; });
39680 enter.append('span')
39681 .attr('class', 'col6 label preset-label-access')
39682 .attr('for', function(d) { return 'preset-input-access-' + d; })
39683 .text(function(d) { return field.t('types.' + d); });
39685 enter.append('div')
39686 .attr('class', 'col6 preset-input-access-wrap')
39688 .attr('type', 'text')
39689 .attr('class', 'preset-input-access')
39690 .attr('id', function(d) { return 'preset-input-access-' + d; })
39691 .each(function(d) {
39693 .call(d3.combobox()
39694 .data(access.options(d)));
39699 wrap.selectAll('.preset-input-access')
39700 .on('change', change)
39701 .on('blur', change);
39704 function change(d) {
39706 tag[d] = d3.select(this).value() || undefined;
39707 dispatch.change(tag);
39710 access.options = function(type) {
39711 var options = ['no', 'permissive', 'private', 'destination'];
39713 if (type !== 'access') {
39714 options.unshift('yes');
39715 options.push('designated');
39717 if (type === 'bicycle') {
39718 options.push('dismount');
39722 return options.map(function(option) {
39724 title: field.t('options.' + option + '.description'),
39730 var placeholders = {
39732 foot: 'designated',
39733 motor_vehicle: 'no'
39737 motor_vehicle: 'no',
39743 motor_vehicle: 'no'
39746 motor_vehicle: 'no',
39747 bicycle: 'designated'
39750 motor_vehicle: 'no',
39751 horse: 'designated'
39755 motor_vehicle: 'no',
39761 motor_vehicle: 'yes',
39766 motor_vehicle: 'yes'
39770 motor_vehicle: 'yes',
39776 motor_vehicle: 'yes',
39782 motor_vehicle: 'yes',
39788 motor_vehicle: 'yes',
39794 motor_vehicle: 'yes',
39800 motor_vehicle: 'yes',
39806 motor_vehicle: 'yes',
39811 motor_vehicle: 'yes'
39815 motor_vehicle: 'yes',
39821 motor_vehicle: 'yes',
39827 motor_vehicle: 'yes',
39833 access.tags = function(tags) {
39834 items.selectAll('.preset-input-access')
39835 .value(function(d) { return tags[d] || ''; })
39836 .attr('placeholder', function() {
39837 return tags.access ? tags.access : field.placeholder();
39840 // items.selectAll('#preset-input-access-access')
39841 // .attr('placeholder', 'yes');
39843 _.forEach(placeholders[tags.highway], function(v, k) {
39844 items.selectAll('#preset-input-access-' + k)
39845 .attr('placeholder', function() { return (tags.access || v); });
39849 access.focus = function() {
39850 items.selectAll('.preset-input-access')
39854 return d3.rebind(access, dispatch, 'on');
39856 iD.ui.preset.address = function(field, context) {
39857 var dispatch = d3.dispatch('init', 'change'),
39870 function getStreets() {
39871 var extent = entity.extent(context.graph()),
39872 l = extent.center(),
39873 box = iD.geo.Extent(l).padByMeters(200);
39875 return context.intersects(box)
39876 .filter(isAddressable)
39878 var loc = context.projection([
39879 (extent[0][0] + extent[1][0]) / 2,
39880 (extent[0][1] + extent[1][1]) / 2]),
39881 choice = iD.geo.chooseEdge(context.childNodes(d), loc, context.projection);
39883 title: d.tags.name,
39884 value: d.tags.name,
39885 dist: choice.distance
39887 }).sort(function(a, b) {
39888 return a.dist - b.dist;
39891 function isAddressable(d) {
39892 return d.tags.highway && d.tags.name && d.type === 'way';
39896 function getCities() {
39897 var extent = entity.extent(context.graph()),
39898 l = extent.center(),
39899 box = iD.geo.Extent(l).padByMeters(200);
39901 return context.intersects(box)
39902 .filter(isAddressable)
39905 title: d.tags['addr:city'] || d.tags.name,
39906 value: d.tags['addr:city'] || d.tags.name,
39907 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
39909 }).sort(function(a, b) {
39910 return a.dist - b.dist;
39913 function isAddressable(d) {
39915 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
39918 if (d.tags.place && d.tags.name && (
39919 d.tags.place === 'city' ||
39920 d.tags.place === 'town' ||
39921 d.tags.place === 'village'))
39924 if (d.tags['addr:city']) return true;
39930 function getPostCodes() {
39931 var extent = entity.extent(context.graph()),
39932 l = extent.center(),
39933 box = iD.geo.Extent(l).padByMeters(200);
39935 return context.intersects(box)
39936 .filter(isAddressable)
39939 title: d.tags['addr:postcode'],
39940 value: d.tags['addr:postcode'],
39941 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
39943 }).sort(function(a, b) {
39944 return a.dist - b.dist;
39947 function isAddressable(d) {
39948 return d.tags['addr:postcode'];
39952 function address(selection) {
39953 isInitialized = false;
39955 wrap = selection.selectAll('.preset-input-wrap')
39962 .attr('class', 'preset-input-wrap');
39964 var center = entity.extent(context.graph()).center(),
39967 iD.services.nominatim().countryCode(center, function (err, countryCode) {
39968 addressFormat = _.find(iD.data.addressFormats, function (a) {
39969 return a && a.countryCodes && _.includes(a.countryCodes, countryCode);
39970 }) || _.first(iD.data.addressFormats);
39973 // Normalize widths.
39974 var total = _.reduce(r, function(sum, field) {
39975 return sum + (widths[field] || 0.5);
39978 return r.map(function (field) {
39981 width: (widths[field] || 0.5) / total
39986 wrap.selectAll('div')
39987 .data(addressFormat.format)
39990 .attr('class', 'addr-row')
39991 .selectAll('input')
39995 .property('type', 'text')
39996 .attr('placeholder', function (d) { return field.t('placeholders.' + d.id); })
39997 .attr('class', function (d) { return 'addr-' + d.id; })
39998 .style('width', function (d) { return d.width * 100 + '%'; });
40002 wrap.selectAll('.addr-street')
40003 .call(d3.combobox()
40004 .fetcher(function(value, callback) {
40005 callback(getStreets());
40008 wrap.selectAll('.addr-city')
40009 .call(d3.combobox()
40010 .fetcher(function(value, callback) {
40011 callback(getCities());
40014 wrap.selectAll('.addr-postcode')
40015 .call(d3.combobox()
40016 .fetcher(function(value, callback) {
40017 callback(getPostCodes());
40020 wrap.selectAll('input')
40021 .on('blur', change())
40022 .on('change', change());
40024 wrap.selectAll('input:not(.combobox-input)')
40025 .on('input', change(true));
40028 isInitialized = true;
40032 function change(onInput) {
40033 return function() {
40036 wrap.selectAll('input')
40037 .each(function (field) {
40038 tags['addr:' + field.id] = this.value || undefined;
40041 dispatch.change(tags, onInput);
40045 function updateTags(tags) {
40046 wrap.selectAll('input')
40047 .value(function (field) {
40048 return tags['addr:' + field.id] || '';
40052 address.entity = function(_) {
40053 if (!arguments.length) return entity;
40058 address.tags = function(tags) {
40059 if (isInitialized) {
40062 dispatch.on('init', function () {
40068 address.focus = function() {
40069 var node = wrap.selectAll('input').node();
40070 if (node) node.focus();
40073 return d3.rebind(address, dispatch, 'on');
40075 iD.ui.preset.check =
40076 iD.ui.preset.defaultcheck = function(field) {
40077 var dispatch = d3.dispatch('change'),
40078 options = field.strings && field.strings.options,
40081 entity, value, box, text, label;
40084 for (var k in options) {
40085 values.push(k === 'undefined' ? undefined : k);
40086 texts.push(field.t('options.' + k, { 'default': options[k] }));
40089 values = [undefined, 'yes'];
40090 texts = [t('inspector.unknown'), t('inspector.check.yes')];
40091 if (field.type === 'check') {
40093 texts.push(t('inspector.check.no'));
40097 var check = function(selection) {
40098 // hack: pretend oneway field is a oneway_yes field
40099 // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
40100 if (field.id === 'oneway') {
40101 for (var key in entity.tags) {
40102 if (key in iD.oneWayTags && (entity.tags[key] in iD.oneWayTags[key])) {
40103 texts[0] = t('presets.fields.oneway_yes.options.undefined');
40109 selection.classed('checkselect', 'true');
40111 label = selection.selectAll('.preset-input-wrap')
40114 var enter = label.enter().append('label')
40115 .attr('class', 'preset-input-wrap');
40117 enter.append('input')
40118 .property('indeterminate', field.type === 'check')
40119 .attr('type', 'checkbox')
40120 .attr('id', 'preset-input-' + field.id);
40122 enter.append('span')
40124 .attr('class', 'value');
40126 box = label.select('input')
40127 .on('click', function() {
40129 t[field.key] = values[(values.indexOf(value) + 1) % values.length];
40130 dispatch.change(t);
40131 d3.event.stopPropagation();
40134 text = label.select('span.value');
40137 check.entity = function(_) {
40138 if (!arguments.length) return entity;
40143 check.tags = function(tags) {
40144 value = tags[field.key];
40145 box.property('indeterminate', field.type === 'check' && !value);
40146 box.property('checked', value === 'yes');
40147 text.text(texts[values.indexOf(value)]);
40148 label.classed('set', !!value);
40151 check.focus = function() {
40152 box.node().focus();
40155 return d3.rebind(check, dispatch, 'on');
40157 iD.ui.preset.combo =
40158 iD.ui.preset.typeCombo =
40159 iD.ui.preset.multiCombo = function(field, context) {
40160 var dispatch = d3.dispatch('change'),
40161 isMulti = (field.type === 'multiCombo'),
40162 optstrings = field.strings && field.strings.options,
40163 optarray = field.options,
40164 snake_case = (field.snake_case || (field.snake_case === undefined)),
40165 combobox = d3.combobox().minItems(isMulti ? 1 : 2),
40172 // ensure multiCombo field.key ends with a ':'
40173 if (isMulti && field.key.match(/:$/) === null) {
40178 function snake(s) {
40179 return s.replace(/\s+/g, '_');
40182 function unsnake(s) {
40183 return s.replace(/_+/g, ' ');
40186 function clean(s) {
40187 return s.split(';')
40188 .map(function(s) { return s.trim(); })
40193 // returns the tag value for a display value
40194 // (for multiCombo, dval should be the key suffix, not the entire key)
40195 function tagValue(dval) {
40196 dval = clean(dval || '');
40199 var match = _.find(comboData, function(o) {
40200 return o.key && clean(o.value) === dval;
40207 if (field.type === 'typeCombo' && !dval) {
40211 return (snake_case ? snake(dval) : dval) || undefined;
40215 // returns the display value for a tag value
40216 // (for multiCombo, tval should be the key suffix, not the entire key)
40217 function displayValue(tval) {
40221 var match = _.find(comboData, function(o) { return o.key === tval && o.value; });
40223 return match.value;
40227 if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
40231 return snake_case ? unsnake(tval) : tval;
40235 function objectDifference(a, b) {
40236 return _.reject(a, function(d1) {
40237 return _.some(b, function(d2) { return d1.value === d2.value; });
40242 function initCombo(selection, attachTo) {
40244 selection.attr('readonly', 'readonly');
40245 selection.call(combobox, attachTo);
40246 setStaticValues(setPlaceholder);
40248 } else if (optarray) {
40249 selection.call(combobox, attachTo);
40250 setStaticValues(setPlaceholder);
40252 } else if (context.taginfo()) {
40253 selection.call(combobox.fetcher(setTaginfoValues), attachTo);
40254 setTaginfoValues('', setPlaceholder);
40259 function setStaticValues(callback) {
40260 if (!(optstrings || optarray)) return;
40263 comboData = Object.keys(optstrings).map(function(k) {
40264 var v = field.t('options.' + k, { 'default': optstrings[k] });
40272 } else if (optarray) {
40273 comboData = optarray.map(function(k) {
40274 var v = snake_case ? unsnake(k) : k;
40283 combobox.data(objectDifference(comboData, multiData));
40284 if (callback) callback(comboData);
40288 function setTaginfoValues(q, callback) {
40289 var fn = isMulti ? 'multikeys' : 'values';
40290 context.taginfo()[fn]({
40293 geometry: context.geometry(entity.id),
40294 query: (isMulti ? field.key : '') + q
40295 }, function(err, data) {
40297 comboData = _.map(data, 'value').map(function(k) {
40298 if (isMulti) k = k.replace(field.key, '');
40299 var v = snake_case ? unsnake(k) : k;
40306 comboData = objectDifference(comboData, multiData);
40307 if (callback) callback(comboData);
40312 function setPlaceholder(d) {
40315 ph = field.placeholder() || t('inspector.add');
40317 var vals = _.map(d, 'value').filter(function(s) { return s.length < 20; }),
40318 placeholders = vals.length > 1 ? vals : _.map(d, 'key');
40319 ph = field.placeholder() || placeholders.slice(0, 3).join(', ');
40322 input.attr('placeholder', ph + '…');
40326 function change() {
40327 var val = tagValue(input.value()),
40332 container.classed('active', false);
40334 field.keys.push(field.key + val);
40335 t[field.key + val] = 'yes';
40336 window.setTimeout(function() { input.node().focus(); }, 10);
40339 t[field.key] = val;
40342 dispatch.change(t);
40346 function removeMultikey(d) {
40347 d3.event.stopPropagation();
40349 t[d.key] = undefined;
40350 dispatch.change(t);
40354 function combo(selection) {
40356 container = selection.selectAll('ul').data([0]);
40360 .attr('class', 'form-field-multicombo')
40361 .on('click', function() {
40362 window.setTimeout(function() { input.node().focus(); }, 10);
40366 container = selection;
40369 input = container.selectAll('input')
40374 .attr('type', 'text')
40375 .attr('id', 'preset-input-' + field.id)
40376 .call(initCombo, selection);
40379 .on('change', change)
40380 .on('blur', change);
40384 .on('accept', function() {
40385 input.node().blur();
40386 input.node().focus();
40390 .on('focus', function() { container.classed('active', true); });
40395 combo.tags = function(tags) {
40399 // Build multiData array containing keys already set..
40400 Object.keys(tags).forEach(function(key) {
40401 if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return;
40403 var suffix = key.substring(field.key.length);
40406 value: displayValue(suffix)
40410 // Set keys for form-field modified (needed for undo and reset buttons)..
40411 field.keys = _.map(multiData, 'key');
40413 // Exclude existing multikeys from combo options..
40414 var available = objectDifference(comboData, multiData);
40415 combobox.data(available);
40417 // Hide "Add" button if this field uses fixed set of
40418 // translateable optstrings and they're all currently used..
40419 container.selectAll('.combobox-input, .combobox-caret')
40420 .classed('hide', optstrings && !available.length);
40424 var chips = container.selectAll('.chips').data(multiData);
40426 var enter = chips.enter()
40427 .insert('li', 'input')
40428 .attr('class', 'chips');
40430 enter.append('span');
40433 chips.select('span')
40434 .text(function(d) { return d.value; });
40437 .on('click', removeMultikey)
40438 .attr('class', 'remove')
40445 input.value(displayValue(tags[field.key]));
40450 combo.focus = function() {
40451 input.node().focus();
40455 combo.entity = function(_) {
40456 if (!arguments.length) return entity;
40462 return d3.rebind(combo, dispatch, 'on');
40464 iD.ui.preset.cycleway = function(field) {
40465 var dispatch = d3.dispatch('change'),
40468 function cycleway(selection) {
40469 var wrap = selection.selectAll('.preset-input-wrap')
40472 wrap.enter().append('div')
40473 .attr('class', 'cf preset-input-wrap')
40476 items = wrap.select('ul').selectAll('li')
40481 var enter = items.enter().append('li')
40482 .attr('class', function(d) { return 'cf preset-cycleway-' + d; });
40484 enter.append('span')
40485 .attr('class', 'col6 label preset-label-cycleway')
40486 .attr('for', function(d) { return 'preset-input-cycleway-' + d; })
40487 .text(function(d) { return field.t('types.' + d); });
40489 enter.append('div')
40490 .attr('class', 'col6 preset-input-cycleway-wrap')
40492 .attr('type', 'text')
40493 .attr('class', 'preset-input-cycleway')
40494 .attr('id', function(d) { return 'preset-input-cycleway-' + d; })
40495 .each(function(d) {
40497 .call(d3.combobox()
40498 .data(cycleway.options(d)));
40503 wrap.selectAll('.preset-input-cycleway')
40504 .on('change', change)
40505 .on('blur', change);
40508 function change() {
40509 var inputs = d3.selectAll('.preset-input-cycleway')[0],
40510 left = d3.select(inputs[0]).value(),
40511 right = d3.select(inputs[1]).value(),
40513 if (left === 'none' || left === '') { left = undefined; }
40514 if (right === 'none' || right === '') { right = undefined; }
40516 // Always set both left and right as changing one can affect the other
40518 cycleway: undefined,
40519 'cycleway:left': left,
40520 'cycleway:right': right
40523 // If the left and right tags match, use the cycleway tag to tag both
40524 // sides the same way
40525 if (left === right) {
40528 'cycleway:left': undefined,
40529 'cycleway:right': undefined
40533 dispatch.change(tag);
40536 cycleway.options = function() {
40537 return d3.keys(field.strings.options).map(function(option) {
40539 title: field.t('options.' + option + '.description'),
40545 cycleway.tags = function(tags) {
40546 items.selectAll('.preset-input-cycleway')
40547 .value(function(d) {
40548 // If cycleway is set, always return that
40549 if (tags.cycleway) {
40550 return tags.cycleway;
40552 return tags[d] || '';
40554 .attr('placeholder', field.placeholder());
40557 cycleway.focus = function() {
40558 items.selectAll('.preset-input-cycleway')
40562 return d3.rebind(cycleway, dispatch, 'on');
40564 iD.ui.preset.text =
40565 iD.ui.preset.number =
40567 iD.ui.preset.email =
40568 iD.ui.preset.url = function(field, context) {
40570 var dispatch = d3.dispatch('change'),
40574 function i(selection) {
40575 var fieldId = 'preset-input-' + field.id;
40577 input = selection.selectAll('input')
40580 input.enter().append('input')
40581 .attr('type', field.type)
40582 .attr('id', fieldId)
40583 .attr('placeholder', field.placeholder() || t('inspector.unknown'));
40586 .on('input', change(true))
40587 .on('blur', change())
40588 .on('change', change());
40590 if (field.type === 'tel') {
40591 var center = entity.extent(context.graph()).center();
40592 iD.services.nominatim().countryCode(center, function (err, countryCode) {
40593 if (err || !iD.data.phoneFormats[countryCode]) return;
40594 selection.selectAll('#' + fieldId)
40595 .attr('placeholder', iD.data.phoneFormats[countryCode]);
40598 } else if (field.type === 'number') {
40599 input.attr('type', 'text');
40601 var spinControl = selection.selectAll('.spin-control')
40604 var enter = spinControl.enter().append('div')
40605 .attr('class', 'spin-control');
40607 enter.append('button')
40609 .attr('class', 'increment')
40610 .attr('tabindex', -1);
40612 enter.append('button')
40614 .attr('class', 'decrement')
40615 .attr('tabindex', -1);
40617 spinControl.selectAll('button')
40618 .on('click', function(d) {
40619 d3.event.preventDefault();
40620 var num = parseInt(input.node().value || 0, 10);
40621 if (!isNaN(num)) input.node().value = num + d;
40627 function change(onInput) {
40628 return function() {
40630 t[field.key] = input.value() || undefined;
40631 dispatch.change(t, onInput);
40635 i.entity = function(_) {
40636 if (!arguments.length) return entity;
40641 i.tags = function(tags) {
40642 input.value(tags[field.key] || '');
40645 i.focus = function() {
40646 var node = input.node();
40647 if (node) node.focus();
40650 return d3.rebind(i, dispatch, 'on');
40652 iD.ui.preset.localized = function(field, context) {
40653 var dispatch = d3.dispatch('change', 'input'),
40654 wikipedia = iD.services.wikipedia(),
40655 input, localizedInputs, wikiTitles,
40658 function i(selection) {
40659 input = selection.selectAll('.localized-main')
40662 input.enter().append('input')
40663 .attr('type', 'text')
40664 .attr('id', 'preset-input-' + field.id)
40665 .attr('class', 'localized-main')
40666 .attr('placeholder', field.placeholder());
40668 if (field.id === 'name') {
40669 var preset = context.presets().match(entity, context.graph());
40670 input.call(d3.combobox().fetcher(
40671 iD.util.SuggestNames(preset, iD.data.suggestions)
40676 .on('input', change(true))
40677 .on('blur', change())
40678 .on('change', change());
40680 var translateButton = selection.selectAll('.localized-add')
40683 translateButton.enter()
40685 .attr('class', 'button-input-action localized-add minor')
40686 .attr('tabindex', -1)
40687 .call(iD.svg.Icon('#icon-plus'))
40688 .call(bootstrap.tooltip()
40689 .title(t('translate.translate'))
40690 .placement('left'));
40693 .on('click', addNew);
40695 localizedInputs = selection.selectAll('.localized-wrap')
40698 localizedInputs.enter().append('div')
40699 .attr('class', 'localized-wrap');
40702 function addNew() {
40703 d3.event.preventDefault();
40704 var data = localizedInputs.selectAll('div.entry').data();
40705 var defaultLang = iD.detect().locale.toLowerCase().split('-')[0];
40706 var langExists = _.find(data, function(datum) { return datum.lang === defaultLang;});
40707 var isLangEn = defaultLang.indexOf('en') > -1;
40708 if (isLangEn || langExists) {
40711 data.push({ lang: defaultLang, value: '' });
40712 localizedInputs.call(render, data);
40715 function change(onInput) {
40716 return function() {
40718 t[field.key] = d3.select(this).value() || undefined;
40719 dispatch.change(t, onInput);
40723 function key(lang) { return field.key + ':' + lang; }
40725 function changeLang(d) {
40726 var lang = d3.select(this).value(),
40728 language = _.find(iD.data.wikipedia, function(d) {
40729 return d[0].toLowerCase() === lang.toLowerCase() ||
40730 d[1].toLowerCase() === lang.toLowerCase();
40733 if (language) lang = language[2];
40735 if (d.lang && d.lang !== lang) {
40736 t[key(d.lang)] = undefined;
40739 var value = d3.select(this.parentNode)
40740 .selectAll('.localized-value')
40743 if (lang && value) {
40744 t[key(lang)] = value;
40745 } else if (lang && wikiTitles && wikiTitles[d.lang]) {
40746 t[key(lang)] = wikiTitles[d.lang];
40750 dispatch.change(t);
40753 function changeValue(d) {
40754 if (!d.lang) return;
40756 t[key(d.lang)] = d3.select(this).value() || undefined;
40757 dispatch.change(t);
40760 function fetcher(value, cb) {
40761 var v = value.toLowerCase();
40763 cb(iD.data.wikipedia.filter(function(d) {
40764 return d[0].toLowerCase().indexOf(v) >= 0 ||
40765 d[1].toLowerCase().indexOf(v) >= 0 ||
40766 d[2].toLowerCase().indexOf(v) >= 0;
40767 }).map(function(d) {
40768 return { value: d[1] };
40772 function render(selection, data) {
40773 var wraps = selection.selectAll('div.entry').
40774 data(data, function(d) { return d.lang; });
40776 var innerWrap = wraps.enter()
40777 .insert('div', ':first-child');
40779 innerWrap.attr('class', 'entry')
40781 var wrap = d3.select(this);
40782 var langcombo = d3.combobox().fetcher(fetcher).minItems(0);
40784 var label = wrap.append('label')
40785 .attr('class','form-label')
40786 .text(t('translate.localized_translation_label'))
40787 .attr('for','localized-lang');
40789 label.append('button')
40790 .attr('class', 'minor remove')
40791 .on('click', function(d){
40792 d3.event.preventDefault();
40794 t[key(d.lang)] = undefined;
40795 dispatch.change(t);
40796 d3.select(this.parentNode.parentNode)
40798 .style('max-height','240px')
40800 .style('opacity', '0')
40801 .style('max-height','0px')
40804 .call(iD.svg.Icon('#operation-delete'));
40806 wrap.append('input')
40807 .attr('class', 'localized-lang')
40808 .attr('type', 'text')
40809 .attr('placeholder',t('translate.localized_translation_language'))
40810 .on('blur', changeLang)
40811 .on('change', changeLang)
40814 wrap.append('input')
40815 .on('blur', changeValue)
40816 .on('change', changeValue)
40817 .attr('type', 'text')
40818 .attr('placeholder', t('translate.localized_translation_name'))
40819 .attr('class', 'localized-value');
40823 .style('margin-top', '0px')
40824 .style('max-height', '0px')
40825 .style('opacity', '0')
40828 .style('margin-top', '10px')
40829 .style('max-height', '240px')
40830 .style('opacity', '1')
40831 .each('end', function() {
40833 .style('max-height', '')
40834 .style('overflow', 'visible');
40840 .style('max-height','0px')
40841 .style('opacity', '0')
40842 .style('top','-10px')
40845 var entry = selection.selectAll('.entry');
40847 entry.select('.localized-lang')
40848 .value(function(d) {
40849 var lang = _.find(iD.data.wikipedia, function(lang) { return lang[2] === d.lang; });
40850 return lang ? lang[1] : d.lang;
40853 entry.select('.localized-value')
40854 .value(function(d) { return d.value; });
40857 i.tags = function(tags) {
40858 // Fetch translations from wikipedia
40859 if (tags.wikipedia && !wikiTitles) {
40861 var wm = tags.wikipedia.match(/([^:]+):(.+)/);
40862 if (wm && wm[0] && wm[1]) {
40863 wikipedia.translations(wm[1], wm[2], function(d) {
40869 input.value(tags[field.key] || '');
40871 var postfixed = [], k, m;
40873 m = k.match(/^(.*):([a-zA-Z_-]+)$/);
40874 if (m && m[1] === field.key && m[2]) {
40875 postfixed.push({ lang: m[2], value: tags[k] });
40879 localizedInputs.call(render, postfixed.reverse());
40882 i.focus = function() {
40883 input.node().focus();
40886 i.entity = function(_) {
40890 return d3.rebind(i, dispatch, 'on');
40892 iD.ui.preset.maxspeed = function(field, context) {
40893 var dispatch = d3.dispatch('change'),
40900 var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
40901 imperialValues = [20, 25, 30, 35, 40, 45, 50, 55, 65, 70];
40903 function maxspeed(selection) {
40904 combobox = d3.combobox();
40905 var unitCombobox = d3.combobox().data(['km/h', 'mph'].map(comboValues));
40907 input = selection.selectAll('#preset-input-' + field.id)
40910 input.enter().append('input')
40911 .attr('type', 'text')
40912 .attr('id', 'preset-input-' + field.id)
40913 .attr('placeholder', field.placeholder());
40917 .on('change', change)
40918 .on('blur', change);
40920 var childNodes = context.graph().childNodes(context.entity(entity.id)),
40921 loc = childNodes[~~(childNodes.length/2)].loc;
40923 imperial = _.some(iD.data.imperial.features, function(f) {
40924 return _.some(f.geometry.coordinates, function(d) {
40925 return iD.geo.pointInPolygon(loc, d[0]);
40929 unitInput = selection.selectAll('input.maxspeed-unit')
40932 unitInput.enter().append('input')
40933 .attr('type', 'text')
40934 .attr('class', 'maxspeed-unit');
40937 .on('blur', changeUnits)
40938 .on('change', changeUnits)
40939 .call(unitCombobox);
40941 function changeUnits() {
40942 imperial = unitInput.value() === 'mph';
40943 unitInput.value(imperial ? 'mph' : 'km/h');
40950 function setSuggestions() {
40951 combobox.data((imperial ? imperialValues : metricValues).map(comboValues));
40952 unitInput.value(imperial ? 'mph' : 'km/h');
40955 function comboValues(d) {
40957 value: d.toString(),
40958 title: d.toString()
40962 function change() {
40964 value = input.value();
40967 tag[field.key] = undefined;
40968 } else if (isNaN(value) || !imperial) {
40969 tag[field.key] = value;
40971 tag[field.key] = value + ' mph';
40974 dispatch.change(tag);
40977 maxspeed.tags = function(tags) {
40978 var value = tags[field.key];
40980 if (value && value.indexOf('mph') >= 0) {
40981 value = parseInt(value, 10);
40983 } else if (value) {
40989 input.value(value || '');
40992 maxspeed.focus = function() {
40993 input.node().focus();
40996 maxspeed.entity = function(_) {
41000 return d3.rebind(maxspeed, dispatch, 'on');
41002 iD.ui.preset.radio = function(field) {
41003 var dispatch = d3.dispatch('change'),
41004 labels, radios, placeholder;
41006 function radio(selection) {
41007 selection.classed('preset-radio', true);
41009 var wrap = selection.selectAll('.preset-input-wrap')
41012 var buttonWrap = wrap.enter().append('div')
41013 .attr('class', 'preset-input-wrap toggle-list');
41015 buttonWrap.append('span')
41016 .attr('class', 'placeholder');
41018 placeholder = selection.selectAll('.placeholder');
41020 labels = wrap.selectAll('label')
41021 .data(field.options || field.keys);
41023 var enter = labels.enter().append('label');
41025 enter.append('input')
41026 .attr('type', 'radio')
41027 .attr('name', field.id)
41028 .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
41029 .attr('checked', false);
41031 enter.append('span')
41032 .text(function(d) { return field.t('options.' + d, { 'default': d }); });
41034 radios = labels.selectAll('input')
41035 .on('change', change);
41038 function change() {
41040 if (field.key) t[field.key] = undefined;
41041 radios.each(function(d) {
41042 var active = d3.select(this).property('checked');
41044 if (active) t[field.key] = d;
41046 t[d] = active ? 'yes' : undefined;
41049 dispatch.change(t);
41052 radio.tags = function(tags) {
41053 function checked(d) {
41055 return tags[field.key] === d;
41057 return !!(tags[d] && tags[d] !== 'no');
41061 labels.classed('active', checked);
41062 radios.property('checked', checked);
41063 var selection = radios.filter(function() { return this.checked; });
41064 if (selection.empty()) {
41065 placeholder.text(t('inspector.none'));
41067 placeholder.text(selection.attr('value'));
41071 radio.focus = function() {
41072 radios.node().focus();
41075 return d3.rebind(radio, dispatch, 'on');
41077 iD.ui.preset.restrictions = function(field, context) {
41078 var dispatch = d3.dispatch('change'),
41079 hover = iD.behavior.Hover(context),
41084 function restrictions(selection) {
41085 // if form field is hidden or has detached from dom, clean up.
41086 if (!d3.select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
41087 selection.call(restrictions.off);
41091 var wrap = selection.selectAll('.preset-input-wrap')
41094 var enter = wrap.enter()
41096 .attr('class', 'preset-input-wrap');
41100 .attr('class', 'restriction-help');
41103 var intersection = iD.geo.Intersection(context.graph(), vertexID),
41104 graph = intersection.graph,
41105 vertex = graph.entity(vertexID),
41106 filter = d3.functor(true),
41107 extent = iD.geo.Extent(),
41108 projection = iD.geo.RawMercator();
41110 var d = wrap.dimensions(),
41111 c = [d[0] / 2, d[1] / 2],
41115 .scale(256 * Math.pow(2, z) / (2 * Math.PI));
41117 var s = projection(vertex.loc);
41120 .translate([c[0] - s[0], c[1] - s[1]])
41121 .clipExtent([[0, 0], d]);
41123 var drawLayers = iD.svg.Layers(projection, context).only('osm').dimensions(d),
41124 drawVertices = iD.svg.Vertices(projection, context),
41125 drawLines = iD.svg.Lines(projection, context),
41126 drawTurns = iD.svg.Turns(projection, context);
41130 .selectAll('.surface')
41134 var surface = wrap.selectAll('.surface');
41138 .call(drawVertices, graph, [vertex], filter, extent, z)
41139 .call(drawLines, graph, intersection.ways, filter)
41140 .call(drawTurns, graph, intersection.turns(fromNodeID));
41143 .on('click.restrictions', click)
41144 .on('mouseover.restrictions', mouseover)
41145 .on('mouseout.restrictions', mouseout);
41148 .selectAll('.selected')
41149 .classed('selected', false);
41153 .selectAll('.' + intersection.highways[fromNodeID].id)
41154 .classed('selected', true);
41160 .on('change.restrictions', render);
41163 .on('resize.restrictions', function() {
41164 wrap.dimensions(null);
41169 var datum = d3.event.target.__data__;
41170 if (datum instanceof iD.Entity) {
41171 fromNodeID = intersection.adjacentNodeId(datum.id);
41173 } else if (datum instanceof iD.geo.Turn) {
41174 if (datum.restriction) {
41176 iD.actions.UnrestrictTurn(datum, projection),
41177 t('operations.restriction.annotation.delete'));
41180 iD.actions.RestrictTurn(datum, projection),
41181 t('operations.restriction.annotation.create'));
41186 function mouseover() {
41187 var datum = d3.event.target.__data__;
41188 if (datum instanceof iD.geo.Turn) {
41189 var graph = context.graph(),
41190 presets = context.presets(),
41193 if (datum.restriction) {
41194 preset = presets.match(graph.entity(datum.restriction), graph);
41196 preset = presets.item('type/restriction/' +
41197 iD.geo.inferRestriction(
41205 wrap.selectAll('.restriction-help')
41206 .text(t('operations.restriction.help.' +
41207 (datum.restriction ? 'toggle_off' : 'toggle_on'),
41208 {restriction: preset.name()}));
41212 function mouseout() {
41213 wrap.selectAll('.restriction-help')
41214 .text(t('operations.restriction.help.' +
41215 (fromNodeID ? 'toggle' : 'select')));
41218 function render() {
41219 if (context.hasEntity(vertexID)) {
41220 restrictions(selection);
41225 restrictions.entity = function(_) {
41226 if (!vertexID || vertexID !== _.id) {
41232 restrictions.tags = function() {};
41233 restrictions.focus = function() {};
41235 restrictions.off = function(selection) {
41236 selection.selectAll('.surface')
41238 .on('click.restrictions', null)
41239 .on('mouseover.restrictions', null)
41240 .on('mouseout.restrictions', null);
41243 .on('change.restrictions', null);
41246 .on('resize.restrictions', null);
41249 return d3.rebind(restrictions, dispatch, 'on');
41251 iD.ui.preset.textarea = function(field) {
41252 var dispatch = d3.dispatch('change'),
41255 function i(selection) {
41256 input = selection.selectAll('textarea')
41259 input.enter().append('textarea')
41260 .attr('id', 'preset-input-' + field.id)
41261 .attr('placeholder', field.placeholder() || t('inspector.unknown'))
41262 .attr('maxlength', 255);
41265 .on('input', change(true))
41266 .on('blur', change())
41267 .on('change', change());
41270 function change(onInput) {
41271 return function() {
41273 t[field.key] = input.value() || undefined;
41274 dispatch.change(t, onInput);
41278 i.tags = function(tags) {
41279 input.value(tags[field.key] || '');
41282 i.focus = function() {
41283 input.node().focus();
41286 return d3.rebind(i, dispatch, 'on');
41288 iD.ui.preset.wikipedia = function(field, context) {
41289 var dispatch = d3.dispatch('change'),
41290 wikipedia = iD.services.wikipedia(),
41291 link, entity, lang, title;
41293 function i(selection) {
41294 var langcombo = d3.combobox()
41295 .fetcher(function(value, cb) {
41296 var v = value.toLowerCase();
41298 cb(iD.data.wikipedia.filter(function(d) {
41299 return d[0].toLowerCase().indexOf(v) >= 0 ||
41300 d[1].toLowerCase().indexOf(v) >= 0 ||
41301 d[2].toLowerCase().indexOf(v) >= 0;
41302 }).map(function(d) {
41303 return { value: d[1] };
41307 var titlecombo = d3.combobox()
41308 .fetcher(function(value, cb) {
41310 if (!value) value = context.entity(entity.id).tags.name || '';
41311 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
41313 searchfn(language()[2], value, function(query, data) {
41314 cb(data.map(function(d) {
41315 return { value: d };
41320 lang = selection.selectAll('input.wiki-lang')
41323 lang.enter().append('input')
41324 .attr('type', 'text')
41325 .attr('class', 'wiki-lang')
41326 .attr('placeholder', t('translate.localized_translation_language'))
41331 .on('blur', changeLang)
41332 .on('change', changeLang);
41334 title = selection.selectAll('input.wiki-title')
41337 title.enter().append('input')
41338 .attr('type', 'text')
41339 .attr('class', 'wiki-title')
41340 .attr('id', 'preset-input-' + field.id);
41344 .on('blur', change)
41345 .on('change', change);
41347 link = selection.selectAll('a.wiki-link')
41350 link.enter().append('a')
41351 .attr('class', 'wiki-link button-input-action minor')
41352 .attr('tabindex', -1)
41353 .attr('target', '_blank')
41354 .call(iD.svg.Icon('#icon-out-link', 'inline'));
41357 function language() {
41358 var value = lang.value().toLowerCase();
41359 var locale = iD.detect().locale.toLowerCase();
41360 var localeLanguage;
41361 return _.find(iD.data.wikipedia, function(d) {
41362 if (d[2] === locale) localeLanguage = d;
41363 return d[0].toLowerCase() === value ||
41364 d[1].toLowerCase() === value ||
41366 }) || localeLanguage || ['English', 'English', 'en'];
41369 function changeLang() {
41370 lang.value(language()[1]);
41374 function change() {
41375 var value = title.value(),
41376 m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
41377 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
41381 // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
41382 value = decodeURIComponent(m[2]).replace(/_/g, ' ');
41385 // Best-effort `anchordecode:` implementation
41386 anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
41388 anchor = decodeURIComponent(m[3]);
41390 value += '#' + anchor.replace(/_/g, ' ');
41392 value = value.slice(0, 1).toUpperCase() + value.slice(1);
41394 title.value(value);
41398 t[field.key] = value ? language()[2] + ':' + value : undefined;
41399 dispatch.change(t);
41402 i.tags = function(tags) {
41403 var value = tags[field.key] || '',
41404 m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
41405 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
41406 anchor = m && m[3];
41408 // value in correct format
41411 title.value(m[2] + (anchor ? ('#' + anchor) : ''));
41414 // Best-effort `anchorencode:` implementation
41415 anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
41417 anchor = anchor.replace(/ /g, '_');
41420 link.attr('href', 'https://' + m[1] + '.wikipedia.org/wiki/' +
41421 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : ''));
41423 // unrecognized value format
41425 title.value(value);
41426 if (value && value !== '') {
41429 link.attr('href', 'https://en.wikipedia.org/wiki/Special:Search?search=' + value);
41433 i.entity = function(_) {
41437 i.focus = function() {
41438 title.node().focus();
41441 return d3.rebind(i, dispatch, 'on');
41443 iD.ui.intro.area = function(context, reveal) {
41444 var event = d3.dispatch('done'),
41448 title: 'intro.areas.title'
41451 step.enter = function() {
41452 var playground = [-85.63552, 41.94159],
41453 corner = [-85.63565411045074, 41.9417715536927];
41454 context.map().centerZoom(playground, 19);
41455 reveal('button.add-area',
41456 t('intro.areas.add', { button: iD.ui.intro.icon('#icon-area', 'pre-text') }),
41457 { tooltipClass: 'intro-areas-add' });
41459 context.on('enter.intro', addArea);
41461 function addArea(mode) {
41462 if (mode.id !== 'add-area') return;
41463 context.on('enter.intro', drawArea);
41465 var padding = 120 * Math.pow(2, context.map().zoom() - 19);
41466 var pointBox = iD.ui.intro.pad(corner, padding, context);
41467 reveal(pointBox, t('intro.areas.corner'));
41469 context.map().on('move.intro', function() {
41470 padding = 120 * Math.pow(2, context.map().zoom() - 19);
41471 pointBox = iD.ui.intro.pad(corner, padding, context);
41472 reveal(pointBox, t('intro.areas.corner'), {duration: 0});
41476 function drawArea(mode) {
41477 if (mode.id !== 'draw-area') return;
41478 context.on('enter.intro', enterSelect);
41480 var padding = 150 * Math.pow(2, context.map().zoom() - 19);
41481 var pointBox = iD.ui.intro.pad(playground, padding, context);
41482 reveal(pointBox, t('intro.areas.place'));
41484 context.map().on('move.intro', function() {
41485 padding = 150 * Math.pow(2, context.map().zoom() - 19);
41486 pointBox = iD.ui.intro.pad(playground, padding, context);
41487 reveal(pointBox, t('intro.areas.place'), {duration: 0});
41491 function enterSelect(mode) {
41492 if (mode.id !== 'select') return;
41493 context.map().on('move.intro', null);
41494 context.on('enter.intro', null);
41496 timeout = setTimeout(function() {
41497 reveal('.preset-search-input',
41498 t('intro.areas.search',
41499 { name: context.presets().item('leisure/playground').name() }));
41500 d3.select('.preset-search-input').on('keyup.intro', keySearch);
41504 function keySearch() {
41505 var first = d3.select('.preset-list-item:first-child');
41506 if (first.classed('preset-leisure-playground')) {
41507 reveal(first.select('.preset-list-button').node(), t('intro.areas.choose'));
41508 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
41509 d3.select('.preset-search-input').on('keyup.intro', null);
41513 function selectedPreset() {
41515 t('intro.areas.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
41516 context.on('exit.intro', event.done);
41520 step.exit = function() {
41521 window.clearTimeout(timeout);
41522 context.on('enter.intro', null);
41523 context.on('exit.intro', null);
41524 context.history().on('change.intro', null);
41525 context.map().on('move.intro', null);
41526 d3.select('.preset-search-input').on('keyup.intro', null);
41529 return d3.rebind(step, event, 'on');
41531 iD.ui.intro.line = function(context, reveal) {
41532 var event = d3.dispatch('done'),
41536 title: 'intro.lines.title'
41539 function timeout(f, t) {
41540 timeouts.push(window.setTimeout(f, t));
41543 function eventCancel() {
41544 d3.event.stopPropagation();
41545 d3.event.preventDefault();
41548 step.enter = function() {
41549 var centroid = [-85.62830, 41.95699];
41550 var midpoint = [-85.62975395449628, 41.95787501510204];
41551 var start = [-85.6297754121684, 41.95805253325314];
41552 var intersection = [-85.62974496187628, 41.95742515554585];
41554 context.map().centerZoom(start, 18);
41555 reveal('button.add-line',
41556 t('intro.lines.add', { button: iD.ui.intro.icon('#icon-line', 'pre-text') }),
41557 { tooltipClass: 'intro-lines-add' });
41559 context.on('enter.intro', addLine);
41561 function addLine(mode) {
41562 if (mode.id !== 'add-line') return;
41563 context.on('enter.intro', drawLine);
41565 var padding = 150 * Math.pow(2, context.map().zoom() - 18);
41566 var pointBox = iD.ui.intro.pad(start, padding, context);
41567 reveal(pointBox, t('intro.lines.start'));
41569 context.map().on('move.intro', function() {
41570 padding = 150 * Math.pow(2, context.map().zoom() - 18);
41571 pointBox = iD.ui.intro.pad(start, padding, context);
41572 reveal(pointBox, t('intro.lines.start'), {duration: 0});
41576 function drawLine(mode) {
41577 if (mode.id !== 'draw-line') return;
41578 context.history().on('change.intro', addIntersection);
41579 context.on('enter.intro', retry);
41581 var padding = 300 * Math.pow(2, context.map().zoom() - 19);
41582 var pointBox = iD.ui.intro.pad(midpoint, padding, context);
41583 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}));
41585 context.map().on('move.intro', function() {
41586 padding = 300 * Math.pow(2, context.map().zoom() - 19);
41587 pointBox = iD.ui.intro.pad(midpoint, padding, context);
41588 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}), {duration: 0});
41592 // ended line before creating intersection
41593 function retry(mode) {
41594 if (mode.id !== 'select') return;
41595 var pointBox = iD.ui.intro.pad(intersection, 30, context),
41596 ids = mode.selectedIDs();
41597 reveal(pointBox, t('intro.lines.restart', {name: t('intro.graph.flower_st')}));
41598 d3.select(window).on('mousedown.intro', eventCancel, true);
41600 timeout(function() {
41601 context.replace(iD.actions.DeleteMultiple(ids));
41607 function addIntersection(changes) {
41608 if ( _.some(changes.created(), function(d) {
41609 return d.type === 'node' && context.graph().parentWays(d).length > 1;
41611 context.history().on('change.intro', null);
41612 context.on('enter.intro', enterSelect);
41614 var padding = 900 * Math.pow(2, context.map().zoom() - 19);
41615 var pointBox = iD.ui.intro.pad(centroid, padding, context);
41616 reveal(pointBox, t('intro.lines.finish'));
41618 context.map().on('move.intro', function() {
41619 padding = 900 * Math.pow(2, context.map().zoom() - 19);
41620 pointBox = iD.ui.intro.pad(centroid, padding, context);
41621 reveal(pointBox, t('intro.lines.finish'), {duration: 0});
41626 function enterSelect(mode) {
41627 if (mode.id !== 'select') return;
41628 context.map().on('move.intro', null);
41629 context.on('enter.intro', null);
41630 d3.select('#curtain').style('pointer-events', 'all');
41635 function presetCategory() {
41636 timeout(function() {
41637 d3.select('#curtain').style('pointer-events', 'none');
41638 var road = d3.select('.preset-category-road .preset-list-button');
41639 reveal(road.node(), t('intro.lines.road'));
41640 road.one('click.intro', roadCategory);
41644 function roadCategory() {
41645 timeout(function() {
41646 var grid = d3.select('.subgrid');
41647 reveal(grid.node(), t('intro.lines.residential'));
41648 grid.selectAll(':not(.preset-highway-residential) .preset-list-button')
41649 .one('click.intro', retryPreset);
41650 grid.selectAll('.preset-highway-residential .preset-list-button')
41651 .one('click.intro', roadDetails);
41655 // selected wrong road type
41656 function retryPreset() {
41657 timeout(function() {
41658 var preset = d3.select('.entity-editor-pane .preset-list-button');
41659 reveal(preset.node(), t('intro.lines.wrong_preset'));
41660 preset.one('click.intro', presetCategory);
41664 function roadDetails() {
41666 t('intro.lines.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
41667 context.on('exit.intro', event.done);
41672 step.exit = function() {
41673 d3.select(window).on('mousedown.intro', null, true);
41674 d3.select('#curtain').style('pointer-events', 'none');
41675 timeouts.forEach(window.clearTimeout);
41676 context.on('enter.intro', null);
41677 context.on('exit.intro', null);
41678 context.map().on('move.intro', null);
41679 context.history().on('change.intro', null);
41682 return d3.rebind(step, event, 'on');
41684 iD.ui.intro.navigation = function(context, reveal) {
41685 var event = d3.dispatch('done'),
41689 title: 'intro.navigation.title'
41692 function set(f, t) {
41693 timeouts.push(window.setTimeout(f, t));
41696 function eventCancel() {
41697 d3.event.stopPropagation();
41698 d3.event.preventDefault();
41701 step.enter = function() {
41702 var rect = context.surfaceRect(),
41704 left: rect.left + 10,
41705 top: rect.top + 70,
41706 width: rect.width - 70,
41707 height: rect.height - 170
41710 context.map().centerZoom([-85.63591, 41.94285], 19);
41712 reveal(map, t('intro.navigation.drag'));
41714 context.map().on('move.intro', _.debounce(function() {
41715 context.map().on('move.intro', null);
41717 context.on('enter.intro', inspectTownHall);
41720 function townhall() {
41721 var hall = [-85.63645945147184, 41.942986488012565];
41723 var point = context.projection(hall);
41724 if (point[0] < 0 || point[0] > rect.width ||
41725 point[1] < 0 || point[1] > rect.height) {
41726 context.map().center(hall);
41729 var box = iD.ui.intro.pointBox(hall, context);
41730 reveal(box, t('intro.navigation.select'));
41732 context.map().on('move.intro', function() {
41733 var box = iD.ui.intro.pointBox(hall, context);
41734 reveal(box, t('intro.navigation.select'), {duration: 0});
41738 function inspectTownHall(mode) {
41739 if (mode.id !== 'select') return;
41740 context.on('enter.intro', null);
41741 context.map().on('move.intro', null);
41743 reveal('.entity-editor-pane',
41744 t('intro.navigation.pane', { button: iD.ui.intro.icon('#icon-close', 'pre-text') }));
41745 context.on('exit.intro', streetSearch);
41749 function streetSearch() {
41750 context.on('exit.intro', null);
41751 reveal('.search-header input',
41752 t('intro.navigation.search', { name: t('intro.graph.spring_st') }));
41753 d3.select('.search-header input').on('keyup.intro', searchResult);
41756 function searchResult() {
41757 var first = d3.select('.feature-list-item:nth-child(0n+2)'), // skip No Results item
41758 firstName = first.select('.entity-name'),
41759 name = t('intro.graph.spring_st');
41761 if (!firstName.empty() && firstName.text() === name) {
41762 reveal(first.node(), t('intro.navigation.choose', { name: name }));
41763 context.on('exit.intro', selectedStreet);
41764 d3.select('.search-header input')
41765 .on('keydown.intro', eventCancel, true)
41766 .on('keyup.intro', null);
41770 function selectedStreet() {
41771 var springSt = [-85.63585099140167, 41.942506848938926];
41772 context.map().center(springSt);
41773 context.on('exit.intro', event.done);
41775 reveal('.entity-editor-pane',
41776 t('intro.navigation.chosen', {
41777 name: t('intro.graph.spring_st'),
41778 button: iD.ui.intro.icon('#icon-close', 'pre-text')
41784 step.exit = function() {
41785 timeouts.forEach(window.clearTimeout);
41786 context.map().on('move.intro', null);
41787 context.on('enter.intro', null);
41788 context.on('exit.intro', null);
41789 d3.select('.search-header input')
41790 .on('keydown.intro', null)
41791 .on('keyup.intro', null);
41794 return d3.rebind(step, event, 'on');
41796 iD.ui.intro.point = function(context, reveal) {
41797 var event = d3.dispatch('done'),
41801 title: 'intro.points.title'
41804 function setTimeout(f, t) {
41805 timeouts.push(window.setTimeout(f, t));
41808 function eventCancel() {
41809 d3.event.stopPropagation();
41810 d3.event.preventDefault();
41813 step.enter = function() {
41814 context.map().centerZoom([-85.63279, 41.94394], 19);
41815 reveal('button.add-point',
41816 t('intro.points.add', { button: iD.ui.intro.icon('#icon-point', 'pre-text') }),
41817 { tooltipClass: 'intro-points-add' });
41819 var corner = [-85.632481,41.944094];
41821 context.on('enter.intro', addPoint);
41823 function addPoint(mode) {
41824 if (mode.id !== 'add-point') return;
41825 context.on('enter.intro', enterSelect);
41827 var pointBox = iD.ui.intro.pad(corner, 150, context);
41828 reveal(pointBox, t('intro.points.place'));
41830 context.map().on('move.intro', function() {
41831 pointBox = iD.ui.intro.pad(corner, 150, context);
41832 reveal(pointBox, t('intro.points.place'), {duration: 0});
41836 function enterSelect(mode) {
41837 if (mode.id !== 'select') return;
41838 context.map().on('move.intro', null);
41839 context.on('enter.intro', null);
41841 setTimeout(function() {
41842 reveal('.preset-search-input',
41843 t('intro.points.search', {name: context.presets().item('amenity/cafe').name()}));
41844 d3.select('.preset-search-input').on('keyup.intro', keySearch);
41848 function keySearch() {
41849 var first = d3.select('.preset-list-item:first-child');
41850 if (first.classed('preset-amenity-cafe')) {
41851 reveal(first.select('.preset-list-button').node(), t('intro.points.choose'));
41852 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
41853 d3.select('.preset-search-input')
41854 .on('keydown.intro', eventCancel, true)
41855 .on('keyup.intro', null);
41859 function selectedPreset() {
41860 setTimeout(function() {
41861 reveal('.entity-editor-pane', t('intro.points.describe'), {tooltipClass: 'intro-points-describe'});
41862 context.history().on('change.intro', closeEditor);
41863 context.on('exit.intro', selectPoint);
41867 function closeEditor() {
41868 d3.select('.preset-search-input').on('keydown.intro', null);
41869 context.history().on('change.intro', null);
41870 reveal('.entity-editor-pane',
41871 t('intro.points.close', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
41874 function selectPoint() {
41875 context.on('exit.intro', null);
41876 context.history().on('change.intro', null);
41877 context.on('enter.intro', enterReselect);
41879 var pointBox = iD.ui.intro.pad(corner, 150, context);
41880 reveal(pointBox, t('intro.points.reselect'));
41882 context.map().on('move.intro', function() {
41883 pointBox = iD.ui.intro.pad(corner, 150, context);
41884 reveal(pointBox, t('intro.points.reselect'), {duration: 0});
41888 function enterReselect(mode) {
41889 if (mode.id !== 'select') return;
41890 context.map().on('move.intro', null);
41891 context.on('enter.intro', null);
41893 setTimeout(function() {
41894 reveal('.entity-editor-pane',
41895 t('intro.points.fixname', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
41896 context.on('exit.intro', deletePoint);
41900 function deletePoint() {
41901 context.on('exit.intro', null);
41902 context.on('enter.intro', enterDelete);
41904 var pointBox = iD.ui.intro.pad(corner, 150, context);
41905 reveal(pointBox, t('intro.points.reselect_delete'));
41907 context.map().on('move.intro', function() {
41908 pointBox = iD.ui.intro.pad(corner, 150, context);
41909 reveal(pointBox, t('intro.points.reselect_delete'), {duration: 0});
41913 function enterDelete(mode) {
41914 if (mode.id !== 'select') return;
41915 context.map().on('move.intro', null);
41916 context.on('enter.intro', null);
41917 context.on('exit.intro', deletePoint);
41918 context.map().on('move.intro', deletePoint);
41919 context.history().on('change.intro', deleted);
41921 setTimeout(function() {
41922 var node = d3.select('.radial-menu-item-delete').node();
41923 var pointBox = iD.ui.intro.pad(node.getBoundingClientRect(), 50, context);
41925 t('intro.points.delete', { button: iD.ui.intro.icon('#operation-delete', 'pre-text') }));
41929 function deleted(changed) {
41930 if (changed.deleted().length) event.done();
41935 step.exit = function() {
41936 timeouts.forEach(window.clearTimeout);
41937 context.on('exit.intro', null);
41938 context.on('enter.intro', null);
41939 context.map().on('move.intro', null);
41940 context.history().on('change.intro', null);
41941 d3.select('.preset-search-input')
41942 .on('keyup.intro', null)
41943 .on('keydown.intro', null);
41946 return d3.rebind(step, event, 'on');
41948 iD.ui.intro.startEditing = function(context, reveal) {
41949 var event = d3.dispatch('done', 'startEditing'),
41954 title: 'intro.startediting.title'
41957 function timeout(f, t) {
41958 timeouts.push(window.setTimeout(f, t));
41961 step.enter = function() {
41962 reveal('.map-control.help-control',
41963 t('intro.startediting.help', { button: iD.ui.intro.icon('#icon-help', 'pre-text') }));
41965 timeout(function() {
41966 reveal('#bar button.save', t('intro.startediting.save'));
41969 timeout(function() {
41970 reveal('#surface');
41973 timeout(function() {
41974 modal = iD.ui.modal(context.container());
41976 modal.select('.modal')
41977 .attr('class', 'modal-splash modal col6');
41979 modal.selectAll('.close').remove();
41981 var startbutton = modal.select('.content')
41982 .attr('class', 'fillL')
41984 .attr('class', 'modal-section huge-modal-button')
41985 .on('click', function() {
41989 startbutton.append('div')
41990 .attr('class','illustration');
41991 startbutton.append('h2')
41992 .text(t('intro.startediting.start'));
41994 event.startEditing();
41998 step.exit = function() {
41999 if (modal) modal.remove();
42000 timeouts.forEach(window.clearTimeout);
42003 return d3.rebind(step, event, 'on');
42005 iD.presets = function() {
42007 // an iD.presets.Collection with methods for
42008 // loading new data and returning defaults
42010 var all = iD.presets.Collection([]),
42011 defaults = { area: all, line: all, point: all, vertex: all, relation: all },
42014 recent = iD.presets.Collection([]);
42016 // Index of presets by (geometry, tag key).
42025 all.match = function(entity, resolver) {
42026 var geometry = entity.geometry(resolver),
42027 geometryMatches = index[geometry],
42031 for (var k in entity.tags) {
42032 var keyMatches = geometryMatches[k];
42033 if (!keyMatches) continue;
42035 for (var i = 0; i < keyMatches.length; i++) {
42036 var score = keyMatches[i].matchScore(entity);
42037 if (score > best) {
42039 match = keyMatches[i];
42044 return match || all.item(geometry);
42047 // Because of the open nature of tagging, iD will never have a complete
42048 // list of tags used in OSM, so we want it to have logic like "assume
42049 // that a closed way with an amenity tag is an area, unless the amenity
42050 // is one of these specific types". This function computes a structure
42051 // that allows testing of such conditions, based on the presets designated
42052 // as as supporting (or not supporting) the area geometry.
42054 // The returned object L is a whitelist/blacklist of tags. A closed way
42055 // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
42056 // (see `iD.Way#isArea()`). In other words, the keys of L form the whitelist,
42057 // and the subkeys form the blacklist.
42058 all.areaKeys = function() {
42060 ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],
42061 presets = _.reject(all.collection, 'suggestion');
42064 presets.forEach(function(d) {
42065 for (var key in d.tags) break;
42067 if (ignore.indexOf(key) !== -1) return;
42069 if (d.geometry.indexOf('area') !== -1) {
42070 areaKeys[key] = areaKeys[key] || {};
42075 presets.forEach(function(d) {
42076 for (var key in d.tags) break;
42078 if (ignore.indexOf(key) !== -1) return;
42080 var value = d.tags[key];
42081 if (d.geometry.indexOf('area') === -1 &&
42082 d.geometry.indexOf('line') !== -1 &&
42083 key in areaKeys && value !== '*') {
42084 areaKeys[key][value] = true;
42091 all.load = function(d) {
42094 _.forEach(d.fields, function(d, id) {
42095 fields[id] = iD.presets.Field(id, d);
42096 if (d.universal) universal.push(fields[id]);
42101 _.forEach(d.presets, function(d, id) {
42102 all.collection.push(iD.presets.Preset(id, d, fields));
42106 if (d.categories) {
42107 _.forEach(d.categories, function(d, id) {
42108 all.collection.push(iD.presets.Category(id, d, all));
42113 var getItem = _.bind(all.item, all);
42115 area: iD.presets.Collection(d.defaults.area.map(getItem)),
42116 line: iD.presets.Collection(d.defaults.line.map(getItem)),
42117 point: iD.presets.Collection(d.defaults.point.map(getItem)),
42118 vertex: iD.presets.Collection(d.defaults.vertex.map(getItem)),
42119 relation: iD.presets.Collection(d.defaults.relation.map(getItem))
42123 for (var i = 0; i < all.collection.length; i++) {
42124 var preset = all.collection[i],
42125 geometry = preset.geometry;
42127 for (var j = 0; j < geometry.length; j++) {
42128 var g = index[geometry[j]];
42129 for (var k in preset.tags) {
42130 (g[k] = g[k] || []).push(preset);
42138 all.field = function(id) {
42142 all.universal = function() {
42146 all.defaults = function(geometry, n) {
42147 var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
42148 def = _.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
42149 return iD.presets.Collection(_.uniq(rec.concat(def).concat(all.item(geometry))));
42152 all.choose = function(preset) {
42153 if (!preset.isFallback()) {
42154 recent = iD.presets.Collection(_.uniq([preset].concat(recent.collection)));
42161 iD.presets.Category = function(id, category, all) {
42162 category = _.clone(category);
42166 category.members = iD.presets.Collection(category.members.map(function(id) {
42167 return all.item(id);
42170 category.matchGeometry = function(geometry) {
42171 return category.geometry.indexOf(geometry) >= 0;
42174 category.matchScore = function() { return -1; };
42176 category.name = function() {
42177 return t('presets.categories.' + id + '.name', {'default': id});
42180 category.terms = function() {
42186 iD.presets.Collection = function(collection) {
42188 var maxSearchResults = 50,
42189 maxSuggestionResults = 10;
42193 collection: collection,
42195 item: function(id) {
42196 return _.find(collection, function(d) {
42197 return d.id === id;
42201 matchGeometry: function(geometry) {
42202 return iD.presets.Collection(collection.filter(function(d) {
42203 return d.matchGeometry(geometry);
42207 search: function(value, geometry) {
42208 if (!value) return this;
42210 value = value.toLowerCase();
42212 var searchable = _.filter(collection, function(a) {
42213 return a.searchable !== false && a.suggestion !== true;
42215 suggestions = _.filter(collection, function(a) {
42216 return a.suggestion === true;
42219 function leading(a) {
42220 var index = a.indexOf(value);
42221 return index === 0 || a[index - 1] === ' ';
42224 // matches value to preset.name
42225 var leading_name = _.filter(searchable, function(a) {
42226 return leading(a.name().toLowerCase());
42227 }).sort(function(a, b) {
42228 var i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
42229 if (i === 0) return a.name().length - b.name().length;
42233 // matches value to preset.terms values
42234 var leading_terms = _.filter(searchable, function(a) {
42235 return _.some(a.terms() || [], leading);
42238 // matches value to preset.tags values
42239 var leading_tag_values = _.filter(searchable, function(a) {
42240 return _.some(_.without(_.values(a.tags || {}), '*'), leading);
42244 // finds close matches to value in preset.name
42245 var levenstein_name = searchable.map(function(a) {
42248 dist: iD.util.editDistance(value, a.name().toLowerCase())
42250 }).filter(function(a) {
42251 return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
42252 }).sort(function(a, b) {
42253 return a.dist - b.dist;
42254 }).map(function(a) {
42258 // finds close matches to value in preset.terms
42259 var leventstein_terms = _.filter(searchable, function(a) {
42260 return _.some(a.terms() || [], function(b) {
42261 return iD.util.editDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
42265 function suggestionName(name) {
42266 var nameArray = name.split(' - ');
42267 if (nameArray.length > 1) {
42268 name = nameArray.slice(0, nameArray.length-1).join(' - ');
42270 return name.toLowerCase();
42273 var leading_suggestions = _.filter(suggestions, function(a) {
42274 return leading(suggestionName(a.name()));
42275 }).sort(function(a, b) {
42276 a = suggestionName(a.name());
42277 b = suggestionName(b.name());
42278 var i = a.indexOf(value) - b.indexOf(value);
42279 if (i === 0) return a.length - b.length;
42283 var leven_suggestions = suggestions.map(function(a) {
42286 dist: iD.util.editDistance(value, suggestionName(a.name()))
42288 }).filter(function(a) {
42289 return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
42290 }).sort(function(a, b) {
42291 return a.dist - b.dist;
42292 }).map(function(a) {
42296 var other = presets.item(geometry);
42298 var results = leading_name.concat(
42300 leading_tag_values,
42301 leading_suggestions.slice(0, maxSuggestionResults+5),
42304 leven_suggestions.slice(0, maxSuggestionResults)
42305 ).slice(0, maxSearchResults-1);
42307 return iD.presets.Collection(_.uniq(
42308 results.concat(other)
42315 iD.presets.Field = function(id, field) {
42316 field = _.clone(field);
42320 field.matchGeometry = function(geometry) {
42321 return !field.geometry || field.geometry === geometry;
42324 field.t = function(scope, options) {
42325 return t('presets.fields.' + id + '.' + scope, options);
42328 field.label = function() {
42329 return field.t('label', {'default': id});
42332 var placeholder = field.placeholder;
42333 field.placeholder = function() {
42334 return field.t('placeholder', {'default': placeholder});
42339 iD.presets.Preset = function(id, preset, fields) {
42340 preset = _.clone(preset);
42343 preset.fields = (preset.fields || []).map(getFields);
42344 preset.geometry = (preset.geometry || []);
42346 function getFields(f) {
42350 preset.matchGeometry = function(geometry) {
42351 return preset.geometry.indexOf(geometry) >= 0;
42354 var matchScore = preset.matchScore || 1;
42355 preset.matchScore = function(entity) {
42356 var tags = preset.tags,
42359 for (var t in tags) {
42360 if (entity.tags[t] === tags[t]) {
42361 score += matchScore;
42362 } else if (tags[t] === '*' && t in entity.tags) {
42363 score += matchScore / 2;
42372 preset.t = function(scope, options) {
42373 return t('presets.presets.' + id + '.' + scope, options);
42376 var name = preset.name;
42377 preset.name = function() {
42378 if (preset.suggestion) {
42379 id = id.split('/');
42380 id = id[0] + '/' + id[1];
42381 return name + ' - ' + t('presets.presets.' + id + '.name');
42383 return preset.t('name', {'default': name});
42386 preset.terms = function() {
42387 return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
42390 preset.isFallback = function() {
42391 var tagCount = Object.keys(preset.tags).length;
42392 return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
42395 preset.reference = function(geometry) {
42396 var key = Object.keys(preset.tags)[0],
42397 value = preset.tags[key];
42399 if (geometry === 'relation' && key === 'type') {
42400 return { rtype: value };
42401 } else if (value === '*') {
42402 return { key: key };
42404 return { key: key, value: value };
42408 var removeTags = preset.removeTags || preset.tags;
42409 preset.removeTags = function(tags, geometry) {
42410 tags = _.omit(tags, _.keys(removeTags));
42412 for (var f in preset.fields) {
42413 var field = preset.fields[f];
42414 if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
42415 delete tags[field.key];
42423 var applyTags = preset.addTags || preset.tags;
42424 preset.applyTags = function(tags, geometry) {
42427 tags = _.clone(tags);
42429 for (k in applyTags) {
42430 if (applyTags[k] === '*') {
42433 tags[k] = applyTags[k];
42437 // Add area=yes if necessary.
42438 // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
42439 // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
42440 // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
42441 if (geometry === 'area') {
42442 var needsAreaTag = true;
42443 if (preset.geometry.indexOf('line') === -1) {
42444 for (k in applyTags) {
42445 if (k in iD.areaKeys) {
42446 needsAreaTag = false;
42451 if (needsAreaTag) {
42456 for (var f in preset.fields) {
42457 var field = preset.fields[f];
42458 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
42459 tags[field.key] = field.default;
42468 iD.validations = {};
42469 iD.validations.DeprecatedTag = function() {
42471 var validation = function(changes) {
42473 for (var i = 0; i < changes.created.length; i++) {
42474 var change = changes.created[i],
42475 deprecatedTags = change.deprecatedTags();
42477 if (!_.isEmpty(deprecatedTags)) {
42478 var tags = iD.util.tagText({ tags: deprecatedTags });
42480 id: 'deprecated_tags',
42481 message: t('validations.deprecated_tags', { tags: tags }),
42491 iD.validations.ManyDeletions = function() {
42492 var threshold = 100;
42494 var validation = function(changes) {
42496 if (changes.deleted.length > threshold) {
42498 id: 'many_deletions',
42499 message: t('validations.many_deletions', { n: changes.deleted.length })
42507 iD.validations.MissingTag = function() {
42509 // Slightly stricter check than Entity#isUsed (#3091)
42510 function hasTags(entity, graph) {
42511 return _.without(Object.keys(entity.tags), 'area', 'name').length > 0 ||
42512 graph.parentRelations(entity).length > 0;
42515 var validation = function(changes, graph) {
42517 for (var i = 0; i < changes.created.length; i++) {
42518 var change = changes.created[i],
42519 geometry = change.geometry(graph);
42521 if ((geometry === 'point' || geometry === 'line' || geometry === 'area') && !hasTags(change, graph)) {
42524 message: t('validations.untagged_' + geometry),
42525 tooltip: t('validations.untagged_' + geometry + '_tooltip'),
42535 iD.validations.TagSuggestsArea = function() {
42537 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
42538 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
42539 function tagSuggestsArea(tags) {
42540 if (_.isEmpty(tags)) return false;
42542 var presence = ['landuse', 'amenities', 'tourism', 'shop'];
42543 for (var i = 0; i < presence.length; i++) {
42544 if (tags[presence[i]] !== undefined) {
42545 return presence[i] + '=' + tags[presence[i]];
42549 if (tags.building && tags.building === 'yes') return 'building=yes';
42552 var validation = function(changes, graph) {
42554 for (var i = 0; i < changes.created.length; i++) {
42555 var change = changes.created[i],
42556 geometry = change.geometry(graph),
42557 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
42561 id: 'tag_suggests_area',
42562 message: t('validations.tag_suggests_area', { tag: suggestion }),
42573 window.locale = { _current: 'en' };
42575 locale.current = function(_) {
42576 if (!arguments.length) return locale._current;
42577 if (locale[_] !== undefined) locale._current = _;
42578 else if (locale[_.split('-')[0]]) locale._current = _.split('-')[0];
42582 function t(s, o, loc) {
42583 loc = loc || locale._current;
42585 var path = s.split(".").reverse(),
42588 while (rep !== undefined && path.length) rep = rep[path.pop()];
42590 if (rep !== undefined) {
42591 if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
42595 if (loc !== 'en') {
42596 return t(s, o, 'en');
42599 if (o && 'default' in o) {
42600 return o['default'];
42603 var missing = 'Missing ' + loc + ' translation: ' + s;
42604 if (typeof console !== "undefined") console.error(missing);
42608 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":{"id":0},"geometry":{"type":"MultiPolygon","coordinates":[[[[-1.426496,50.639342],[-1.445953,50.648139],[-1.452789,50.654283],[-1.485951,50.669338],[-1.497426,50.672309],[-1.535146,50.669379],[-1.551503,50.665107],[-1.569488,50.658026],[-1.545318,50.686103],[-1.50593,50.707709],[-1.418691,50.733791],[-1.420888,50.730455],[-1.423451,50.7237],[-1.425364,50.72012],[-1.400868,50.721991],[-1.377553,50.734198],[-1.343495,50.761054],[-1.318512,50.772162],[-1.295766,50.773179],[-1.144276,50.733791],[-1.119537,50.734198],[-1.10912,50.732856],[-1.097035,50.726955],[-1.096425,50.724433],[-1.097646,50.71601],[-1.097035,50.713324],[-1.094228,50.712633],[-1.085561,50.714016],[-1.082753,50.713324],[-1.062327,50.692816],[-1.062327,50.685289],[-1.066965,50.685248],[-1.069651,50.683498],[-1.071889,50.680976],[-1.075307,50.678534],[-1.112701,50.671454],[-1.128651,50.666449],[-1.156361,50.650784],[-1.162221,50.645982],[-1.164703,50.640937],[-1.164666,50.639543],[-1.426496,50.639342]]],[[[-7.240314,55.050389],[-7.013736,55.1615],[-6.958913,55.20349],[-6.571562,55.268366],[-6.509633,55.31398],[-6.226158,55.344406],[-6.07105,55.25001],[-5.712696,55.017635],[-5.242021,54.415204],[-5.695554,54.14284],[-5.72473,54.07455],[-6.041633,54.006238],[-6.153953,54.054931],[-6.220539,54.098803],[-6.242502,54.099758],[-6.263661,54.104682],[-6.269887,54.097927],[-6.28465,54.105226],[-6.299585,54.104037],[-6.313796,54.099696],[-6.327128,54.097888],[-6.338962,54.102952],[-6.346662,54.109877],[-6.354827,54.110652],[-6.368108,54.097319],[-6.369348,54.091118],[-6.367643,54.083418],[-6.366919,54.075098],[-6.371157,54.066778],[-6.377513,54.063264],[-6.401026,54.060887],[-6.426761,54.05541],[-6.433892,54.055306],[-6.4403,54.057993],[-6.446243,54.062438],[-6.450222,54.066675],[-6.450894,54.068432],[-6.47854,54.067709],[-6.564013,54.04895],[-6.571868,54.049519],[-6.587164,54.053343],[-6.595071,54.052412],[-6.60029,54.04895],[-6.605217,54.044475],[-6.610987,54.039235],[-6.616465,54.037271],[-6.630624,54.041819],[-6.657289,54.061146],[-6.672534,54.068432],[-6.657082,54.091945],[-6.655791,54.103314],[-6.666436,54.114786],[-6.643957,54.131839],[-6.634552,54.150133],[-6.640339,54.168013],[-6.648448,54.173665],[-6.663025,54.183826],[-6.683954,54.194368],[-6.694651,54.197985],[-6.706537,54.198915],[-6.717234,54.195143],[-6.724779,54.188631],[-6.73284,54.183567],[-6.744777,54.184187],[-6.766481,54.192352],[-6.787824,54.202998],[-6.807358,54.21633],[-6.823946,54.23235],[-6.829733,54.242375],[-6.833196,54.25209],[-6.837743,54.260513],[-6.846683,54.266456],[-6.882185,54.277257],[-6.864667,54.282734],[-6.856657,54.292811],[-6.858414,54.307332],[-6.870015,54.326001],[-6.879705,54.341594],[-6.885957,54.345624],[-6.897895,54.346193],[-6.905956,54.349035],[-6.915051,54.365933],[-6.922028,54.372703],[-6.984091,54.403089],[-7.017836,54.413166],[-7.049255,54.411512],[-7.078504,54.394717],[-7.127028,54.349759],[-7.159894,54.335186],[-7.168059,54.335031],[-7.185629,54.336943],[-7.18947,54.335692],[-7.19245,54.334721],[-7.193949,54.329967],[-7.191468,54.323869],[-7.187644,54.318804],[-7.185009,54.317254],[-7.184647,54.316634],[-7.192399,54.307384],[-7.193691,54.307539],[-7.199168,54.303457],[-7.206661,54.304903],[-7.211467,54.30418],[-7.209038,54.293431],[-7.1755,54.283664],[-7.181495,54.269763],[-7.14589,54.25209],[-7.159739,54.24067],[-7.153331,54.224237],[-7.174725,54.216072],[-7.229502,54.207545],[-7.240871,54.202326],[-7.249088,54.197416],[-7.255496,54.190854],[-7.261128,54.18088],[-7.256322,54.176901],[-7.247021,54.17225],[-7.24578,54.166979],[-7.265366,54.16114],[-7.26087,54.151166],[-7.263505,54.140986],[-7.27074,54.132253],[-7.280042,54.126155],[-7.293788,54.122021],[-7.297353,54.125896],[-7.29632,54.134991],[-7.296423,54.146515],[-7.295028,54.155404],[-7.292134,54.162638],[-7.295545,54.165119],[-7.325982,54.154577],[-7.333165,54.149409],[-7.333165,54.142743],[-7.310324,54.114683],[-7.316489,54.11428],[-7.326964,54.113597],[-7.375488,54.123312],[-7.390216,54.121194],[-7.39466,54.121917],[-7.396624,54.126258],[-7.403962,54.135043],[-7.41223,54.136438],[-7.422255,54.135456],[-7.425769,54.136955],[-7.414659,54.145688],[-7.439619,54.146929],[-7.480753,54.127653],[-7.502302,54.125121],[-7.609014,54.139901],[-7.620796,54.144965],[-7.624052,54.153336],[-7.625706,54.162173],[-7.632682,54.168529],[-7.70477,54.200362],[-7.722599,54.202326],[-7.782078,54.2],[-7.836959,54.204341],[-7.856441,54.211421],[-7.86967,54.226872],[-7.873649,54.271055],[-7.880264,54.287023],[-7.894966,54.293586],[-7.93411,54.297049],[-7.942075,54.298873],[-7.950802,54.300873],[-7.96801,54.31219],[-7.981033,54.326556],[-8.002194,54.357923],[-8.03134,54.358027],[-8.05648,54.365882],[-8.079941,54.380196],[-8.122419,54.415233],[-8.146346,54.430736],[-8.156035,54.439055],[-8.158128,54.447117],[-8.161177,54.454817],[-8.173837,54.461741],[-8.168467,54.463477],[-8.15017,54.46939],[-8.097046,54.478588],[-8.072448,54.487063],[-8.060976,54.493316],[-8.05586,54.497553],[-8.043561,54.512229],[-8.023278,54.529696],[-8.002194,54.543442],[-7.926411,54.533055],[-7.887137,54.532125],[-7.848844,54.54091],[-7.749264,54.596152],[-7.707871,54.604162],[-7.707944,54.604708],[-7.707951,54.604763],[-7.710558,54.624264],[-7.721204,54.625866],[-7.736758,54.619251],[-7.753553,54.614497],[-7.769159,54.618011],[-7.801199,54.634806],[-7.814996,54.639457],[-7.822541,54.638113],[-7.838044,54.63124],[-7.846416,54.631447],[-7.85427,54.636408],[-7.864347,54.649069],[-7.872771,54.652221],[-7.890082,54.655063],[-7.906619,54.661316],[-7.914835,54.671651],[-7.907135,54.686689],[-7.913233,54.688653],[-7.929666,54.696714],[-7.880109,54.711029],[-7.845899,54.731027],[-7.832153,54.730614],[-7.803576,54.716145],[-7.770503,54.706016],[-7.736603,54.707463],[-7.70229,54.718883],[-7.667512,54.738779],[-7.649683,54.744877],[-7.61537,54.739347],[-7.585398,54.744722],[-7.566639,54.738675],[-7.556149,54.738365],[-7.543075,54.741673],[-7.543023,54.743791],[-7.548398,54.747202],[-7.551705,54.754695],[-7.549741,54.779603],[-7.543385,54.793091],[-7.470831,54.845284],[-7.45507,54.863009],[-7.444735,54.884455],[-7.444735,54.894893],[-7.448972,54.920318],[-7.445251,54.932152],[-7.436983,54.938301],[-7.417139,54.943056],[-7.415755,54.944372],[-7.408665,54.951117],[-7.407424,54.959437],[-7.413109,54.984965],[-7.409078,54.992045],[-7.403755,54.99313],[-7.40112,54.994836],[-7.405254,55.003569],[-7.376987,55.02889],[-7.366962,55.035557],[-7.355024,55.040931],[-7.291152,55.046615],[-7.282987,55.051835],[-7.275288,55.058863],[-7.266503,55.065167],[-7.247097,55.069328],[-7.2471,55.069322],[-7.256744,55.050686],[-7.240956,55.050279],[-7.240314,55.050389]]],[[[-13.688588,57.596259],[-13.690419,57.596259],[-13.691314,57.596503],[-13.691314,57.597154],[-13.690419,57.597805],[-13.688588,57.597805],[-13.687652,57.597154],[-13.687652,57.596869],[-13.688588,57.596259]]],[[[-4.839121,54.469789],[-4.979941,54.457977],[-5.343644,54.878637],[-5.308469,55.176452],[-6.272566,55.418443],[-8.690528,57.833706],[-6.344705,59.061083],[-4.204785,58.63305],[-2.31566,60.699068],[-1.695335,60.76432],[-1.58092,60.866001],[-0.17022,60.897204],[-0.800508,59.770037],[-1.292368,57.732574],[-1.850077,55.766368],[-1.73054,55.782219],[1.892395,52.815229],[1.742775,51.364209],[1.080173,50.847526],[0.000774,50.664982],[-0.162997,50.752401],[-0.725152,50.731879],[-0.768853,50.741516],[-0.770985,50.736884],[-0.789947,50.730048],[-0.812815,50.734768],[-0.877742,50.761156],[-0.942879,50.758338],[-0.992581,50.737379],[-1.18513,50.766989],[-1.282741,50.792353],[-1.375004,50.772063],[-1.523427,50.719605],[-1.630649,50.695128],[-1.663617,50.670508],[-1.498021,50.40831],[-4.097427,49.735486],[-6.825199,49.700905],[-5.541541,51.446591],[-6.03361,51.732369],[-4.791746,52.635365],[-4.969244,52.637413],[-5.049473,53.131209],[-4.787393,53.409491],[-4.734148,53.424866],[-4.917096,53.508212],[-4.839121,54.469789]]]]}},{"type":"Feature","properties":{"id":0},"geometry":{"type":"MultiPolygon","coordinates":[[[[-157.018938,19.300864],[-179.437336,27.295312],[-179.480084,28.991459],[-168.707465,26.30325],[-163.107414,24.60499],[-153.841679,20.079306],[-154.233846,19.433391],[-153.61725,18.900587],[-154.429471,18.171036],[-156.780638,18.718492],[-157.018938,19.300864]]],[[[-78.91269,43.037032],[-78.964351,42.976393],[-78.981718,42.979043],[-78.998055,42.991111],[-79.01189,43.004358],[-79.022046,43.010539],[-79.023076,43.017015],[-79.00983,43.050867],[-79.011449,43.065291],[-78.993051,43.066174],[-78.975536,43.069707],[-78.958905,43.070884],[-78.943304,43.065291],[-78.917399,43.058521],[-78.908569,43.049396],[-78.91269,43.037032]]],[[[-123.03529,48.992515],[-123.035308,48.992499],[-123.045277,48.984361],[-123.08849,48.972235],[-123.089345,48.987982],[-123.090484,48.992499],[-123.090488,48.992515],[-123.035306,48.992515],[-123.03529,48.992515]]],[[[-103.837038,29.279906],[-103.864121,29.281366],[-103.928122,29.293019],[-104.01915,29.32033],[-104.057313,29.339037],[-104.105424,29.385675],[-104.139789,29.400584],[-104.161648,29.416759],[-104.194514,29.448927],[-104.212291,29.484661],[-104.218698,29.489829],[-104.227148,29.493033],[-104.251022,29.508588],[-104.267171,29.526571],[-104.292751,29.532824],[-104.320604,29.532255],[-104.338484,29.524013],[-104.349026,29.537578],[-104.430443,29.582795],[-104.437832,29.58543],[-104.444008,29.589203],[-104.448555,29.597678],[-104.452069,29.607109],[-104.455222,29.613387],[-104.469381,29.625402],[-104.516639,29.654315],[-104.530824,29.667906],[-104.535036,29.677802],[-104.535191,29.687853],[-104.537103,29.702116],[-104.543666,29.71643],[-104.561391,29.745421],[-104.570279,29.787511],[-104.583586,29.802575],[-104.601207,29.81477],[-104.619682,29.833064],[-104.623764,29.841487],[-104.637588,29.887996],[-104.656346,29.908201],[-104.660635,29.918433],[-104.663478,29.923084],[-104.676526,29.93683],[-104.680479,29.942308],[-104.682469,29.952126],[-104.680117,29.967784],[-104.680479,29.976466],[-104.699108,30.03145],[-104.701589,30.055324],[-104.698592,30.075271],[-104.684639,30.111135],[-104.680479,30.134131],[-104.67867,30.170356],[-104.681564,30.192939],[-104.695853,30.208441],[-104.715231,30.243995],[-104.724585,30.252211],[-104.742155,30.25986],[-104.74939,30.264459],[-104.761689,30.284199],[-104.774143,30.311588],[-104.788767,30.335927],[-104.807732,30.346418],[-104.8129,30.350707],[-104.814967,30.360577],[-104.816001,30.371997],[-104.818274,30.380524],[-104.824269,30.38719],[-104.83755,30.394063],[-104.844939,30.40104],[-104.853259,30.41215],[-104.855016,30.417473],[-104.853621,30.423984],[-104.852432,30.438867],[-104.854655,30.448737],[-104.864473,30.462018],[-104.866695,30.473025],[-104.865248,30.479898],[-104.859615,30.491112],[-104.859254,30.497261],[-104.863026,30.502377],[-104.879718,30.510852],[-104.882146,30.520929],[-104.884007,30.541858],[-104.886591,30.551883],[-104.898166,30.569401],[-104.928242,30.599529],[-104.93434,30.610536],[-104.941057,30.61405],[-104.972735,30.618029],[-104.98276,30.620716],[-104.989117,30.629553],[-104.991649,30.640301],[-104.992941,30.651464],[-104.995783,30.661747],[-105.008495,30.676992],[-105.027977,30.690117],[-105.049475,30.699264],[-105.06813,30.702675],[-105.087043,30.709806],[-105.133604,30.757917],[-105.140425,30.750476],[-105.153241,30.763188],[-105.157788,30.76572],[-105.160889,30.764118],[-105.162698,30.774919],[-105.167297,30.781171],[-105.17479,30.783962],[-105.185125,30.784634],[-105.195306,30.787941],[-105.204917,30.80241],[-105.2121,30.805718],[-105.21825,30.806803],[-105.229257,30.810214],[-105.232874,30.809128],[-105.239851,30.801532],[-105.243985,30.799103],[-105.249049,30.798845],[-105.259488,30.802979],[-105.265844,30.808405],[-105.270753,30.814348],[-105.277006,30.819412],[-105.334315,30.843803],[-105.363771,30.850366],[-105.376173,30.859565],[-105.41555,30.902456],[-105.496682,30.95651],[-105.530789,30.991701],[-105.555955,31.002605],[-105.565722,31.016661],[-105.578641,31.052163],[-105.59094,31.071438],[-105.605875,31.081928],[-105.623496,31.090351],[-105.643805,31.103684],[-105.668042,31.127869],[-105.675225,31.131951],[-105.692278,31.137635],[-105.76819,31.18001],[-105.777854,31.192722],[-105.78483,31.211016],[-105.861983,31.288376],[-105.880147,31.300881],[-105.896994,31.305997],[-105.897149,31.309511],[-105.908802,31.317004],[-105.928052,31.326461],[-105.934563,31.335504],[-105.941772,31.352351],[-105.948515,31.361239],[-105.961202,31.371006],[-106.004739,31.396948],[-106.021147,31.402167],[-106.046261,31.404648],[-106.065304,31.410952],[-106.099385,31.428884],[-106.141113,31.439167],[-106.164316,31.447797],[-106.174471,31.460251],[-106.209249,31.477305],[-106.215424,31.483919],[-106.21744,31.488725],[-106.218731,31.494616],[-106.222891,31.50459],[-106.232658,31.519938],[-106.274749,31.562622],[-106.286298,31.580141],[-106.312292,31.648612],[-106.331309,31.68215],[-106.35849,31.717548],[-106.39177,31.745919],[-106.428951,31.758476],[-106.473135,31.755065],[-106.492797,31.759044],[-106.501425,31.766344],[-106.506052,31.770258],[-106.517189,31.773824],[-106.558969,31.773876],[-106.584859,31.773927],[-106.610697,31.773979],[-106.636587,31.774082],[-106.662477,31.774134],[-106.688315,31.774237],[-106.714205,31.774237],[-106.740095,31.774289],[-106.765933,31.774392],[-106.791823,31.774444],[-106.817713,31.774496],[-106.843603,31.774547],[-106.869441,31.774599],[-106.895331,31.774702],[-106.921221,31.774702],[-106.947111,31.774754],[-106.973001,31.774857],[-106.998891,31.774909],[-107.02478,31.774961],[-107.05067,31.775013],[-107.076509,31.775064],[-107.102398,31.775168],[-107.128288,31.775168],[-107.154127,31.775219],[-107.180016,31.775374],[-107.205906,31.775374],[-107.231796,31.775426],[-107.257634,31.775478],[-107.283524,31.775529],[-107.309414,31.775633],[-107.335252,31.775684],[-107.361142,31.775788],[-107.387032,31.775788],[-107.412896,31.775839],[-107.438786,31.775943],[-107.464676,31.775994],[-107.490566,31.776098],[-107.516404,31.776149],[-107.542294,31.776201],[-107.568184,31.776253],[-107.594074,31.776304],[-107.619964,31.776408],[-107.645854,31.776459],[-107.671744,31.776459],[-107.697633,31.776563],[-107.723472,31.776614],[-107.749362,31.776666],[-107.775251,31.776718],[-107.801141,31.77677],[-107.82698,31.776873],[-107.852869,31.776925],[-107.878759,31.776925],[-107.904598,31.777028],[-107.930487,31.77708],[-107.956377,31.777131],[-107.982216,31.777183],[-108.008105,31.777235],[-108.033995,31.777338],[-108.059885,31.77739],[-108.085723,31.77739],[-108.111613,31.777545],[-108.137503,31.777545],[-108.163341,31.777648],[-108.189283,31.7777],[-108.215121,31.777751],[-108.215121,31.770723],[-108.215121,31.763695],[-108.215121,31.756667],[-108.215121,31.749639],[-108.215121,31.74256],[-108.215121,31.735583],[-108.215121,31.728555],[-108.215121,31.721476],[-108.215121,31.714396],[-108.215121,31.70742],[-108.215121,31.700392],[-108.215121,31.693312],[-108.215121,31.686284],[-108.215121,31.679256],[-108.215121,31.672176],[-108.21507,31.665148],[-108.215018,31.658172],[-108.215018,31.651092],[-108.215018,31.644064],[-108.215018,31.637036],[-108.215018,31.630008],[-108.215018,31.62298],[-108.215018,31.615952],[-108.215018,31.608873],[-108.215018,31.601845],[-108.215018,31.594817],[-108.215018,31.587789],[-108.215018,31.580761],[-108.215018,31.573733],[-108.215018,31.566653],[-108.215018,31.559625],[-108.214966,31.552597],[-108.214966,31.545569],[-108.214966,31.538489],[-108.214966,31.531461],[-108.214966,31.524485],[-108.214966,31.517405],[-108.214966,31.510378],[-108.214966,31.503401],[-108.214966,31.496322],[-108.214966,31.489242],[-108.214966,31.482214],[-108.214966,31.475238],[-108.214966,31.468158],[-108.214966,31.46113],[-108.214966,31.454102],[-108.214966,31.447074],[-108.214915,31.440046],[-108.214863,31.432966],[-108.214863,31.425938],[-108.214863,31.41891],[-108.214863,31.411882],[-108.214863,31.404803],[-108.214863,31.397826],[-108.214863,31.390798],[-108.214863,31.383719],[-108.214863,31.376639],[-108.214863,31.369663],[-108.214863,31.362635],[-108.214863,31.355555],[-108.214863,31.348527],[-108.214863,31.341551],[-108.214863,31.334471],[-108.214811,31.327443],[-108.257573,31.327391],[-108.300336,31.327391],[-108.34302,31.327391],[-108.385731,31.327391],[-108.428442,31.327391],[-108.471152,31.327391],[-108.513837,31.327391],[-108.556547,31.327391],[-108.59931,31.327391],[-108.64202,31.327391],[-108.684757,31.327391],[-108.727467,31.327391],[-108.770178,31.327391],[-108.812914,31.327391],[-108.855625,31.327391],[-108.898335,31.327391],[-108.941046,31.327391],[-108.968282,31.327391],[-108.983731,31.327391],[-109.026493,31.327391],[-109.04743,31.327391],[-109.069203,31.327391],[-109.111914,31.327391],[-109.154599,31.327391],[-109.197361,31.327391],[-109.240072,31.32734],[-109.282782,31.32734],[-109.325519,31.32734],[-109.368229,31.32734],[-109.410914,31.32734],[-109.45365,31.32734],[-109.496387,31.32734],[-109.539071,31.32734],[-109.581808,31.32734],[-109.624493,31.32734],[-109.667177,31.32734],[-109.709965,31.32734],[-109.75265,31.32734],[-109.795335,31.32734],[-109.838123,31.32734],[-109.880808,31.32734],[-109.923596,31.327288],[-109.96628,31.327236],[-110.008965,31.327236],[-110.051702,31.327236],[-110.094386,31.327236],[-110.137071,31.327236],[-110.179807,31.327236],[-110.222544,31.327236],[-110.265229,31.327236],[-110.308017,31.327236],[-110.350753,31.327236],[-110.39349,31.327236],[-110.436174,31.327236],[-110.478859,31.327236],[-110.521595,31.327236],[-110.56428,31.327236],[-110.606965,31.327236],[-110.649727,31.327236],[-110.692438,31.327236],[-110.7352,31.327236],[-110.777885,31.327236],[-110.820595,31.327236],[-110.863358,31.327236],[-110.906068,31.327236],[-110.948753,31.327185],[-111.006269,31.327185],[-111.067118,31.333644],[-111.094455,31.342532],[-111.145924,31.359069],[-111.197446,31.375554],[-111.248864,31.392142],[-111.300333,31.40873],[-111.351803,31.425318],[-111.403299,31.441855],[-111.454768,31.458339],[-111.506238,31.474979],[-111.915464,31.601431],[-112.324715,31.727987],[-112.733967,31.854543],[-113.143218,31.981046],[-113.552444,32.107602],[-113.961696,32.234132],[-114.370921,32.360687],[-114.780147,32.487243],[-114.816785,32.498534],[-114.819373,32.499363],[-114.822108,32.50024],[-114.809447,32.511324],[-114.795546,32.552226],[-114.794203,32.574111],[-114.802678,32.594497],[-114.786813,32.621033],[-114.781542,32.628061],[-114.758804,32.64483],[-114.751156,32.65222],[-114.739477,32.669066],[-114.731209,32.686636],[-114.723871,32.711519],[-114.724284,32.712835],[-114.724285,32.712836],[-114.764541,32.709839],[-114.838076,32.704206],[-114.911612,32.698703],[-114.985199,32.693122],[-115.058734,32.687567],[-115.13227,32.681986],[-115.205806,32.676456],[-115.27929,32.670823],[-115.352851,32.665346],[-115.426386,32.659765],[-115.499922,32.654209],[-115.573535,32.648654],[-115.647019,32.643073],[-115.720529,32.637518],[-115.794064,32.631963],[-115.8676,32.626408],[-115.941213,32.620827],[-116.014748,32.615271],[-116.088232,32.609664],[-116.161742,32.604161],[-116.235329,32.598554],[-116.308891,32.593025],[-116.382426,32.587469],[-116.455962,32.581888],[-116.529472,32.576333],[-116.603007,32.570804],[-116.676543,32.565223],[-116.750104,32.559667],[-116.82364,32.554086],[-116.897201,32.548531],[-116.970737,32.542976],[-117.044221,32.537421],[-117.125121,32.531669],[-117.125969,32.538258],[-117.239623,32.531308],[-120.274098,32.884264],[-121.652736,34.467248],[-124.367265,37.662798],[-126.739806,41.37928],[-126.996297,45.773888],[-124.770704,48.44258],[-123.734053,48.241906],[-123.1663,48.27837],[-123.193018,48.501035],[-123.176987,48.65482],[-122.912481,48.753561],[-122.899122,48.897797],[-122.837671,48.97502],[-122.743986,48.980582],[-122.753,48.992499],[-122.753012,48.992515],[-122.653258,48.992515],[-122.433375,48.992515],[-122.213517,48.992515],[-121.993763,48.992515],[-121.773958,48.992515],[-121.554152,48.992515],[-121.33432,48.992515],[-121.114515,48.992515],[-95.396937,48.99267],[-95.177106,48.99267],[-95.168527,48.995047],[-95.161887,49.001145],[-95.159329,49.01179],[-95.159665,49.10951],[-95.160027,49.223353],[-95.160337,49.313012],[-95.160569,49.369494],[-95.102821,49.35394],[-94.982518,49.356162],[-94.926087,49.345568],[-94.856195,49.318283],[-94.839142,49.308878],[-94.827256,49.292858],[-94.819892,49.252034],[-94.810358,49.229606],[-94.806121,49.210899],[-94.811185,49.166561],[-94.803743,49.146407],[-94.792039,49.12646],[-94.753772,49.026156],[-94.711217,48.914586],[-94.711734,48.862755],[-94.712147,48.842446],[-94.713284,48.823843],[-94.710907,48.807513],[-94.701786,48.790098],[-94.688893,48.778832],[-94.592852,48.726433],[-94.519161,48.70447],[-94.4795,48.700698],[-94.311577,48.713927],[-94.292586,48.711912],[-94.284034,48.709069],[-94.274499,48.704108],[-94.265482,48.697752],[-94.258454,48.690828],[-94.255767,48.683541],[-94.252459,48.662405],[-94.251038,48.65729],[-94.23215,48.652019],[-94.03485,48.643311],[-93.874885,48.636206],[-93.835741,48.617137],[-93.809386,48.543576],[-93.778664,48.519468],[-93.756779,48.516549],[-93.616297,48.531302],[-93.599889,48.526341],[-93.566584,48.538279],[-93.491756,48.542309],[-93.459924,48.557399],[-93.45225,48.572721],[-93.453774,48.586958],[-93.451475,48.597422],[-93.417316,48.604114],[-93.385716,48.614863],[-93.25774,48.630314],[-93.131701,48.62463],[-92.97972,48.61768],[-92.955588,48.612228],[-92.884197,48.579878],[-92.72555,48.548692],[-92.648604,48.536263],[-92.630181,48.519468],[-92.627468,48.502777],[-92.646743,48.497428],[-92.691366,48.489858],[-92.710641,48.482882],[-92.718909,48.459782],[-92.704052,48.445158],[-92.677129,48.441747],[-92.657053,48.438233],[-92.570521,48.446656],[-92.526932,48.445623],[-92.490629,48.433117],[-92.474532,48.410483],[-92.467581,48.394282],[-92.467064,48.353225],[-92.462465,48.329299],[-92.451381,48.312685],[-92.41823,48.282041],[-92.38464,48.232406],[-92.371851,48.222587],[-92.353815,48.222897],[-92.327874,48.229435],[-92.303663,48.239279],[-92.291029,48.249562],[-92.292062,48.270336],[-92.301416,48.290645],[-92.303095,48.310928],[-92.281598,48.33178],[-92.259118,48.339635],[-92.154732,48.350125],[-92.070499,48.346714],[-92.043421,48.334596],[-92.030114,48.313176],[-92.021355,48.287441],[-92.007997,48.262482],[-91.992158,48.247909],[-91.975492,48.236566],[-91.957302,48.228323],[-91.852244,48.195974],[-91.764988,48.187344],[-91.744137,48.179593],[-91.727575,48.168327],[-91.695509,48.13758],[-91.716438,48.112051],[-91.692512,48.097866],[-91.618615,48.089572],[-91.597479,48.090399],[-91.589676,48.088332],[-91.581098,48.080942],[-91.579806,48.070969],[-91.585129,48.06084],[-91.586989,48.052572],[-91.574845,48.048205],[-91.487098,48.053476],[-91.464722,48.048955],[-91.446274,48.040738],[-91.427929,48.036449],[-91.3654,48.057843],[-91.276362,48.064768],[-91.23807,48.082648],[-91.203963,48.107659],[-91.071103,48.170859],[-91.02816,48.184838],[-91.008109,48.194372],[-90.923153,48.227109],[-90.873802,48.234344],[-90.840678,48.220107],[-90.837939,48.210547],[-90.848843,48.198713],[-90.849721,48.189566],[-90.843003,48.176983],[-90.83427,48.171789],[-90.823883,48.168327],[-90.812307,48.160989],[-90.803057,48.147166],[-90.796701,48.117064],[-90.786469,48.10045],[-90.750347,48.083991],[-90.701307,48.08456],[-90.611079,48.103499],[-90.586843,48.104817],[-90.573872,48.097892],[-90.562194,48.088849],[-90.542014,48.083733],[-90.531601,48.08456],[-90.501887,48.094275],[-90.490493,48.096239],[-90.483465,48.094482],[-90.477858,48.091536],[-90.470623,48.089882],[-90.178625,48.116444],[-90.120386,48.115359],[-90.073257,48.101199],[-90.061036,48.091019],[-90.008222,48.029731],[-89.995329,48.018595],[-89.980317,48.010094],[-89.92045,47.98746],[-89.902441,47.985909],[-89.803454,48.013763],[-89.780975,48.017199],[-89.763302,48.017303],[-89.745964,48.013763],[-89.724596,48.005908],[-89.712788,48.003376],[-89.678656,48.008699],[-89.65659,48.007975],[-89.593105,47.996503],[-89.581753,47.996333],[-89.586724,47.992938],[-89.310872,47.981097],[-89.072861,48.046842],[-88.49789,48.212841],[-88.286621,48.156675],[-85.939935,47.280501],[-84.784644,46.770068],[-84.516909,46.435083],[-84.489712,46.446652],[-84.491052,46.457658],[-84.478301,46.466467],[-84.465408,46.478172],[-84.448096,46.489722],[-84.42324,46.511581],[-84.389702,46.520262],[-84.352469,46.522743],[-84.30534,46.501607],[-84.242011,46.526464],[-84.197285,46.546359],[-84.147676,46.541346],[-84.110443,46.526464],[-84.158812,46.433343],[-84.147676,46.399882],[-84.129046,46.375026],[-84.10543,46.347741],[-84.105944,46.346374],[-84.117195,46.347157],[-84.117489,46.338326],[-84.122361,46.331922],[-84.112061,46.287102],[-84.092672,46.227469],[-84.111983,46.20337],[-84.015118,46.149712],[-83.957038,46.045736],[-83.676821,46.15388],[-83.429449,46.086221],[-83.523049,45.892052],[-83.574563,45.890259],[-82.551615,44.857931],[-82.655591,43.968545],[-82.440632,43.096285],[-82.460131,43.084392],[-82.458894,43.083247],[-82.431813,43.039387],[-82.424748,43.02408],[-82.417242,43.01731],[-82.416369,43.01742],[-82.416412,43.017143],[-82.414603,42.983243],[-82.430442,42.951307],[-82.453179,42.918983],[-82.464781,42.883637],[-82.468036,42.863974],[-82.482325,42.835113],[-82.485271,42.818524],[-82.473618,42.798164],[-82.470982,42.790568],[-82.471344,42.779845],[-82.476951,42.761474],[-82.48341,42.719254],[-82.511264,42.646675],[-82.526224,42.619906],[-82.549246,42.590941],[-82.575833,42.571795],[-82.608467,42.561098],[-82.644331,42.557817],[-82.644698,42.557533],[-82.644932,42.561634],[-82.637132,42.568405],[-82.60902,42.579296],[-82.616673,42.582828],[-82.636985,42.599607],[-82.625357,42.616092],[-82.629331,42.626394],[-82.638751,42.633459],[-82.644344,42.640524],[-82.644166,42.641056],[-82.716083,42.617461],[-82.777592,42.408506],[-82.888693,42.406093],[-82.889991,42.403266],[-82.905739,42.387665],[-82.923842,42.374419],[-82.937972,42.366176],[-82.947686,42.363527],[-82.979624,42.359406],[-83.042618,42.340861],[-83.061899,42.32732],[-83.081622,42.30907],[-83.11342,42.279619],[-83.145306,42.066968],[-83.177398,41.960666],[-83.21512,41.794493],[-82.219051,41.516445],[-80.345329,42.13344],[-80.316455,42.123137],[-79.270266,42.591872],[-79.221058,42.582892],[-78.871842,42.860012],[-78.875011,42.867184],[-78.896205,42.897209],[-78.901651,42.908101],[-78.90901,42.952255],[-78.913426,42.957848],[-78.932118,42.9708],[-78.936386,42.979631],[-78.927997,43.002003],[-78.893114,43.029379],[-78.887963,43.051456],[-78.914897,43.076477],[-79.026167,43.086485],[-79.065231,43.10573],[-79.065273,43.105897],[-79.065738,43.120237],[-79.061423,43.130288],[-79.055583,43.138427],[-79.051604,43.146851],[-79.04933,43.159847],[-79.048607,43.170622],[-79.053775,43.260358],[-79.058425,43.277799],[-79.058631,43.2782],[-78.990696,43.286947],[-78.862059,43.324332],[-78.767813,43.336418],[-78.516117,43.50645],[-76.363317,43.943219],[-76.396746,44.106667],[-76.364697,44.111631],[-76.366146,44.117349],[-76.357462,44.131478],[-76.183493,44.223025],[-76.162644,44.229888],[-76.176117,44.30795],[-76.046414,44.354817],[-75.928746,44.391137],[-75.852508,44.381639],[-75.849095,44.386103],[-75.847623,44.392579],[-75.84674,44.398172],[-75.845415,44.40141],[-75.780803,44.432318],[-75.770205,44.446153],[-75.772266,44.463815],[-75.779184,44.48236],[-75.791496,44.496513],[-75.791183,44.496768],[-75.754622,44.527567],[-75.69969,44.581673],[-75.578199,44.661513],[-75.455958,44.741766],[-75.341831,44.816749],[-75.270233,44.863774],[-75.129647,44.925166],[-75.075594,44.935501],[-75.058721,44.941031],[-75.0149,44.96599],[-74.998647,44.972398],[-74.940201,44.987746],[-74.903744,45.005213],[-74.88651,45.009398],[-74.868474,45.010122],[-74.741557,44.998857],[-74.712961,44.999254],[-74.695875,44.99803],[-74.596114,44.998495],[-74.496352,44.999012],[-74.197146,45.000458],[-71.703551,45.012757],[-71.603816,45.013274],[-71.505848,45.013731],[-71.50408,45.013739],[-71.506613,45.037045],[-71.504752,45.052962],[-71.497259,45.066553],[-71.45659,45.110994],[-71.451215,45.121691],[-71.445996,45.140295],[-71.441604,45.150682],[-71.413026,45.186184],[-71.406567,45.204942],[-71.42269,45.217189],[-71.449045,45.226905],[-71.438813,45.233468],[-71.394888,45.241529],[-71.381245,45.250779],[-71.3521,45.278323],[-71.334323,45.28871],[-71.311534,45.294136],[-71.293396,45.292327],[-71.20937,45.254758],[-71.185133,45.248557],[-71.160329,45.245767],[-71.141725,45.252329],[-71.111029,45.287108],[-71.095242,45.300905],[-71.085553,45.304213],[-71.084952,45.304293],[-71.064211,45.307055],[-71.054418,45.310362],[-71.036667,45.323385],[-71.027598,45.33465],[-71.016539,45.343125],[-70.993155,45.347827],[-70.968118,45.34452],[-70.951608,45.332014],[-70.906908,45.246232],[-70.892412,45.234604],[-70.874351,45.245663],[-70.870605,45.255275],[-70.872491,45.274189],[-70.870243,45.283129],[-70.862621,45.290363],[-70.842389,45.301215],[-70.835258,45.309794],[-70.83208,45.328552],[-70.835465,45.373097],[-70.833837,45.393096],[-70.825982,45.410459],[-70.812986,45.42343],[-70.794873,45.430406],[-70.771877,45.430045],[-70.75255,45.422345],[-70.718004,45.397282],[-70.696739,45.388652],[-70.675785,45.388704],[-70.65359,45.395473],[-70.641316,45.408496],[-70.650257,45.427461],[-70.668162,45.439036],[-70.707385,45.4564],[-70.722836,45.470921],[-70.732009,45.491591],[-70.730329,45.507973],[-70.686792,45.572723],[-70.589614,45.651788],[-70.572406,45.662279],[-70.514735,45.681709],[-70.484763,45.699641],[-70.4728,45.703568],[-70.450424,45.703723],[-70.439132,45.705893],[-70.419315,45.716901],[-70.407351,45.731525],[-70.402442,45.749663],[-70.403941,45.771161],[-70.408282,45.781651],[-70.413682,45.787697],[-70.41717,45.793795],[-70.415232,45.804389],[-70.409935,45.810745],[-70.389807,45.825059],[-70.312654,45.867641],[-70.283173,45.890482],[-70.262528,45.923038],[-70.255939,45.948876],[-70.263148,45.956834],[-70.280434,45.959315],[-70.303947,45.968616],[-70.316298,45.982982],[-70.316892,45.999002],[-70.306143,46.035331],[-70.303637,46.038483],[-70.294309,46.044943],[-70.29201,46.048663],[-70.293017,46.054038],[-70.296092,46.057862],[-70.300795,46.061737],[-70.304774,46.065975],[-70.311362,46.071866],[-70.312629,46.079566],[-70.30033,46.089281],[-70.26444,46.106593],[-70.24948,46.120597],[-70.244002,46.141009],[-70.249247,46.162765],[-70.263329,46.183229],[-70.284801,46.191859],[-70.280899,46.211857],[-70.253407,46.251493],[-70.236173,46.288339],[-70.223693,46.300793],[-70.201886,46.305495],[-70.199509,46.315262],[-70.197028,46.336863],[-70.188398,46.358412],[-70.167418,46.368179],[-70.153052,46.372829],[-70.074323,46.419545],[-70.061817,46.445409],[-70.050086,46.511271],[-70.032723,46.609766],[-70.023628,46.661287],[-70.007763,46.704075],[-69.989961,46.721697],[-69.899708,46.811562],[-69.809403,46.901299],[-69.719099,46.991086],[-69.628794,47.080797],[-69.538464,47.17061],[-69.448159,47.260346],[-69.357906,47.350134],[-69.267628,47.439844],[-69.25091,47.452919],[-69.237268,47.45881],[-69.221972,47.459688],[-69.069655,47.431886],[-69.054023,47.418399],[-69.054333,47.389253],[-69.066193,47.32967],[-69.065134,47.296339],[-69.06356,47.290809],[-69.057486,47.269467],[-69.0402,47.249055],[-68.906229,47.190221],[-68.889718,47.190609],[-68.761819,47.23704],[-68.71779,47.245231],[-68.668801,47.243422],[-68.644203,47.245283],[-68.6256,47.255205],[-68.607926,47.269829],[-68.58524,47.28249],[-68.539662,47.299853],[-68.518009,47.304762],[-68.492016,47.307553],[-68.466746,47.305692],[-68.435327,47.291275],[-68.422563,47.293109],[-68.410212,47.297424],[-68.385614,47.301713],[-68.383392,47.307139],[-68.384839,47.315873],[-68.382049,47.32781],[-68.347839,47.358506],[-68.299728,47.367833],[-68.24645,47.360573],[-68.197047,47.341401],[-68.184335,47.333133],[-68.156068,47.306674],[-68.145061,47.301455],[-68.115398,47.292282],[-68.101446,47.286185],[-68.039382,47.245231],[-67.993184,47.223217],[-67.962436,47.197689],[-67.953703,47.18663],[-67.949982,47.172936],[-67.943419,47.164538],[-67.899132,47.138778],[-67.870607,47.107358],[-67.854742,47.09785],[-67.813556,47.081908],[-67.808699,47.075138],[-67.805185,47.035631],[-67.802549,46.901247],[-67.800017,46.766785],[-67.797433,46.632297],[-67.794849,46.497861],[-67.792317,46.363476],[-67.789733,46.229014],[-67.78715,46.094552],[-67.784566,45.960142],[-67.782757,45.95053],[-67.776556,45.942933],[-67.767461,45.935957],[-67.759658,45.928567],[-67.757849,45.919472],[-67.769425,45.903969],[-67.787356,45.890017],[-67.799242,45.875651],[-67.792627,45.858907],[-67.776091,45.840821],[-67.772835,45.828057],[-67.779863,45.815706],[-67.794126,45.799169],[-67.80627,45.781754],[-67.811127,45.76651],[-67.810816,45.762414],[-67.817811,45.754896],[-67.821785,45.740767],[-67.827673,45.739001],[-67.868884,45.744593],[-67.856815,45.723694],[-67.835768,45.703971],[-67.793821,45.676301],[-67.733034,45.651869],[-67.723173,45.645393],[-67.711546,45.642155],[-67.697564,45.64922],[-67.66695,45.620077],[-67.649435,45.611247],[-67.603073,45.605948],[-67.561862,45.596234],[-67.54052,45.593879],[-67.442056,45.603593],[-67.440939,45.604586],[-67.431306,45.597941],[-67.422107,45.568796],[-67.42619,45.533449],[-67.443036,45.522184],[-67.467531,45.508283],[-67.493214,45.493142],[-67.48231,45.455521],[-67.428825,45.38705],[-67.434561,45.350308],[-67.459056,45.318424],[-67.468668,45.301835],[-67.475024,45.282353],[-67.471303,45.266282],[-67.427585,45.236568],[-67.390533,45.193108],[-67.356272,45.165926],[-67.31922,45.153886],[-67.284648,45.169699],[-67.279584,45.179052],[-67.279222,45.187372],[-67.277207,45.195072],[-67.267336,45.202513],[-67.254986,45.205045],[-67.242428,45.202565],[-67.219071,45.192126],[-67.206166,45.189401],[-67.176015,45.178656],[-67.191274,45.180365],[-67.204376,45.178209],[-67.204724,45.177791],[-67.152423,45.148932],[-67.048033,45.043407],[-66.962727,45.047088],[-66.857192,44.968696],[-66.897268,44.817275],[-67.2159,44.593511],[-67.122366,44.423624],[-67.68447,44.192544],[-67.459678,40.781645],[-76.607854,32.495823],[-76.798479,32.713735],[-78.561892,29.037718],[-78.892446,29.039659],[-79.762295,26.719312],[-80.026352,24.932961],[-82.368794,23.994833],[-83.806281,29.068506],[-87.460772,29.089961],[-87.922646,28.666131],[-90.461001,28.246758],[-91.787336,29.11536],[-93.311871,29.12431],[-96.423449,26.057857],[-97.129057,25.991017],[-97.129509,25.966833],[-97.139358,25.965876],[-97.202171,25.960893],[-97.202176,25.960857],[-97.204941,25.960639],[-97.253051,25.963481],[-97.266358,25.960639],[-97.2692,25.944361],[-97.287649,25.928651],[-97.310981,25.922088],[-97.328447,25.933302],[-97.351107,25.918419],[-97.355112,25.912786],[-97.35227,25.894493],[-97.345165,25.871704],[-97.345733,25.852222],[-97.36599,25.843902],[-97.376015,25.846744],[-97.380124,25.853203],[-97.383121,25.860541],[-97.389891,25.865657],[-97.397823,25.865812],[-97.399476,25.861162],[-97.39989,25.855115],[-97.404179,25.851395],[-97.425418,25.854857],[-97.435727,25.869275],[-97.441309,25.884933],[-97.448259,25.892322],[-97.469421,25.892943],[-97.486319,25.895733],[-97.502209,25.901883],[-97.52027,25.912786],[-97.565177,25.954748],[-97.594322,25.966375],[-97.604787,25.979966],[-97.613055,25.995985],[-97.622641,26.00906],[-97.641451,26.022495],[-97.659874,26.03066],[-97.679614,26.034639],[-97.766948,26.039652],[-97.780306,26.043218],[-97.782321,26.058617],[-97.80201,26.063733],[-97.878181,26.063733],[-97.941666,26.056809],[-97.999233,26.064302],[-98.013057,26.063682],[-98.044166,26.048799],[-98.065457,26.042184],[-98.075146,26.046628],[-98.083311,26.070916],[-98.103103,26.074947],[-98.150232,26.063682],[-98.185062,26.065232],[-98.222656,26.075412],[-98.300429,26.111431],[-98.309809,26.121094],[-98.333037,26.15303],[-98.339264,26.159851],[-98.365774,26.160161],[-98.377272,26.163572],[-98.377272,26.173649],[-98.36934,26.19401],[-98.397193,26.201141],[-98.428845,26.217729],[-98.456544,26.225946],[-98.472383,26.207652],[-98.49295,26.230596],[-98.521527,26.240932],[-98.552791,26.248321],[-98.581627,26.262274],[-98.640564,26.24181],[-98.653663,26.244291],[-98.664696,26.250647],[-98.685289,26.268475],[-98.693325,26.270542],[-98.702239,26.271628],[-98.704255,26.27664],[-98.691465,26.290231],[-98.701413,26.299119],[-98.713169,26.303357],[-98.726217,26.30439],[-98.739911,26.303253],[-98.735932,26.320048],[-98.746397,26.332141],[-98.780839,26.351674],[-98.795851,26.368314],[-98.801329,26.372138],[-98.810295,26.372448],[-98.817323,26.368521],[-98.825023,26.366454],[-98.836081,26.372138],[-98.842334,26.365834],[-98.850835,26.364077],[-98.860524,26.366299],[-98.870214,26.372138],[-98.893029,26.367849],[-98.9299,26.39224],[-98.945377,26.378288],[-98.954136,26.393946],[-98.962844,26.399527],[-98.986951,26.400095],[-99.004056,26.393842],[-99.010515,26.392602],[-99.016432,26.394462],[-99.022995,26.403351],[-99.027878,26.406245],[-99.047645,26.406968],[-99.066351,26.404746],[-99.085498,26.40764],[-99.106427,26.423039],[-99.108907,26.434253],[-99.102525,26.446966],[-99.09374,26.459781],[-99.089373,26.47115],[-99.091492,26.484018],[-99.10299,26.512078],[-99.115108,26.525617],[-99.140946,26.531405],[-99.164873,26.540448],[-99.17128,26.563961],[-99.171548,26.56583],[-99.213953,26.568537],[-99.242801,26.579723],[-99.254575,26.6018],[-99.258844,26.614752],[-99.277683,26.638007],[-99.281951,26.649781],[-99.277389,26.657729],[-99.26635,26.653314],[-99.252662,26.644483],[-99.240299,26.639184],[-99.244861,26.652431],[-99.240299,26.697763],[-99.242507,26.713658],[-99.252368,26.743683],[-99.254575,26.75899],[-99.252368,26.799024],[-99.254575,26.810504],[-99.257666,26.813153],[-99.262229,26.814036],[-99.266497,26.817863],[-99.268263,26.827872],[-99.271649,26.832876],[-99.289458,26.84465],[-99.308444,26.830521],[-99.316539,26.822279],[-99.323457,26.810504],[-99.328166,26.797258],[-99.329197,26.789016],[-99.331699,26.78254],[-99.340383,26.77312],[-99.366728,26.761345],[-99.380269,26.777241],[-99.391896,26.796963],[-99.412207,26.796963],[-99.410883,26.808149],[-99.405437,26.818452],[-99.396606,26.824928],[-99.384979,26.824928],[-99.377178,26.816686],[-99.374823,26.804028],[-99.374234,26.791076],[-99.371291,26.783128],[-99.360694,26.780479],[-99.359369,26.790487],[-99.36452,26.810504],[-99.357897,26.822279],[-99.351274,26.83111],[-99.346123,26.840824],[-99.344062,26.855247],[-99.348772,26.899696],[-99.355101,26.920302],[-99.36452,26.934726],[-99.403377,26.952093],[-99.413974,26.964162],[-99.401758,26.985651],[-99.399991,26.999192],[-99.418831,27.007728],[-99.441938,27.013615],[-99.453271,27.019797],[-99.455332,27.025979],[-99.464751,27.039225],[-99.466959,27.047467],[-99.462544,27.057181],[-99.461635,27.056839],[-99.461728,27.056954],[-99.442039,27.089614],[-99.439404,27.098347],[-99.441419,27.107494],[-99.445734,27.114728],[-99.450178,27.120465],[-99.452452,27.125012],[-99.450333,27.145166],[-99.435786,27.188419],[-99.431988,27.207591],[-99.434029,27.22697],[-99.440902,27.244798],[-99.451832,27.26118],[-99.46612,27.276527],[-99.468963,27.278233],[-99.480409,27.283297],[-99.482941,27.286708],[-99.484879,27.294821],[-99.486584,27.297611],[-99.493199,27.30128],[-99.521362,27.311254],[-99.5148,27.321796],[-99.497591,27.338798],[-99.494026,27.348203],[-99.492889,27.358848],[-99.487721,27.37187],[-99.484621,27.391766],[-99.475706,27.414762],[-99.472916,27.426647],[-99.473639,27.463803],[-99.472916,27.468299],[-99.47643,27.48251],[-99.480409,27.490778],[-99.48829,27.494654],[-99.503689,27.495584],[-99.509503,27.500028],[-99.510071,27.510518],[-99.507074,27.533437],[-99.507203,27.57377],[-99.515006,27.588601],[-99.535031,27.604828],[-99.55503,27.613509],[-99.572264,27.61847],[-99.578232,27.622811],[-99.590247,27.642061],[-99.600169,27.646427],[-99.612442,27.643637],[-99.633526,27.633069],[-99.644869,27.632733],[-99.648642,27.636919],[-99.658693,27.654024],[-99.664739,27.659398],[-99.70037,27.659191],[-99.705692,27.66317],[-99.710674,27.670116],[-99.723056,27.687381],[-99.730652,27.691825],[-99.734037,27.702031],[-99.736311,27.713607],[-99.740445,27.722159],[-99.747344,27.726009],[-99.765198,27.731177],[-99.774577,27.735828],[-99.78685,27.748488],[-99.795428,27.761924],[-99.806963,27.771423],[-99.808167,27.772414],[-99.83292,27.776755],[-99.832971,27.782181],[-99.844779,27.793576],[-99.858241,27.803524],[-99.863357,27.804661],[-99.864727,27.814324],[-99.861858,27.83608],[-99.863357,27.845666],[-99.870928,27.854477],[-99.880204,27.859231],[-99.888007,27.864812],[-99.891288,27.876026],[-99.882684,27.89158],[-99.878808,27.901838],[-99.88134,27.906463],[-99.896766,27.912923],[-99.914336,27.928245],[-99.929916,27.946331],[-99.939683,27.961085],[-99.928289,27.975761],[-99.940717,27.983254],[-99.961852,27.987492],[-99.976606,27.992453],[-99.991127,28.007801],[-100.000584,28.02041],[-100.007457,28.033561],[-100.014123,28.050459],[-100.013503,28.056971],[-100.010506,28.063611],[-100.010196,28.068882],[-100.017585,28.070949],[-100.031538,28.081801],[-100.045077,28.095289],[-100.048023,28.102523],[-100.048901,28.115959],[-100.056498,28.137922],[-100.074895,28.154407],[-100.172873,28.198538],[-100.189203,28.201329],[-100.197626,28.207168],[-100.201192,28.220346],[-100.202949,28.234428],[-100.205946,28.242877],[-100.212819,28.245073],[-100.240724,28.249698],[-100.257932,28.260524],[-100.275089,28.277242],[-100.284339,28.296517],[-100.277931,28.314888],[-100.278551,28.331088],[-100.293899,28.353413],[-100.322631,28.386899],[-100.331675,28.422013],[-100.336326,28.458574],[-100.340201,28.464259],[-100.348315,28.470253],[-100.355549,28.478185],[-100.35679,28.489322],[-100.351622,28.496711],[-100.322631,28.510406],[-100.364024,28.524797],[-100.38423,28.537174],[-100.397769,28.557586],[-100.398751,28.568645],[-100.397097,28.592726],[-100.401438,28.60226],[-100.411463,28.609314],[-100.434821,28.619133],[-100.44619,28.626497],[-100.444898,28.643782],[-100.481381,28.686054],[-100.493939,28.708378],[-100.519054,28.804961],[-100.524996,28.814831],[-100.529285,28.819947],[-100.534453,28.830231],[-100.538639,28.835631],[-100.54515,28.83899],[-100.559671,28.839378],[-100.566234,28.842504],[-100.569696,28.84961],[-100.56334,28.86209],[-100.566234,28.869789],[-100.571763,28.8732],[-100.586543,28.879789],[-100.58954,28.883458],[-100.594966,28.899322],[-100.606955,28.910123],[-100.618841,28.917926],[-100.624318,28.924721],[-100.624783,28.93777],[-100.626696,28.948338],[-100.630778,28.956683],[-100.637909,28.962884],[-100.628918,28.98433],[-100.632793,29.005156],[-100.652224,29.044817],[-100.660854,29.102669],[-100.668967,29.116208],[-100.678165,29.119412],[-100.690826,29.121014],[-100.70204,29.12365],[-100.706846,29.130187],[-100.70974,29.135561],[-100.762501,29.173776],[-100.770098,29.187289],[-100.762088,29.208658],[-100.783172,29.243074],[-100.796143,29.257673],[-100.81609,29.270773],[-100.86389,29.290616],[-100.871797,29.296456],[-100.891227,29.318547],[-100.91474,29.337048],[-100.987397,29.366322],[-100.998301,29.372472],[-101.008068,29.380585],[-101.016232,29.390068],[-101.022175,29.40048],[-101.025948,29.414356],[-101.029617,29.442984],[-101.037782,29.460063],[-101.039026,29.460452],[-101.040188,29.457132],[-101.045487,29.451245],[-101.060205,29.449184],[-101.067711,29.45095],[-101.076101,29.453894],[-101.085962,29.454483],[-101.098031,29.449184],[-101.113043,29.466552],[-101.142774,29.475383],[-101.174124,29.475971],[-101.193699,29.469495],[-101.198703,29.473911],[-101.198851,29.476854],[-101.184132,29.497754],[-101.184868,29.512767],[-101.195171,29.521892],[-101.214157,29.518065],[-101.245213,29.493044],[-101.265818,29.487157],[-101.290545,29.49746],[-101.297315,29.503936],[-101.300995,29.512767],[-101.294372,29.520715],[-101.273177,29.524247],[-101.259195,29.533372],[-101.243888,29.554861],[-101.231966,29.580176],[-101.227845,29.599899],[-101.239178,29.616677],[-101.26052,29.613439],[-101.281272,29.597249],[-101.290545,29.575761],[-101.295255,29.570168],[-101.306146,29.574583],[-101.317626,29.584003],[-101.323955,29.592539],[-101.323661,29.603137],[-101.318804,29.616383],[-101.311445,29.628158],[-101.303497,29.634045],[-101.303669,29.631411],[-101.302727,29.633851],[-101.301073,29.649509],[-101.30978,29.654548],[-101.336239,29.654315],[-101.349029,29.660103],[-101.357684,29.667441],[-101.364351,29.676665],[-101.376624,29.700643],[-101.383368,29.718497],[-101.39962,29.740718],[-101.406545,29.752888],[-101.409309,29.765781],[-101.405098,29.778442],[-101.414012,29.774411],[-101.424218,29.771414],[-101.435096,29.770122],[-101.446103,29.771052],[-101.455689,29.77591],[-101.462433,29.788932],[-101.470908,29.791516],[-101.490286,29.785547],[-101.505763,29.773894],[-101.521809,29.765936],[-101.542893,29.771052],[-101.539689,29.779191],[-101.530516,29.796477],[-101.528604,29.801438],[-101.531912,29.811101],[-101.539172,29.817974],[-101.546458,29.820145],[-101.549766,29.815701],[-101.553977,29.796684],[-101.564907,29.786478],[-101.580281,29.781568],[-101.632216,29.775651],[-101.794531,29.795857],[-101.80298,29.801438],[-101.805978,29.811928],[-101.812695,29.812032],[-101.82409,29.805184],[-101.857602,29.805184],[-101.877524,29.810843],[-101.88742,29.81229],[-101.895455,29.808621],[-101.90238,29.803247],[-101.910881,29.799888],[-101.920157,29.798182],[-101.929613,29.797717],[-101.942662,29.803608],[-101.957054,29.814047],[-101.972246,29.818181],[-101.98793,29.805184],[-102.014595,29.810998],[-102.109344,29.80211],[-102.145647,29.815701],[-102.157248,29.824537],[-102.203679,29.846138],[-102.239775,29.849135],[-102.253444,29.855285],[-102.258276,29.873475],[-102.276181,29.869547],[-102.289023,29.878126],[-102.302175,29.889391],[-102.321011,29.893939],[-102.330235,29.888926],[-102.339769,29.870633],[-102.351061,29.866602],[-102.36323,29.864276],[-102.370723,29.857765],[-102.374547,29.848102],[-102.376589,29.821488],[-102.380051,29.811386],[-102.404132,29.780793],[-102.406096,29.777279],[-102.515288,29.784721],[-102.523066,29.782318],[-102.531127,29.769915],[-102.54154,29.762474],[-102.543349,29.760123],[-102.546578,29.757875],[-102.553141,29.756738],[-102.558309,29.759089],[-102.562882,29.769347],[-102.566758,29.771052],[-102.58531,29.764696],[-102.621225,29.747281],[-102.638743,29.743715],[-102.676054,29.74449],[-102.683469,29.743715],[-102.69104,29.736817],[-102.693624,29.729401],[-102.694709,29.720616],[-102.697758,29.709557],[-102.726748,29.664495],[-102.73127,29.650594],[-102.735507,29.649509],[-102.751656,29.622457],[-102.75176,29.620157],[-102.761346,29.603414],[-102.767598,29.59729],[-102.779665,29.592303],[-102.774084,29.579617],[-102.776461,29.575948],[-102.785892,29.571814],[-102.78075,29.558249],[-102.786512,29.550497],[-102.795478,29.54427],[-102.827311,29.470502],[-102.833951,29.461355],[-102.839067,29.45195],[-102.841134,29.438308],[-102.838705,29.426939],[-102.834984,29.415699],[-102.835191,29.403839],[-102.844545,29.390533],[-102.845578,29.384719],[-102.838033,29.370534],[-102.837672,29.366322],[-102.84656,29.361749],[-102.853872,29.361],[-102.859867,29.361155],[-102.864957,29.359527],[-102.876972,29.350871],[-102.883069,29.343766],[-102.885188,29.333379],[-102.885498,29.314801],[-102.899399,29.276095],[-102.899709,29.2639],[-102.892139,29.254391],[-102.867954,29.240387],[-102.858781,29.229147],[-102.869866,29.224781],[-102.896893,29.220285],[-102.942265,29.190209],[-102.947536,29.182018],[-102.969757,29.192845],[-102.988386,29.177135],[-103.015826,29.126776],[-103.024275,29.116157],[-103.032621,29.110214],[-103.072541,29.091404],[-103.080758,29.085203],[-103.085589,29.07572],[-103.091532,29.057866],[-103.095356,29.060294],[-103.104684,29.057866],[-103.109205,29.023372],[-103.122771,28.996474],[-103.147989,28.985105],[-103.187108,28.990221],[-103.241756,29.003502],[-103.301545,29.002365],[-103.316247,29.010065],[-103.311514,29.026043],[-103.309994,29.031175],[-103.3248,29.026808],[-103.330484,29.023733],[-103.342602,29.041226],[-103.351671,29.039417],[-103.360534,29.029831],[-103.372083,29.023733],[-103.38663,29.028798],[-103.414639,29.052414],[-103.423605,29.057866],[-103.435697,29.061121],[-103.478537,29.08205],[-103.529748,29.126776],[-103.535588,29.135122],[-103.538223,29.142408],[-103.541711,29.148816],[-103.550238,29.154656],[-103.558015,29.156206],[-103.58499,29.154656],[-103.673125,29.173569],[-103.702477,29.187858],[-103.749476,29.222972],[-103.759062,29.226848],[-103.770767,29.229845],[-103.777718,29.235297],[-103.769424,29.257543],[-103.774229,29.267517],[-103.78366,29.274803],[-103.794177,29.277594],[-103.837038,29.279906]]],[[[178.301106,52.056551],[179.595462,52.142083],[179.825447,51.992849],[179.661729,51.485763],[179.723231,51.459963],[179.408066,51.209841],[178.411463,51.523605],[177.698335,51.877899],[177.16784,51.581866],[176.487008,52.175325],[174.484678,52.08716],[172.866263,52.207379],[172.825506,52.716846],[172.747012,52.654022],[172.08261,52.952695],[172.942925,53.183013],[173.029416,52.993628],[173.127208,52.99494],[173.143321,52.990383],[173.175059,52.971747],[173.182932,52.968373],[176.45233,52.628178],[176.468135,52.488358],[177.900385,52.488358],[178.007601,52.179677],[178.301106,52.056551]]],[[[-168.899607,65.747626],[-168.909861,65.739569],[-168.926218,65.739895],[-168.942128,65.74372],[-168.951731,65.75316],[-168.942983,65.764716],[-168.920115,65.768866],[-168.907908,65.768297],[-168.902781,65.761542],[-168.899607,65.747626]]],[[[-131.160718,54.787192],[-132.853508,54.482536],[-134.77719,54.717786],[-142.6966,55.845503],[-142.861997,49.948308],[-155.675916,51.109976],[-164.492732,50.603976],[-164.691217,50.997975],[-171.246993,49.948308],[-171.215436,50.576636],[-173.341669,50.968826],[-173.362022,51.082198],[-177.799603,51.272899],[-179.155463,50.982285],[-179.476076,52.072632],[-177.11459,52.248701],[-177.146284,52.789384],[-174.777218,52.443779],[-174.773743,52.685853],[-173.653194,52.704099],[-173.790528,53.469081],[-171.063371,53.604473],[-170.777733,59.291898],[-174.324884,60.332184],[-171.736408,62.68026],[-172.315705,62.725352],[-171.995091,63.999658],[-168.501424,65.565173],[-168.714145,65.546708],[-168.853077,68.370871],[-161.115601,72.416214],[-146.132257,70.607941],[-140.692512,69.955349],[-141.145395,69.671641],[-141.015207,69.654202],[-141.006459,69.651272],[-141.005564,69.650946],[-141.005549,69.650941],[-141.005471,69.505164],[-141.001208,60.466879],[-141.001156,60.321074],[-140.994929,60.304382],[-140.979555,60.295804],[-140.909146,60.28366],[-140.768457,60.259269],[-140.660505,60.24051],[-140.533743,60.218548],[-140.518705,60.22387],[-140.506664,60.236324],[-140.475323,60.276477],[-140.462791,60.289138],[-140.447805,60.29446],[-140.424111,60.293168],[-140.32497,60.267537],[-140.169243,60.227229],[-140.01579,60.187387],[-139.967757,60.188369],[-139.916933,60.207851],[-139.826318,60.256478],[-139.728417,60.309033],[-139.679816,60.32681],[-139.628346,60.334096],[-139.517965,60.336732],[-139.413992,60.339212],[-139.262193,60.342778],[-139.101608,60.346602],[-139.079465,60.341021],[-139.06869,60.322056],[-139.073186,60.299835],[-139.113468,60.226816],[-139.149615,60.161187],[-139.183231,60.100157],[-139.182146,60.073389],[-139.112305,60.031376],[-139.060207,60.000059],[-139.051611,59.994892],[-139.003759,59.977219],[-138.842425,59.937686],[-138.742586,59.913192],[-138.704888,59.898464],[-138.697188,59.89371],[-138.692098,59.886888],[-138.654349,59.805498],[-138.63745,59.784052],[-138.59921,59.753822],[-138.488881,59.696357],[-138.363617,59.631142],[-138.219543,59.556004],[-138.067614,59.476991],[-137.91057,59.395187],[-137.758305,59.315915],[-137.611363,59.239331],[-137.594181,59.225275],[-137.582088,59.206568],[-137.5493,59.134531],[-137.521007,59.072364],[-137.484394,58.991904],[-137.507752,58.939969],[-137.50876,58.914906],[-137.486875,58.900075],[-137.453466,58.899145],[-137.423106,58.907723],[-137.338098,58.955472],[-137.2819,58.98715],[-137.172346,59.027148],[-137.062367,59.067572],[-137.047109,59.07331],[-136.942282,59.11107],[-136.840816,59.148174],[-136.785496,59.157217],[-136.671911,59.150809],[-136.613491,59.15422],[-136.569489,59.172152],[-136.484791,59.2538],[-136.483551,59.257469],[-136.466549,59.287803],[-136.467092,59.38449],[-136.467557,59.461643],[-136.415958,59.452238],[-136.36684,59.449551],[-136.319995,59.459059],[-136.275036,59.486448],[-136.244728,59.528202],[-136.258474,59.556107],[-136.29935,59.575745],[-136.350329,59.592384],[-136.2585,59.621582],[-136.145406,59.636826],[-136.02686,59.652846],[-135.923818,59.666747],[-135.830955,59.693257],[-135.641251,59.747362],[-135.482759,59.792475],[-135.465137,59.789685],[-135.404392,59.753305],[-135.345791,59.731032],[-135.259879,59.698218],[-135.221897,59.675273],[-135.192028,59.64711],[-135.157792,59.623287],[-135.106684,59.613158],[-135.087874,59.606544],[-135.032942,59.573109],[-135.018524,59.559363],[-135.016198,59.543447],[-135.01948,59.493166],[-135.023252,59.477146],[-135.037489,59.461591],[-135.078598,59.438337],[-135.095754,59.418855],[-134.993254,59.381906],[-135.00483,59.367127],[-135.014441,59.35152],[-135.016198,59.336173],[-134.979973,59.297415],[-134.95783,59.280982],[-134.932431,59.270647],[-134.839465,59.258141],[-134.74345,59.245119],[-134.70552,59.240106],[-134.692084,59.235249],[-134.68286,59.223001],[-134.671439,59.193752],[-134.66038,59.181298],[-134.610771,59.144556],[-134.582788,59.128847],[-134.556717,59.123059],[-134.509072,59.122801],[-134.477575,59.114946],[-134.451013,59.097893],[-134.398019,59.051952],[-134.387167,59.036863],[-134.385591,59.018828],[-134.399389,58.974954],[-134.343423,58.968857],[-134.329651,58.963017],[-134.320039,58.952682],[-134.32314,58.949168],[-134.330323,58.945344],[-134.333036,58.93413],[-134.327403,58.916457],[-134.316939,58.903796],[-134.22219,58.842714],[-134.108838,58.808246],[-133.983109,58.769902],[-133.87123,58.735899],[-133.831129,58.718019],[-133.796402,58.693421],[-133.700077,58.59937],[-133.626283,58.546402],[-133.547063,58.505577],[-133.463089,58.462221],[-133.392241,58.403878],[-133.43012,58.372097],[-133.41503,58.330549],[-133.374567,58.290965],[-133.257262,58.210298],[-133.165588,58.147305],[-133.142127,58.120588],[-133.094843,58.0331],[-133.075154,58.007882],[-132.99335,57.941917],[-132.917153,57.880499],[-132.83212,57.791564],[-132.70944,57.663303],[-132.629057,57.579277],[-132.552447,57.499075],[-132.455735,57.420992],[-132.362304,57.3457],[-132.304684,57.280355],[-132.230994,57.19682],[-132.276366,57.14889],[-132.34122,57.080393],[-132.16229,57.050317],[-132.031859,57.028406],[-132.107384,56.858753],[-131.871558,56.79346],[-131.865874,56.785708],[-131.872411,56.77297],[-131.882617,56.759146],[-131.887966,56.747958],[-131.886028,56.737055],[-131.880705,56.728838],[-131.864789,56.71349],[-131.838976,56.682278],[-131.830424,56.664759],[-131.826574,56.644606],[-131.832103,56.603368],[-131.825592,56.593343],[-131.799108,56.587658],[-131.692293,56.585074],[-131.585891,56.595048],[-131.560363,56.594066],[-131.536437,56.585229],[-131.491659,56.560166],[-131.345699,56.503271],[-131.215604,56.45255],[-131.100546,56.407669],[-131.016934,56.38705],[-130.839089,56.372452],[-130.760334,56.345192],[-130.645768,56.261942],[-130.602256,56.247059],[-130.495518,56.232434],[-130.47229,56.22489],[-130.458053,56.210653],[-130.427926,56.143964],[-130.418159,56.129702],[-130.403974,56.121898],[-130.290311,56.10097],[-130.243156,56.092391],[-130.211246,56.089962],[-130.116756,56.105646],[-130.094328,56.101486],[-130.071539,56.084123],[-130.039319,56.045521],[-130.026632,56.024101],[-130.01901,56.002216],[-130.014695,55.963252],[-130.016788,55.918913],[-130.019612,55.907978],[-130.019618,55.907952],[-130.022817,55.901353],[-130.049387,55.871405],[-130.104726,55.825263],[-130.136627,55.806464],[-130.148834,55.795356],[-130.163482,55.771145],[-130.167307,55.766262],[-130.170806,55.759833],[-130.173655,55.749498],[-130.170806,55.740953],[-130.163808,55.734565],[-130.160064,55.727118],[-130.167388,55.715399],[-130.155914,55.700141],[-130.142893,55.689521],[-130.131825,55.676581],[-130.126454,55.653998],[-130.12857,55.63642],[-130.135121,55.619127],[-130.153147,55.58511],[-130.148671,55.578192],[-130.146881,55.569322],[-130.146962,55.547187],[-130.112172,55.509345],[-130.101674,55.481147],[-130.095082,55.472113],[-130.065419,55.446112],[-130.057525,55.434882],[-130.052561,55.414008],[-130.054311,55.366645],[-130.05012,55.345445],[-130.039296,55.330756],[-129.989247,55.284003],[-130.031239,55.26435],[-130.050038,55.252875],[-130.067494,55.239],[-130.078236,55.233791],[-130.100494,55.230292],[-130.104726,55.225653],[-130.105702,55.211127],[-130.10912,55.200751],[-130.115793,55.191596],[-130.126454,55.180976],[-130.151967,55.163275],[-130.159983,55.153713],[-130.167592,55.129584],[-130.173695,55.117743],[-130.200266,55.104153],[-130.211781,55.084133],[-130.228871,55.04385],[-130.238678,55.03441],[-130.261342,55.022895],[-130.269846,55.016547],[-130.275706,55.006985],[-130.286366,54.983222],[-130.294342,54.971869],[-130.326568,54.952094],[-130.335561,54.938707],[-130.365387,54.907294],[-130.385243,54.896552],[-130.430816,54.881252],[-130.488759,54.844184],[-130.580312,54.806383],[-130.597485,54.803391],[-130.71074,54.733215],[-131.160718,54.787192]]]]}}]},"featureIcons":{"circle-stroked-24":{"x":0,"y":0,"width":24,"height":24},"circle-stroked-18":{"x":24,"y":0,"width":18,"height":18},"circle-stroked-12":{"x":42,"y":0,"width":12,"height":12},"circle-24":{"x":54,"y":0,"width":24,"height":24},"circle-18":{"x":78,"y":0,"width":18,"height":18},"circle-12":{"x":96,"y":0,"width":12,"height":12},"square-stroked-24":{"x":108,"y":0,"width":24,"height":24},"square-stroked-18":{"x":132,"y":0,"width":18,"height":18},"square-stroked-12":{"x":150,"y":0,"width":12,"height":12},"square-24":{"x":162,"y":0,"width":24,"height":24},"square-18":{"x":186,"y":0,"width":18,"height":18},"square-12":{"x":204,"y":0,"width":12,"height":12},"triangle-stroked-24":{"x":216,"y":0,"width":24,"height":24},"triangle-stroked-18":{"x":240,"y":0,"width":18,"height":18},"triangle-stroked-12":{"x":258,"y":0,"width":12,"height":12},"triangle-24":{"x":0,"y":24,"width":24,"height":24},"triangle-18":{"x":24,"y":24,"width":18,"height":18},"triangle-12":{"x":42,"y":24,"width":12,"height":12},"star-stroked-24":{"x":54,"y":24,"width":24,"height":24},"star-stroked-18":{"x":78,"y":24,"width":18,"height":18},"star-stroked-12":{"x":96,"y":24,"width":12,"height":12},"star-24":{"x":108,"y":24,"width":24,"height":24},"star-18":{"x":132,"y":24,"width":18,"height":18},"star-12":{"x":150,"y":24,"width":12,"height":12},"cross-24":{"x":162,"y":24,"width":24,"height":24},"cross-18":{"x":186,"y":24,"width":18,"height":18},"cross-12":{"x":204,"y":24,"width":12,"height":12},"marker-stroked-24":{"x":216,"y":24,"width":24,"height":24},"marker-stroked-18":{"x":240,"y":24,"width":18,"height":18},"marker-stroked-12":{"x":258,"y":24,"width":12,"height":12},"marker-24":{"x":0,"y":48,"width":24,"height":24},"marker-18":{"x":24,"y":48,"width":18,"height":18},"marker-12":{"x":42,"y":48,"width":12,"height":12},"religious-jewish-24":{"x":54,"y":48,"width":24,"height":24},"religious-jewish-18":{"x":78,"y":48,"width":18,"height":18},"religious-jewish-12":{"x":96,"y":48,"width":12,"height":12},"religious-christian-24":{"x":108,"y":48,"width":24,"height":24},"religious-christian-18":{"x":132,"y":48,"width":18,"height":18},"religious-christian-12":{"x":150,"y":48,"width":12,"height":12},"religious-muslim-24":{"x":162,"y":48,"width":24,"height":24},"religious-muslim-18":{"x":186,"y":48,"width":18,"height":18},"religious-muslim-12":{"x":204,"y":48,"width":12,"height":12},"cemetery-24":{"x":216,"y":48,"width":24,"height":24},"cemetery-18":{"x":240,"y":48,"width":18,"height":18},"cemetery-12":{"x":258,"y":48,"width":12,"height":12},"rocket-24":{"x":0,"y":72,"width":24,"height":24},"rocket-18":{"x":24,"y":72,"width":18,"height":18},"rocket-12":{"x":42,"y":72,"width":12,"height":12},"airport-24":{"x":54,"y":72,"width":24,"height":24},"airport-18":{"x":78,"y":72,"width":18,"height":18},"airport-12":{"x":96,"y":72,"width":12,"height":12},"heliport-24":{"x":108,"y":72,"width":24,"height":24},"heliport-18":{"x":132,"y":72,"width":18,"height":18},"heliport-12":{"x":150,"y":72,"width":12,"height":12},"rail-24":{"x":162,"y":72,"width":24,"height":24},"rail-18":{"x":186,"y":72,"width":18,"height":18},"rail-12":{"x":204,"y":72,"width":12,"height":12},"rail-metro-24":{"x":216,"y":72,"width":24,"height":24},"rail-metro-18":{"x":240,"y":72,"width":18,"height":18},"rail-metro-12":{"x":258,"y":72,"width":12,"height":12},"rail-light-24":{"x":0,"y":96,"width":24,"height":24},"rail-light-18":{"x":24,"y":96,"width":18,"height":18},"rail-light-12":{"x":42,"y":96,"width":12,"height":12},"bus-24":{"x":54,"y":96,"width":24,"height":24},"bus-18":{"x":78,"y":96,"width":18,"height":18},"bus-12":{"x":96,"y":96,"width":12,"height":12},"fuel-24":{"x":108,"y":96,"width":24,"height":24},"fuel-18":{"x":132,"y":96,"width":18,"height":18},"fuel-12":{"x":150,"y":96,"width":12,"height":12},"parking-24":{"x":162,"y":96,"width":24,"height":24},"parking-18":{"x":186,"y":96,"width":18,"height":18},"parking-12":{"x":204,"y":96,"width":12,"height":12},"parking-garage-24":{"x":216,"y":96,"width":24,"height":24},"parking-garage-18":{"x":240,"y":96,"width":18,"height":18},"parking-garage-12":{"x":258,"y":96,"width":12,"height":12},"airfield-24":{"x":0,"y":120,"width":24,"height":24},"airfield-18":{"x":24,"y":120,"width":18,"height":18},"airfield-12":{"x":42,"y":120,"width":12,"height":12},"roadblock-24":{"x":54,"y":120,"width":24,"height":24},"roadblock-18":{"x":78,"y":120,"width":18,"height":18},"roadblock-12":{"x":96,"y":120,"width":12,"height":12},"ferry-24":{"x":108,"y":120,"width":24,"height":24},"ferry-18":{"x":132,"y":120,"width":18,"height":18},"ferry-12":{"x":150,"y":120,"width":12,"height":12},"harbor-24":{"x":162,"y":120,"width":24,"height":24},"harbor-18":{"x":186,"y":120,"width":18,"height":18},"harbor-12":{"x":204,"y":120,"width":12,"height":12},"bicycle-24":{"x":216,"y":120,"width":24,"height":24},"bicycle-18":{"x":240,"y":120,"width":18,"height":18},"bicycle-12":{"x":258,"y":120,"width":12,"height":12},"park-24":{"x":0,"y":144,"width":24,"height":24},"park-18":{"x":24,"y":144,"width":18,"height":18},"park-12":{"x":42,"y":144,"width":12,"height":12},"park2-24":{"x":54,"y":144,"width":24,"height":24},"park2-18":{"x":78,"y":144,"width":18,"height":18},"park2-12":{"x":96,"y":144,"width":12,"height":12},"museum-24":{"x":108,"y":144,"width":24,"height":24},"museum-18":{"x":132,"y":144,"width":18,"height":18},"museum-12":{"x":150,"y":144,"width":12,"height":12},"lodging-24":{"x":162,"y":144,"width":24,"height":24},"lodging-18":{"x":186,"y":144,"width":18,"height":18},"lodging-12":{"x":204,"y":144,"width":12,"height":12},"monument-24":{"x":216,"y":144,"width":24,"height":24},"monument-18":{"x":240,"y":144,"width":18,"height":18},"monument-12":{"x":258,"y":144,"width":12,"height":12},"zoo-24":{"x":0,"y":168,"width":24,"height":24},"zoo-18":{"x":24,"y":168,"width":18,"height":18},"zoo-12":{"x":42,"y":168,"width":12,"height":12},"garden-24":{"x":54,"y":168,"width":24,"height":24},"garden-18":{"x":78,"y":168,"width":18,"height":18},"garden-12":{"x":96,"y":168,"width":12,"height":12},"campsite-24":{"x":108,"y":168,"width":24,"height":24},"campsite-18":{"x":132,"y":168,"width":18,"height":18},"campsite-12":{"x":150,"y":168,"width":12,"height":12},"theatre-24":{"x":162,"y":168,"width":24,"height":24},"theatre-18":{"x":186,"y":168,"width":18,"height":18},"theatre-12":{"x":204,"y":168,"width":12,"height":12},"art-gallery-24":{"x":216,"y":168,"width":24,"height":24},"art-gallery-18":{"x":240,"y":168,"width":18,"height":18},"art-gallery-12":{"x":258,"y":168,"width":12,"height":12},"pitch-24":{"x":0,"y":192,"width":24,"height":24},"pitch-18":{"x":24,"y":192,"width":18,"height":18},"pitch-12":{"x":42,"y":192,"width":12,"height":12},"soccer-24":{"x":54,"y":192,"width":24,"height":24},"soccer-18":{"x":78,"y":192,"width":18,"height":18},"soccer-12":{"x":96,"y":192,"width":12,"height":12},"america-football-24":{"x":108,"y":192,"width":24,"height":24},"america-football-18":{"x":132,"y":192,"width":18,"height":18},"america-football-12":{"x":150,"y":192,"width":12,"height":12},"tennis-24":{"x":162,"y":192,"width":24,"height":24},"tennis-18":{"x":186,"y":192,"width":18,"height":18},"tennis-12":{"x":204,"y":192,"width":12,"height":12},"basketball-24":{"x":216,"y":192,"width":24,"height":24},"basketball-18":{"x":240,"y":192,"width":18,"height":18},"basketball-12":{"x":258,"y":192,"width":12,"height":12},"baseball-24":{"x":0,"y":216,"width":24,"height":24},"baseball-18":{"x":24,"y":216,"width":18,"height":18},"baseball-12":{"x":42,"y":216,"width":12,"height":12},"golf-24":{"x":54,"y":216,"width":24,"height":24},"golf-18":{"x":78,"y":216,"width":18,"height":18},"golf-12":{"x":96,"y":216,"width":12,"height":12},"swimming-24":{"x":108,"y":216,"width":24,"height":24},"swimming-18":{"x":132,"y":216,"width":18,"height":18},"swimming-12":{"x":150,"y":216,"width":12,"height":12},"cricket-24":{"x":162,"y":216,"width":24,"height":24},"cricket-18":{"x":186,"y":216,"width":18,"height":18},"cricket-12":{"x":204,"y":216,"width":12,"height":12},"skiing-24":{"x":216,"y":216,"width":24,"height":24},"skiing-18":{"x":240,"y":216,"width":18,"height":18},"skiing-12":{"x":258,"y":216,"width":12,"height":12},"school-24":{"x":0,"y":240,"width":24,"height":24},"school-18":{"x":24,"y":240,"width":18,"height":18},"school-12":{"x":42,"y":240,"width":12,"height":12},"college-24":{"x":54,"y":240,"width":24,"height":24},"college-18":{"x":78,"y":240,"width":18,"height":18},"college-12":{"x":96,"y":240,"width":12,"height":12},"library-24":{"x":108,"y":240,"width":24,"height":24},"library-18":{"x":132,"y":240,"width":18,"height":18},"library-12":{"x":150,"y":240,"width":12,"height":12},"post-24":{"x":162,"y":240,"width":24,"height":24},"post-18":{"x":186,"y":240,"width":18,"height":18},"post-12":{"x":204,"y":240,"width":12,"height":12},"fire-station-24":{"x":216,"y":240,"width":24,"height":24},"fire-station-18":{"x":240,"y":240,"width":18,"height":18},"fire-station-12":{"x":258,"y":240,"width":12,"height":12},"town-hall-24":{"x":0,"y":264,"width":24,"height":24},"town-hall-18":{"x":24,"y":264,"width":18,"height":18},"town-hall-12":{"x":42,"y":264,"width":12,"height":12},"police-24":{"x":54,"y":264,"width":24,"height":24},"police-18":{"x":78,"y":264,"width":18,"height":18},"police-12":{"x":96,"y":264,"width":12,"height":12},"prison-24":{"x":108,"y":264,"width":24,"height":24},"prison-18":{"x":132,"y":264,"width":18,"height":18},"prison-12":{"x":150,"y":264,"width":12,"height":12},"embassy-24":{"x":162,"y":264,"width":24,"height":24},"embassy-18":{"x":186,"y":264,"width":18,"height":18},"embassy-12":{"x":204,"y":264,"width":12,"height":12},"beer-24":{"x":216,"y":264,"width":24,"height":24},"beer-18":{"x":240,"y":264,"width":18,"height":18},"beer-12":{"x":258,"y":264,"width":12,"height":12},"restaurant-24":{"x":0,"y":288,"width":24,"height":24},"restaurant-18":{"x":24,"y":288,"width":18,"height":18},"restaurant-12":{"x":42,"y":288,"width":12,"height":12},"cafe-24":{"x":54,"y":288,"width":24,"height":24},"cafe-18":{"x":78,"y":288,"width":18,"height":18},"cafe-12":{"x":96,"y":288,"width":12,"height":12},"shop-24":{"x":108,"y":288,"width":24,"height":24},"shop-18":{"x":132,"y":288,"width":18,"height":18},"shop-12":{"x":150,"y":288,"width":12,"height":12},"fast-food-24":{"x":162,"y":288,"width":24,"height":24},"fast-food-18":{"x":186,"y":288,"width":18,"height":18},"fast-food-12":{"x":204,"y":288,"width":12,"height":12},"bar-24":{"x":216,"y":288,"width":24,"height":24},"bar-18":{"x":240,"y":288,"width":18,"height":18},"bar-12":{"x":258,"y":288,"width":12,"height":12},"bank-24":{"x":0,"y":312,"width":24,"height":24},"bank-18":{"x":24,"y":312,"width":18,"height":18},"bank-12":{"x":42,"y":312,"width":12,"height":12},"grocery-24":{"x":54,"y":312,"width":24,"height":24},"grocery-18":{"x":78,"y":312,"width":18,"height":18},"grocery-12":{"x":96,"y":312,"width":12,"height":12},"cinema-24":{"x":108,"y":312,"width":24,"height":24},"cinema-18":{"x":132,"y":312,"width":18,"height":18},"cinema-12":{"x":150,"y":312,"width":12,"height":12},"pharmacy-24":{"x":162,"y":312,"width":24,"height":24},"pharmacy-18":{"x":186,"y":312,"width":18,"height":18},"pharmacy-12":{"x":204,"y":312,"width":12,"height":12},"hospital-24":{"x":216,"y":312,"width":24,"height":24},"hospital-18":{"x":240,"y":312,"width":18,"height":18},"hospital-12":{"x":258,"y":312,"width":12,"height":12},"danger-24":{"x":0,"y":336,"width":24,"height":24},"danger-18":{"x":24,"y":336,"width":18,"height":18},"danger-12":{"x":42,"y":336,"width":12,"height":12},"industrial-24":{"x":54,"y":336,"width":24,"height":24},"industrial-18":{"x":78,"y":336,"width":18,"height":18},"industrial-12":{"x":96,"y":336,"width":12,"height":12},"warehouse-24":{"x":108,"y":336,"width":24,"height":24},"warehouse-18":{"x":132,"y":336,"width":18,"height":18},"warehouse-12":{"x":150,"y":336,"width":12,"height":12},"commercial-24":{"x":162,"y":336,"width":24,"height":24},"commercial-18":{"x":186,"y":336,"width":18,"height":18},"commercial-12":{"x":204,"y":336,"width":12,"height":12},"building-24":{"x":216,"y":336,"width":24,"height":24},"building-18":{"x":240,"y":336,"width":18,"height":18},"building-12":{"x":258,"y":336,"width":12,"height":12},"place-of-worship-24":{"x":0,"y":360,"width":24,"height":24},"place-of-worship-18":{"x":24,"y":360,"width":18,"height":18},"place-of-worship-12":{"x":42,"y":360,"width":12,"height":12},"alcohol-shop-24":{"x":54,"y":360,"width":24,"height":24},"alcohol-shop-18":{"x":78,"y":360,"width":18,"height":18},"alcohol-shop-12":{"x":96,"y":360,"width":12,"height":12},"logging-24":{"x":108,"y":360,"width":24,"height":24},"logging-18":{"x":132,"y":360,"width":18,"height":18},"logging-12":{"x":150,"y":360,"width":12,"height":12},"oil-well-24":{"x":162,"y":360,"width":24,"height":24},"oil-well-18":{"x":186,"y":360,"width":18,"height":18},"oil-well-12":{"x":204,"y":360,"width":12,"height":12},"slaughterhouse-24":{"x":216,"y":360,"width":24,"height":24},"slaughterhouse-18":{"x":240,"y":360,"width":18,"height":18},"slaughterhouse-12":{"x":258,"y":360,"width":12,"height":12},"dam-24":{"x":0,"y":384,"width":24,"height":24},"dam-18":{"x":24,"y":384,"width":18,"height":18},"dam-12":{"x":42,"y":384,"width":12,"height":12},"water-24":{"x":54,"y":384,"width":24,"height":24},"water-18":{"x":78,"y":384,"width":18,"height":18},"water-12":{"x":96,"y":384,"width":12,"height":12},"wetland-24":{"x":108,"y":384,"width":24,"height":24},"wetland-18":{"x":132,"y":384,"width":18,"height":18},"wetland-12":{"x":150,"y":384,"width":12,"height":12},"disability-24":{"x":162,"y":384,"width":24,"height":24},"disability-18":{"x":186,"y":384,"width":18,"height":18},"disability-12":{"x":204,"y":384,"width":12,"height":12},"telephone-24":{"x":216,"y":384,"width":24,"height":24},"telephone-18":{"x":240,"y":384,"width":18,"height":18},"telephone-12":{"x":258,"y":384,"width":12,"height":12},"emergency-telephone-24":{"x":0,"y":408,"width":24,"height":24},"emergency-telephone-18":{"x":24,"y":408,"width":18,"height":18},"emergency-telephone-12":{"x":42,"y":408,"width":12,"height":12},"toilets-24":{"x":54,"y":408,"width":24,"height":24},"toilets-18":{"x":78,"y":408,"width":18,"height":18},"toilets-12":{"x":96,"y":408,"width":12,"height":12},"waste-basket-24":{"x":108,"y":408,"width":24,"height":24},"waste-basket-18":{"x":132,"y":408,"width":18,"height":18},"waste-basket-12":{"x":150,"y":408,"width":12,"height":12},"music-24":{"x":162,"y":408,"width":24,"height":24},"music-18":{"x":186,"y":408,"width":18,"height":18},"music-12":{"x":204,"y":408,"width":12,"height":12},"land-use-24":{"x":216,"y":408,"width":24,"height":24},"land-use-18":{"x":240,"y":408,"width":18,"height":18},"land-use-12":{"x":258,"y":408,"width":12,"height":12},"city-24":{"x":0,"y":432,"width":24,"height":24},"city-18":{"x":24,"y":432,"width":18,"height":18},"city-12":{"x":42,"y":432,"width":12,"height":12},"town-24":{"x":54,"y":432,"width":24,"height":24},"town-18":{"x":78,"y":432,"width":18,"height":18},"town-12":{"x":96,"y":432,"width":12,"height":12},"village-24":{"x":108,"y":432,"width":24,"height":24},"village-18":{"x":132,"y":432,"width":18,"height":18},"village-12":{"x":150,"y":432,"width":12,"height":12},"farm-24":{"x":162,"y":432,"width":24,"height":24},"farm-18":{"x":186,"y":432,"width":18,"height":18},"farm-12":{"x":204,"y":432,"width":12,"height":12},"bakery-24":{"x":216,"y":432,"width":24,"height":24},"bakery-18":{"x":240,"y":432,"width":18,"height":18},"bakery-12":{"x":258,"y":432,"width":12,"height":12},"dog-park-24":{"x":0,"y":456,"width":24,"height":24},"dog-park-18":{"x":24,"y":456,"width":18,"height":18},"dog-park-12":{"x":42,"y":456,"width":12,"height":12},"lighthouse-24":{"x":54,"y":456,"width":24,"height":24},"lighthouse-18":{"x":78,"y":456,"width":18,"height":18},"lighthouse-12":{"x":96,"y":456,"width":12,"height":12},"clothing-store-24":{"x":108,"y":456,"width":24,"height":24},"clothing-store-18":{"x":132,"y":456,"width":18,"height":18},"clothing-store-12":{"x":150,"y":456,"width":12,"height":12},"polling-place-24":{"x":162,"y":456,"width":24,"height":24},"polling-place-18":{"x":186,"y":456,"width":18,"height":18},"polling-place-12":{"x":204,"y":456,"width":12,"height":12},"playground-24":{"x":216,"y":456,"width":24,"height":24},"playground-18":{"x":240,"y":456,"width":18,"height":18},"playground-12":{"x":258,"y":456,"width":12,"height":12},"entrance-24":{"x":0,"y":480,"width":24,"height":24},"entrance-18":{"x":24,"y":480,"width":18,"height":18},"entrance-12":{"x":42,"y":480,"width":12,"height":12},"heart-24":{"x":54,"y":480,"width":24,"height":24},"heart-18":{"x":78,"y":480,"width":18,"height":18},"heart-12":{"x":96,"y":480,"width":12,"height":12},"london-underground-24":{"x":108,"y":480,"width":24,"height":24},"london-underground-18":{"x":132,"y":480,"width":18,"height":18},"london-underground-12":{"x":150,"y":480,"width":12,"height":12},"minefield-24":{"x":162,"y":480,"width":24,"height":24},"minefield-18":{"x":186,"y":480,"width":18,"height":18},"minefield-12":{"x":204,"y":480,"width":12,"height":12},"rail-underground-24":{"x":216,"y":480,"width":24,"height":24},"rail-underground-18":{"x":240,"y":480,"width":18,"height":18},"rail-underground-12":{"x":258,"y":480,"width":12,"height":12},"rail-above-24":{"x":0,"y":504,"width":24,"height":24},"rail-above-18":{"x":24,"y":504,"width":18,"height":18},"rail-above-12":{"x":42,"y":504,"width":12,"height":12},"camera-24":{"x":54,"y":504,"width":24,"height":24},"camera-18":{"x":78,"y":504,"width":18,"height":18},"camera-12":{"x":96,"y":504,"width":12,"height":12},"laundry-24":{"x":108,"y":504,"width":24,"height":24},"laundry-18":{"x":132,"y":504,"width":18,"height":18},"laundry-12":{"x":150,"y":504,"width":12,"height":12},"car-24":{"x":162,"y":504,"width":24,"height":24},"car-18":{"x":186,"y":504,"width":18,"height":18},"car-12":{"x":204,"y":504,"width":12,"height":12},"suitcase-24":{"x":216,"y":504,"width":24,"height":24},"suitcase-18":{"x":240,"y":504,"width":18,"height":18},"suitcase-12":{"x":258,"y":504,"width":12,"height":12},"hairdresser-24":{"x":0,"y":528,"width":24,"height":24},"hairdresser-18":{"x":24,"y":528,"width":18,"height":18},"hairdresser-12":{"x":42,"y":528,"width":12,"height":12},"chemist-24":{"x":54,"y":528,"width":24,"height":24},"chemist-18":{"x":78,"y":528,"width":18,"height":18},"chemist-12":{"x":96,"y":528,"width":12,"height":12},"mobilephone-24":{"x":108,"y":528,"width":24,"height":24},"mobilephone-18":{"x":132,"y":528,"width":18,"height":18},"mobilephone-12":{"x":150,"y":528,"width":12,"height":12},"scooter-24":{"x":162,"y":528,"width":24,"height":24},"scooter-18":{"x":186,"y":528,"width":18,"height":18},"scooter-12":{"x":204,"y":528,"width":12,"height":12},"gift-24":{"x":216,"y":528,"width":24,"height":24},"gift-18":{"x":240,"y":528,"width":18,"height":18},"gift-12":{"x":258,"y":528,"width":12,"height":12},"ice-cream-24":{"x":0,"y":552,"width":24,"height":24},"ice-cream-18":{"x":24,"y":552,"width":18,"height":18},"ice-cream-12":{"x":42,"y":552,"width":12,"height":12}},"locales":["af","sq","ar","ar-AA","hy","ast","bn","bs","bg-BG","ca","zh","zh-CN","zh-HK","zh-TW","yue","hr","cs","da","nl","en-GB","eo","et","fi","fr","gl","de","el","hi","hu","is","id","it","ja","kn","ko","lv","lij","lt","no","fa","pl","pt","pt-BR","ro","ru","sc","sr","si","sk","sl","es","sv","tl","ta","te","th","tr","uk","vi"],"en":{"modes":{"add_area":{"title":"Area","description":"Add parks, buildings, lakes or other areas to the map.","tail":"Click on the map to start drawing an area, like a park, lake, or building."},"add_line":{"title":"Line","description":"Add highways, streets, pedestrian paths, canals or other lines to the map.","tail":"Click on the map to start drawing a road, path, or route."},"add_point":{"title":"Point","description":"Add restaurants, monuments, postal boxes or other points to the map.","tail":"Click on the map to add a point."},"browse":{"title":"Browse","description":"Pan and zoom the map."},"draw_area":{"tail":"Click to add nodes to your area. Click the first node to finish the area."},"draw_line":{"tail":"Click to add more nodes to the line. Click on other lines to connect to them, and double-click to end the line."}},"operations":{"add":{"annotation":{"point":"Added a point.","vertex":"Added a node to a way.","relation":"Added a relation."}},"start":{"annotation":{"line":"Started a line.","area":"Started an area."}},"continue":{"key":"A","title":"Continue","description":"Continue this line.","not_eligible":"No line can be continued here.","multiple":"Several lines can be continued here. To choose a line, press the Shift key and click on it to select it.","annotation":{"line":"Continued a line.","area":"Continued an area."}},"cancel_draw":{"annotation":"Canceled drawing."},"change_role":{"annotation":"Changed the role of a relation member."},"change_tags":{"annotation":"Changed tags."},"circularize":{"title":"Circularize","description":{"line":"Make this line circular.","area":"Make this area circular."},"key":"O","annotation":{"line":"Made a line circular.","area":"Made an area circular."},"not_closed":"This can't be made circular because it's not a loop.","too_large":"This can't be made circular because not enough of it is currently visible.","connected_to_hidden":"This can't be made circular because it is connected to a hidden feature."},"orthogonalize":{"title":"Square","description":{"line":"Square the corners of this line.","area":"Square the corners of this area."},"key":"S","annotation":{"line":"Squared the corners of a line.","area":"Squared the corners of an area."},"not_squarish":"This can't be made square because it is not squarish.","too_large":"This can't be made square because not enough of it is currently visible.","connected_to_hidden":"This can't be made square because it is connected to a hidden feature."},"straighten":{"title":"Straighten","description":"Straighten this line.","key":"S","annotation":"Straightened a line.","too_bendy":"This can't be straightened because it bends too much.","connected_to_hidden":"This line can't be straightened because it is connected to a hidden feature."},"delete":{"title":"Delete","description":"Delete object permanently.","annotation":{"point":"Deleted a point.","vertex":"Deleted a node from a way.","line":"Deleted a line.","area":"Deleted an area.","relation":"Deleted a relation.","multiple":"Deleted {n} objects."},"incomplete_relation":"This feature can't be deleted because it hasn't been fully downloaded.","part_of_relation":"This feature can't be deleted because it's part of a larger relation. You must remove it from the relation first.","connected_to_hidden":"This can't be deleted because it is connected to a hidden feature."},"add_member":{"annotation":"Added a member to a relation."},"delete_member":{"annotation":"Removed a member from a relation."},"connect":{"annotation":{"point":"Connected a way to a point.","vertex":"Connected a way to another.","line":"Connected a way to a line.","area":"Connected a way to an area."}},"disconnect":{"title":"Disconnect","description":"Disconnect these lines/areas from each other.","key":"D","annotation":"Disconnected lines/areas.","not_connected":"There aren't enough lines/areas here to disconnect.","connected_to_hidden":"This can't be disconnected because it is connected to a hidden feature.","relation":"This can't be disconnected because it connects members of a relation."},"merge":{"title":"Merge","description":"Merge these features.","key":"C","annotation":"Merged {n} features.","not_eligible":"These features can't be merged.","not_adjacent":"These features can't be merged because they aren't connected.","restriction":"These features can't be merged because at least one is a member of a \"{relation}\" relation.","incomplete_relation":"These features can't be merged because at least one hasn't been fully downloaded.","conflicting_tags":"These features can't be merged because some of their tags have conflicting values."},"move":{"title":"Move","description":"Move this to a different location.","key":"M","annotation":{"point":"Moved a point.","vertex":"Moved a node in a way.","line":"Moved a line.","area":"Moved an area.","multiple":"Moved multiple objects."},"incomplete_relation":"This feature can't be moved because it hasn't been fully downloaded.","too_large":"This can't be moved because not enough of it is currently visible.","connected_to_hidden":"This can't be moved because it is connected to a hidden feature."},"rotate":{"title":"Rotate","description":"Rotate this object around its center point.","key":"R","annotation":{"line":"Rotated a line.","area":"Rotated an area."},"too_large":"This can't be rotated because not enough of it is currently visible.","connected_to_hidden":"This can't be rotated because it is connected to a hidden feature."},"reverse":{"title":"Reverse","description":"Make this line go in the opposite direction.","key":"V","annotation":"Reversed a line."},"split":{"title":"Split","description":{"line":"Split this line into two at this node.","area":"Split the boundary of this area into two.","multiple":"Split the lines/area boundaries at this node into two."},"key":"X","annotation":{"line":"Split a line.","area":"Split an area boundary.","multiple":"Split {n} lines/area boundaries."},"not_eligible":"Lines can't be split at their beginning or end.","multiple_ways":"There are too many lines here to split.","connected_to_hidden":"This can't be split because it is connected to a hidden feature."},"restriction":{"help":{"select":"Click to select a road segment.","toggle":"Click to toggle turn restrictions.","toggle_on":"Click to add a \"{restriction}\" restriction.","toggle_off":"Click to remove the \"{restriction}\" restriction."},"annotation":{"create":"Added a turn restriction","delete":"Deleted a turn restriction"}}},"undo":{"tooltip":"Undo: {action}","nothing":"Nothing to undo."},"redo":{"tooltip":"Redo: {action}","nothing":"Nothing to redo."},"tooltip_keyhint":"Shortcut:","browser_notice":"This editor is supported in Firefox, Chrome, Safari, Opera, and Internet Explorer 11 and above. Please upgrade your browser or use Potlatch 2 to edit the map.","translate":{"translate":"Translate","localized_translation_label":"Multilingual name","localized_translation_language":"Choose language","localized_translation_name":"Name"},"zoom_in_edit":"Zoom in to Edit","logout":"logout","loading_auth":"Connecting to OpenStreetMap...","report_a_bug":"Report a bug","help_translate":"Help translate","feature_info":{"hidden_warning":"{count} hidden features","hidden_details":"These features are currently hidden: {details}"},"status":{"error":"Unable to connect to API.","offline":"The API is offline. Please try editing later.","readonly":"The API is read-only. You will need to wait to save your changes."},"commit":{"title":"Save Changes","description_placeholder":"Brief description of your contributions (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","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"},"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"}};