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'),
6227 var fetcher = function(val, cb) {
6228 cb(data.filter(function(d) {
6232 .indexOf(val.toLowerCase()) !== -1;
6236 var combobox = function(input) {
6238 container = d3.select(document.body)
6239 .selectAll('div.combobox')
6240 .filter(function(d) { return d === input.node(); }),
6241 shown = !container.empty();
6244 .classed('combobox-input', true)
6245 .on('focus.typeahead', focus)
6246 .on('blur.typeahead', blur)
6247 .on('keydown.typeahead', keydown)
6248 .on('keyup.typeahead', keyup)
6249 .on('input.typeahead', change)
6251 var parent = this.parentNode,
6252 sibling = this.nextSibling;
6254 var caret = d3.select(parent).selectAll('.combobox-caret')
6255 .filter(function(d) { return d === input.node(); })
6256 .data([input.node()]);
6258 caret.enter().insert('div', function() { return sibling; })
6259 .attr('class', 'combobox-caret');
6262 .on('mousedown', function () {
6263 // prevent the form element from blurring. it blurs
6265 d3.event.stopPropagation();
6266 d3.event.preventDefault();
6268 input.node().focus();
6277 fetch(value(), render);
6281 window.setTimeout(hide, 150);
6286 container = d3.select(document.body)
6287 .insert('div', ':first-child')
6288 .datum(input.node())
6289 .attr('class', 'combobox')
6291 position: 'absolute',
6295 .on('mousedown', function () {
6296 // prevent moving focus out of the text field
6297 d3.event.preventDefault();
6300 d3.select(document.body)
6301 .on('scroll.combobox', render, true);
6312 d3.select(document.body)
6313 .on('scroll.combobox', null);
6319 function keydown() {
6320 switch (d3.event.keyCode) {
6321 // backspace, delete
6324 input.on('input.typeahead', function() {
6327 var start = input.property('selectionStart');
6328 input.node().setSelectionRange(start, start);
6329 input.on('input.typeahead', change);
6334 container.selectAll('a.selected').each(event.accept);
6338 d3.event.preventDefault();
6343 d3.event.preventDefault();
6348 d3.event.preventDefault();
6351 d3.event.stopPropagation();
6355 switch (d3.event.keyCode) {
6362 container.selectAll('a.selected').each(event.accept);
6369 fetch(value(), function() {
6376 idx = Math.max(Math.min(idx + dir, suggestions.length - 1), 0);
6377 input.property('value', suggestions[idx].value);
6383 var value = input.property('value'),
6384 start = input.property('selectionStart'),
6385 end = input.property('selectionEnd');
6388 value = value.substring(0, start);
6394 function fetch(v, cb) {
6395 fetcher.call(input, v, function(_) {
6401 function autocomplete() {
6408 for (var i = 0; i < suggestions.length; i++) {
6409 if (suggestions[i].value.toLowerCase().indexOf(v.toLowerCase()) === 0) {
6410 var completion = suggestions[i].value;
6412 input.property('value', completion);
6413 input.node().setSelectionRange(v.length, completion.length);
6420 if (suggestions.length >= minItems && document.activeElement === input.node()) {
6427 var options = container
6428 .selectAll('a.combobox-option')
6429 .data(suggestions, function(d) { return d.value; });
6431 options.enter().append('a')
6432 .attr('class', 'combobox-option')
6433 .text(function(d) { return d.value; });
6436 .attr('title', function(d) { return d.title; })
6437 .classed('selected', function(d, i) { return i == idx; })
6438 .on('mouseover', select)
6439 .on('click', accept)
6445 var rect = input.node().getBoundingClientRect();
6448 'left': rect.left + 'px',
6449 'width': rect.width + 'px',
6450 'top': rect.height + rect.top + 'px'
6454 function select(d, i) {
6459 function ensureVisible() {
6460 var node = container.selectAll('a.selected').node();
6461 if (node) node.scrollIntoView();
6464 function accept(d) {
6467 .property('value', d.value)
6474 combobox.fetcher = function(_) {
6475 if (!arguments.length) return fetcher;
6480 combobox.data = function(_) {
6481 if (!arguments.length) return data;
6486 combobox.minItems = function(_) {
6487 if (!arguments.length) return minItems;
6492 return d3.rebind(combobox, event, 'on');
6495 d3.combobox.off = function(input) {
6500 .on('focus.typeahead', null)
6501 .on('blur.typeahead', null)
6502 .on('keydown.typeahead', null)
6503 .on('keyup.typeahead', null)
6504 .on('input.typeahead', null)
6506 d3.select(this.parentNode).selectAll('.combobox-caret')
6507 .filter(function(d) { return d === input.node(); })
6508 .on('mousedown', null);
6511 d3.select(document.body)
6512 .on('scroll.combobox', null);
6514 d3.geo.tile = function() {
6515 var size = [960, 500],
6517 scaleExtent = [0, 20],
6518 translate = [size[0] / 2, size[1] / 2],
6522 return Math.min(scaleExtent[1], Math.max(scaleExtent[0], _));
6526 var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
6527 z0 = bound(Math.round(z + zoomDelta)),
6528 k = Math.pow(2, z - z0 + 8),
6529 origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
6531 cols = d3.range(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
6532 rows = d3.range(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
6534 rows.forEach(function(y) {
6535 cols.forEach(function(x) {
6536 tiles.push([x, y, z0]);
6540 tiles.translate = origin;
6546 tile.scaleExtent = function(_) {
6547 if (!arguments.length) return scaleExtent;
6552 tile.size = function(_) {
6553 if (!arguments.length) return size;
6558 tile.scale = function(_) {
6559 if (!arguments.length) return scale;
6564 tile.translate = function(_) {
6565 if (!arguments.length) return translate;
6570 tile.zoomDelta = function(_) {
6571 if (!arguments.length) return zoomDelta;
6578 d3.jsonp = function (url, callback) {
6580 var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
6582 while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
6586 function create(url) {
6587 var e = url.match(/callback=d3.jsonp.(\w+)/),
6588 c = e ? e[1] : rand();
6589 d3.jsonp[c] = function(data) {
6594 return 'd3.jsonp.' + c;
6597 var cb = create(url),
6598 script = d3.select('head')
6600 .attr('type', 'text/javascript')
6601 .attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
6604 * This code is licensed under the MIT license.
6606 * Copyright © 2013, iD authors.
6608 * Portions copyright © 2011, Keith Cirkel
6609 * See https://github.com/keithamus/jwerty
6612 d3.keybinding = function(namespace) {
6615 function matches(binding, event) {
6616 for (var p in binding.event) {
6617 if (event[p] != binding.event[p])
6621 return (!binding.capture) === (event.eventPhase !== Event.CAPTURING_PHASE);
6624 function capture() {
6625 for (var i = 0; i < bindings.length; i++) {
6626 var binding = bindings[i];
6627 if (matches(binding, d3.event)) {
6634 var tagName = d3.select(d3.event.target).node().tagName;
6635 if (tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA') {
6641 function keybinding(selection) {
6642 selection = selection || d3.select(document);
6643 selection.on('keydown.capture' + namespace, capture, true);
6644 selection.on('keydown.bubble' + namespace, bubble, false);
6648 keybinding.off = function(selection) {
6649 selection = selection || d3.select(document);
6650 selection.on('keydown.capture' + namespace, null);
6651 selection.on('keydown.bubble' + namespace, null);
6655 keybinding.on = function(code, callback, capture) {
6668 code = code.toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
6670 for (var i = 0; i < code.length; i++) {
6671 // Normalise matching errors
6672 if (code[i] === '++') code[i] = '+';
6674 if (code[i] in d3.keybinding.modifierCodes) {
6675 binding.event[d3.keybinding.modifierProperties[d3.keybinding.modifierCodes[code[i]]]] = true;
6676 } else if (code[i] in d3.keybinding.keyCodes) {
6677 binding.event.keyCode = d3.keybinding.keyCodes[code[i]];
6681 bindings.push(binding);
6690 d3.keybinding.modifierCodes = {
6693 // CTRL key, on Mac: ⌃
6695 // ALT key, on Mac: ⌥ (Alt)
6696 '⌥': 18, alt: 18, option: 18,
6697 // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
6698 '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
6701 d3.keybinding.modifierProperties = {
6708 d3.keybinding.keyCodes = {
6709 // Backspace key, on Mac: ⌫ (Backspace)
6710 '⌫': 8, backspace: 8,
6711 // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
6712 '⇥': 9, '⇆': 9, tab: 9,
6714 '↩': 13, 'return': 13, enter: 13, '⌅': 13,
6716 'pause': 19, 'pause-break': 19,
6718 '⇪': 20, caps: 20, 'caps-lock': 20,
6719 // Escape key, on Mac: ⎋, on Windows: Esc
6720 '⎋': 27, escape: 27, esc: 27,
6723 // Page-Up key, or pgup, on Mac: ↖
6724 '↖': 33, pgup: 33, 'page-up': 33,
6725 // Page-Down key, or pgdown, on Mac: ↘
6726 '↘': 34, pgdown: 34, 'page-down': 34,
6727 // END key, on Mac: ⇟
6729 // HOME key, on Mac: ⇞
6731 // Insert key, or ins
6732 ins: 45, insert: 45,
6733 // Delete key, on Mac: ⌦ (Delete)
6734 '⌦': 46, del: 46, 'delete': 46,
6735 // Left Arrow Key, or ←
6736 '←': 37, left: 37, 'arrow-left': 37,
6737 // Up Arrow Key, or ↑
6738 '↑': 38, up: 38, 'arrow-up': 38,
6739 // Right Arrow Key, or →
6740 '→': 39, right: 39, 'arrow-right': 39,
6741 // Up Arrow Key, or ↓
6742 '↓': 40, down: 40, 'arrow-down': 40,
6743 // odities, printing characters that come out wrong:
6746 // Num-Multiply, or *
6747 '*': 106, star: 106, asterisk: 106, multiply: 106,
6749 '+': 107, 'plus': 107,
6750 // Num-Subtract, or -
6751 '-': 109, subtract: 109,
6757 ';': 186, semicolon: 186,
6759 '=': 187, 'equals': 187,
6761 ',': 188, comma: 188,
6763 // Period, or ., or full-stop
6764 '.': 190, period: 190, 'full-stop': 190,
6765 // Slash, or /, or forward-slash
6766 '/': 191, slash: 191, 'forward-slash': 191,
6767 // Tick, or `, or back-quote
6768 '`': 192, tick: 192, 'back-quote': 192,
6769 // Open bracket, or [
6770 '[': 219, 'open-bracket': 219,
6772 '\\': 220, 'back-slash': 220,
6773 // Close backet, or ]
6774 ']': 221, 'close-bracket': 221,
6775 // Apostrophe, or Quote, or '
6776 '\'': 222, quote: 222, apostrophe: 222
6782 d3.keybinding.keyCodes['num-' + n] = i;
6789 d3.keybinding.keyCodes[n] = i;
6796 d3.keybinding.keyCodes['f' + n] = i;
6803 d3.keybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i;
6806 d3.selection.prototype.one = function (type, listener, capture) {
6807 var target = this, typeOnce = type + ".once";
6809 target.on(typeOnce, null);
6810 listener.apply(this, arguments);
6812 target.on(typeOnce, one, capture);
6815 d3.selection.prototype.dimensions = function (dimensions) {
6816 var refresh = (function(node) {
6817 var cr = node.getBoundingClientRect();
6818 prop = [cr.width, cr.height];
6819 this.property('__dimensions__', prop);
6823 var node = this.node();
6825 if (!arguments.length) {
6826 if (!node) return [0,0];
6827 return this.property('__dimensions__') || refresh(node);
6829 if (dimensions === null) {
6830 if (!node) return [0,0];
6831 return refresh(node);
6835 .property('__dimensions__', [dimensions[0], dimensions[1]])
6836 .attr({width: dimensions[0], height: dimensions[1]});
6838 d3.selection.prototype.trigger = function (type) {
6839 this.each(function() {
6840 var evt = document.createEvent('HTMLEvents');
6841 evt.initEvent(type, true, true);
6842 this.dispatchEvent(evt);
6845 // Tooltips and svg mask used to highlight certain features
6846 d3.curtain = function() {
6848 var event = d3.dispatch(),
6853 function curtain(selection) {
6855 surface = selection.append('svg')
6856 .attr('id', 'curtain')
6859 'pointer-events': 'none',
6860 'position': 'absolute',
6865 darkness = surface.append('path')
6869 'class': 'curtain-darkness'
6872 d3.select(window).on('resize.curtain', resize);
6874 tooltip = selection.append('div')
6875 .attr('class', 'tooltip')
6876 .style('z-index', 1002);
6878 tooltip.append('div').attr('class', 'tooltip-arrow');
6879 tooltip.append('div').attr('class', 'tooltip-inner');
6885 width: window.innerWidth,
6886 height: window.innerHeight
6888 curtain.cut(darkness.datum());
6892 curtain.reveal = function(box, text, tooltipclass, duration) {
6893 if (typeof box === 'string') box = d3.select(box).node();
6894 if (box.getBoundingClientRect) box = box.getBoundingClientRect();
6896 curtain.cut(box, duration);
6899 // pseudo markdown bold text hack
6900 var parts = text.split('**');
6901 var html = parts[0] ? '<span>' + parts[0] + '</span>' : '';
6902 if (parts[1]) html += '<span class="bold">' + parts[1] + '</span>';
6904 var dimensions = tooltip.classed('in', true)
6905 .select('.tooltip-inner')
6911 var w = window.innerWidth,
6912 h = window.innerHeight;
6914 if (box.top + box.height < Math.min(100, box.width + box.left)) {
6916 pos = [box.left + box.width / 2 - dimensions[0]/ 2, box.top + box.height];
6918 } else if (box.left + box.width + 300 < window.innerWidth) {
6920 pos = [box.left + box.width, box.top + box.height / 2 - dimensions[1] / 2];
6922 } else if (box.left > 300) {
6924 pos = [box.left - 200, box.top + box.height / 2 - dimensions[1] / 2];
6927 pos = [box.left, box.top + box.height];
6931 Math.min(Math.max(10, pos[0]), w - dimensions[0] - 10),
6932 Math.min(Math.max(10, pos[1]), h - dimensions[1] - 10)
6936 if (duration !== 0 || !tooltip.classed(side)) tooltip.call(iD.ui.Toggle(true));
6939 .style('top', pos[1] + 'px')
6940 .style('left', pos[0] + 'px')
6941 .attr('class', 'curtain-tooltip tooltip in ' + side + ' ' + tooltipclass)
6942 .select('.tooltip-inner')
6946 tooltip.call(iD.ui.Toggle(false));
6950 curtain.cut = function(datum, duration) {
6951 darkness.datum(datum);
6953 (duration === 0 ? darkness : darkness.transition().duration(duration || 600))
6954 .attr('d', function(d) {
6955 var string = "M 0,0 L 0," + window.innerHeight + " L " +
6956 window.innerWidth + "," + window.innerHeight + "L" +
6957 window.innerWidth + ",0 Z";
6959 if (!d) return string;
6960 return string + 'M' +
6961 d.left + ',' + d.top + 'L' +
6962 d.left + ',' + (d.top + d.height) + 'L' +
6963 (d.left + d.width) + ',' + (d.top + d.height) + 'L' +
6964 (d.left + d.width) + ',' + (d.top) + 'Z';
6969 curtain.remove = function() {
6974 return d3.rebind(curtain, event, 'on');
6976 // Like selection.property('value', ...), but avoids no-op value sets,
6977 // which can result in layout/repaint thrashing in some situations.
6978 d3.selection.prototype.value = function(value) {
6979 function d3_selection_value(value) {
6980 function valueNull() {
6984 function valueConstant() {
6985 if (this.value !== value) this.value = value;
6988 function valueFunction() {
6989 var x = value.apply(this, arguments);
6990 if (x == null) delete this.value;
6991 else if (this.value !== x) this.value = x;
6994 return value == null
6995 ? valueNull : (typeof value === "function"
6996 ? valueFunction : valueConstant);
6999 if (!arguments.length) return this.property('value');
7000 return this.each(d3_selection_value(value));
7002 // Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
7003 // Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
7005 // Permission is hereby granted, free of charge, to any person
7006 // obtaining a copy of this software and associated documentation files
7007 // (the "Software"), to deal in the Software without restriction,
7008 // including without limitation the rights to use, copy, modify, merge,
7009 // publish, distribute, sublicense, and/or sell copies of the Software,
7010 // and to permit persons to whom the Software is furnished to do so,
7011 // subject to the following conditions:
7013 // The above copyright notice and this permission notice shall be
7014 // included in all copies or substantial portions of the Software.
7016 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
7017 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
7018 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
7019 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
7020 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
7021 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
7022 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
7025 // source: https://bitbucket.org/lshift/synchrotron/src
7027 Diff3 = (function() {
7031 longest_common_subsequence: function(file1, file2) {
7032 /* Text diff algorithm following Hunt and McIlroy 1976.
7033 * J. W. Hunt and M. D. McIlroy, An algorithm for differential file
7034 * comparison, Bell Telephone Laboratories CSTR #41 (1976)
7035 * http://www.cs.dartmouth.edu/~doug/
7037 * Expects two arrays of strings.
7039 var equivalenceClasses;
7044 var c, i, j, jX, r, s;
7046 equivalenceClasses = {};
7047 for (j = 0; j < file2.length; j++) {
7049 if (equivalenceClasses[line]) {
7050 equivalenceClasses[line].push(j);
7052 equivalenceClasses[line] = [j];
7056 candidates = [{file1index: -1,
7060 for (i = 0; i < file1.length; i++) {
7062 file2indices = equivalenceClasses[line] || [];
7067 for (jX = 0; jX < file2indices.length; jX++) {
7068 j = file2indices[jX];
7070 for (s = 0; s < candidates.length; s++) {
7071 if ((candidates[s].file2index < j) &&
7072 ((s == candidates.length - 1) ||
7073 (candidates[s + 1].file2index > j)))
7077 if (s < candidates.length) {
7078 newCandidate = {file1index: i,
7080 chain: candidates[s]};
7081 if (r == candidates.length) {
7088 if (r == candidates.length) {
7089 break; // no point in examining further (j)s
7097 // At this point, we know the LCS: it's in the reverse of the
7098 // linked-list through .chain of
7099 // candidates[candidates.length - 1].
7101 return candidates[candidates.length - 1];
7104 diff_comm: function(file1, file2) {
7105 // We apply the LCS to build a "comm"-style picture of the
7106 // differences between file1 and file2.
7109 var tail1 = file1.length;
7110 var tail2 = file2.length;
7111 var common = {common: []};
7113 function processCommon() {
7114 if (common.common.length) {
7115 common.common.reverse();
7116 result.push(common);
7117 common = {common: []};
7121 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7123 candidate = candidate.chain)
7125 var different = {file1: [], file2: []};
7127 while (--tail1 > candidate.file1index) {
7128 different.file1.push(file1[tail1]);
7131 while (--tail2 > candidate.file2index) {
7132 different.file2.push(file2[tail2]);
7135 if (different.file1.length || different.file2.length) {
7137 different.file1.reverse();
7138 different.file2.reverse();
7139 result.push(different);
7143 common.common.push(file1[tail1]);
7153 diff_patch: function(file1, file2) {
7154 // We apply the LCD to build a JSON representation of a
7155 // diff(1)-style patch.
7158 var tail1 = file1.length;
7159 var tail2 = file2.length;
7161 function chunkDescription(file, offset, length) {
7163 for (var i = 0; i < length; i++) {
7164 chunk.push(file[offset + i]);
7166 return {offset: offset,
7171 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7173 candidate = candidate.chain)
7175 var mismatchLength1 = tail1 - candidate.file1index - 1;
7176 var mismatchLength2 = tail2 - candidate.file2index - 1;
7177 tail1 = candidate.file1index;
7178 tail2 = candidate.file2index;
7180 if (mismatchLength1 || mismatchLength2) {
7181 result.push({file1: chunkDescription(file1,
7182 candidate.file1index + 1,
7184 file2: chunkDescription(file2,
7185 candidate.file2index + 1,
7194 strip_patch: function(patch) {
7195 // Takes the output of Diff3.diff_patch(), and removes
7196 // information from it. It can still be used by patch(),
7197 // below, but can no longer be inverted.
7199 for (var i = 0; i < patch.length; i++) {
7200 var chunk = patch[i];
7201 newpatch.push({file1: {offset: chunk.file1.offset,
7202 length: chunk.file1.length},
7203 file2: {chunk: chunk.file2.chunk}});
7208 invert_patch: function(patch) {
7209 // Takes the output of Diff3.diff_patch(), and inverts the
7210 // sense of it, so that it can be applied to file2 to give
7211 // file1 rather than the other way around.
7213 for (var i = 0; i < patch.length; i++) {
7214 var chunk = patch[i];
7215 var tmp = chunk.file1;
7216 chunk.file1 = chunk.file2;
7221 patch: function (file, patch) {
7222 // Applies a patch to a file.
7224 // Given file1 and file2, Diff3.patch(file1,
7225 // Diff3.diff_patch(file1, file2)) should give file2.
7228 var commonOffset = 0;
7230 function copyCommon(targetOffset) {
7231 while (commonOffset < targetOffset) {
7232 result.push(file[commonOffset]);
7237 for (var chunkIndex = 0; chunkIndex < patch.length; chunkIndex++) {
7238 var chunk = patch[chunkIndex];
7239 copyCommon(chunk.file1.offset);
7240 for (var lineIndex = 0; lineIndex < chunk.file2.chunk.length; lineIndex++) {
7241 result.push(chunk.file2.chunk[lineIndex]);
7243 commonOffset += chunk.file1.length;
7246 copyCommon(file.length);
7250 diff_indices: function(file1, file2) {
7251 // We apply the LCS to give a simple representation of the
7252 // offsets and lengths of mismatched chunks in the input
7253 // files. This is used by diff3_merge_indices below.
7256 var tail1 = file1.length;
7257 var tail2 = file2.length;
7259 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7261 candidate = candidate.chain)
7263 var mismatchLength1 = tail1 - candidate.file1index - 1;
7264 var mismatchLength2 = tail2 - candidate.file2index - 1;
7265 tail1 = candidate.file1index;
7266 tail2 = candidate.file2index;
7268 if (mismatchLength1 || mismatchLength2) {
7269 result.push({file1: [tail1 + 1, mismatchLength1],
7270 file2: [tail2 + 1, mismatchLength2]});
7278 diff3_merge_indices: function (a, o, b) {
7279 // Given three files, A, O, and B, where both A and B are
7280 // independently derived from O, returns a fairly complicated
7281 // internal representation of merge decisions it's taken. The
7282 // interested reader may wish to consult
7284 // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
7285 // Formal Investigation of Diff3." In Arvind and Prasad,
7286 // editors, Foundations of Software Technology and Theoretical
7287 // Computer Science (FSTTCS), December 2007.
7289 // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
7292 var m1 = Diff3.diff_indices(o, a);
7293 var m2 = Diff3.diff_indices(o, b);
7296 function addHunk(h, side) {
7297 hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]);
7299 for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); }
7300 for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); }
7304 var commonOffset = 0;
7305 function copyCommon(targetOffset) {
7306 if (targetOffset > commonOffset) {
7307 result.push([1, commonOffset, targetOffset - commonOffset]);
7308 commonOffset = targetOffset;
7312 for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {
7313 var firstHunkIndex = hunkIndex;
7314 var hunk = hunks[hunkIndex];
7315 var regionLhs = hunk[0];
7316 var regionRhs = regionLhs + hunk[2];
7317 while (hunkIndex < hunks.length - 1) {
7318 var maybeOverlapping = hunks[hunkIndex + 1];
7319 var maybeLhs = maybeOverlapping[0];
7320 if (maybeLhs > regionRhs) break;
7321 regionRhs = maybeLhs + maybeOverlapping[2];
7325 copyCommon(regionLhs);
7326 if (firstHunkIndex == hunkIndex) {
7327 // The "overlap" was only one hunk long, meaning that
7328 // there's no conflict here. Either a and o were the
7329 // same, or b and o were the same.
7331 result.push([hunk[1], hunk[3], hunk[4]]);
7334 // A proper conflict. Determine the extents of the
7335 // regions involved from a, o and b. Effectively merge
7336 // all the hunks on the left into one giant hunk, and
7337 // do the same for the right; then, correct for skew
7338 // in the regions of o that each side changed, and
7339 // report appropriate spans for the three sides.
7341 0: [a.length, -1, o.length, -1],
7342 2: [b.length, -1, o.length, -1]
7344 for (i = firstHunkIndex; i <= hunkIndex; i++) {
7347 var r = regions[side];
7349 var oRhs = oLhs + hunk[2];
7350 var abLhs = hunk[3];
7351 var abRhs = abLhs + hunk[4];
7352 r[0] = Math.min(abLhs, r[0]);
7353 r[1] = Math.max(abRhs, r[1]);
7354 r[2] = Math.min(oLhs, r[2]);
7355 r[3] = Math.max(oRhs, r[3]);
7357 var aLhs = regions[0][0] + (regionLhs - regions[0][2]);
7358 var aRhs = regions[0][1] + (regionRhs - regions[0][3]);
7359 var bLhs = regions[2][0] + (regionLhs - regions[2][2]);
7360 var bRhs = regions[2][1] + (regionRhs - regions[2][3]);
7363 regionLhs, regionRhs - regionLhs,
7364 bLhs, bRhs - bLhs]);
7366 commonOffset = regionRhs;
7369 copyCommon(o.length);
7373 diff3_merge: function (a, o, b, excludeFalseConflicts) {
7374 // Applies the output of Diff3.diff3_merge_indices to actually
7375 // construct the merged file; the returned result alternates
7376 // between "ok" and "conflict" blocks.
7379 var files = [a, o, b];
7380 var indices = Diff3.diff3_merge_indices(a, o, b);
7383 function flushOk() {
7384 if (okLines.length) {
7385 result.push({ok: okLines});
7389 function pushOk(xs) {
7390 for (var j = 0; j < xs.length; j++) {
7391 okLines.push(xs[j]);
7395 function isTrueConflict(rec) {
7396 if (rec[2] != rec[6]) return true;
7399 for (var j = 0; j < rec[2]; j++) {
7400 if (a[j + aoff] != b[j + boff]) return true;
7405 for (var i = 0; i < indices.length; i++) {
7409 if (excludeFalseConflicts && !isTrueConflict(x)) {
7410 pushOk(files[0].slice(x[1], x[1] + x[2]));
7413 result.push({conflict: {a: a.slice(x[1], x[1] + x[2]),
7415 o: o.slice(x[3], x[3] + x[4]),
7417 b: b.slice(x[5], x[5] + x[6]),
7421 pushOk(files[side].slice(x[1], x[1] + x[2]));
7432 if (typeof module !== 'undefined') module.exports = Diff3;
7433 var JXON = new (function () {
7435 sValueProp = "keyValue", sAttributesProp = "keyAttributes", sAttrPref = "@", /* you can customize these values */
7436 aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
7438 function parseText (sValue) {
7439 if (rIsNull.test(sValue)) { return null; }
7440 if (rIsBool.test(sValue)) { return sValue.toLowerCase() === "true"; }
7441 if (isFinite(sValue)) { return parseFloat(sValue); }
7442 if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
7446 function EmptyTree () { }
7447 EmptyTree.prototype.toString = function () { return "null"; };
7448 EmptyTree.prototype.valueOf = function () { return null; };
7450 function objectify (vValue) {
7451 return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
7454 function createObjTree (oParentNode, nVerb, bFreeze, bNesteAttr) {
7456 nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(),
7457 bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
7460 sProp, vContent, nLength = 0, sCollectedTxt = "",
7461 vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
7464 for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
7465 oNode = oParentNode.childNodes.item(nItem);
7466 if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is "CDATASection" (4) */
7467 else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is "Text" (3) */
7468 else if (oNode.nodeType === 1 && !oNode.prefix) { aCache.push(oNode); } /* nodeType is "Element" (1) */
7472 var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
7474 if (!bHighVerb && (bChildren || bAttributes)) { vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; }
7476 for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
7477 sProp = aCache[nElId].nodeName.toLowerCase();
7478 vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
7479 if (vResult.hasOwnProperty(sProp)) {
7480 if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; }
7481 vResult[sProp].push(vContent);
7483 vResult[sProp] = vContent;
7490 nAttrLen = oParentNode.attributes.length,
7491 sAPrefix = bNesteAttr ? "" : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
7493 for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
7494 oAttrib = oParentNode.attributes.item(nAttrib);
7495 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
7499 if (bFreeze) { Object.freeze(oAttrParent); }
7500 vResult[sAttributesProp] = oAttrParent;
7501 nLength -= nAttrLen - 1;
7505 if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
7506 vResult[sValueProp] = vBuiltVal;
7507 } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
7508 vResult = vBuiltVal;
7511 if (bFreeze && (bHighVerb || nLength > 0)) { Object.freeze(vResult); }
7513 aCache.length = nLevelStart;
7518 function loadObjTree (oXMLDoc, oParentEl, oParentObj) {
7521 if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
7522 oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
7523 } else if (oParentObj.constructor === Date) {
7524 oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
7527 for (var sName in oParentObj) {
7528 vValue = oParentObj[sName];
7529 if (isFinite(sName) || vValue instanceof Function) { continue; } /* verbosity level is 0 */
7530 if (sName === sValueProp) {
7531 if (vValue !== null && vValue !== true) { oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); }
7532 } else if (sName === sAttributesProp) { /* verbosity level is 3 */
7533 for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); }
7534 } else if (sName.charAt(0) === sAttrPref) {
7535 oParentEl.setAttribute(sName.slice(1), vValue);
7536 } else if (vValue.constructor === Array) {
7537 for (var nItem = 0; nItem < vValue.length; nItem++) {
7538 oChild = oXMLDoc.createElement(sName);
7539 loadObjTree(oXMLDoc, oChild, vValue[nItem]);
7540 oParentEl.appendChild(oChild);
7543 oChild = oXMLDoc.createElement(sName);
7544 if (vValue instanceof Object) {
7545 loadObjTree(oXMLDoc, oChild, vValue);
7546 } else if (vValue !== null && vValue !== true) {
7547 oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
7549 oParentEl.appendChild(oChild);
7554 this.build = function (oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
7555 var _nVerb = arguments.length > 1 && typeof nVerbosity === "number" ? nVerbosity & 3 : /* put here the default verbosity level: */ 1;
7556 return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
7559 this.unbuild = function (oObjTree) {
7560 var oNewDoc = document.implementation.createDocument("", "", null);
7561 loadObjTree(oNewDoc, oNewDoc, oObjTree);
7565 this.stringify = function (oObjTree) {
7566 return (new XMLSerializer()).serializeToString(JXON.unbuild(oObjTree));
7569 // var myObject = JXON.build(doc);
7570 // we got our javascript object! try: alert(JSON.stringify(myObject));
7572 // var newDoc = JXON.unbuild(myObject);
7573 // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
7576 * lodash 3.9.3 (Custom Build) <https://lodash.com/>
7577 * Build: `lodash --development --output js/lib/lodash.js include="any,assign,bind,chunk,clone,compact,contains,debounce,difference,each,every,extend,filter,find,first,forEach,forOwn,groupBy,indexOf,intersection,isEmpty,isEqual,isFunction,keys,last,map,omit,pairs,pluck,reject,some,throttle,union,uniq,unique,values,without,flatten,value,chain,cloneDeep,merge,pick,reduce" exports="global,node"`
7578 * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
7579 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
7580 * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
7581 * Available under MIT license <https://lodash.com/license>
7585 /** Used as a safe reference for `undefined` in pre-ES5 environments. */
7588 /** Used as the semantic version number. */
7589 var VERSION = '3.9.3';
7591 /** Used to compose bitmasks for wrapper metadata. */
7594 CURRY_BOUND_FLAG = 4,
7596 CURRY_RIGHT_FLAG = 16,
7598 PARTIAL_RIGHT_FLAG = 64,
7602 /** Used to detect when a function becomes hot. */
7603 var HOT_COUNT = 150,
7606 /** Used to indicate the type of lazy iteratees. */
7607 var LAZY_DROP_WHILE_FLAG = 0,
7608 LAZY_FILTER_FLAG = 1,
7611 /** Used as the `TypeError` message for "Functions" methods. */
7612 var FUNC_ERROR_TEXT = 'Expected a function';
7614 /** Used as the internal argument placeholder. */
7615 var PLACEHOLDER = '__lodash_placeholder__';
7617 /** `Object#toString` result references. */
7618 var argsTag = '[object Arguments]',
7619 arrayTag = '[object Array]',
7620 boolTag = '[object Boolean]',
7621 dateTag = '[object Date]',
7622 errorTag = '[object Error]',
7623 funcTag = '[object Function]',
7624 mapTag = '[object Map]',
7625 numberTag = '[object Number]',
7626 objectTag = '[object Object]',
7627 regexpTag = '[object RegExp]',
7628 setTag = '[object Set]',
7629 stringTag = '[object String]',
7630 weakMapTag = '[object WeakMap]';
7632 var arrayBufferTag = '[object ArrayBuffer]',
7633 float32Tag = '[object Float32Array]',
7634 float64Tag = '[object Float64Array]',
7635 int8Tag = '[object Int8Array]',
7636 int16Tag = '[object Int16Array]',
7637 int32Tag = '[object Int32Array]',
7638 uint8Tag = '[object Uint8Array]',
7639 uint8ClampedTag = '[object Uint8ClampedArray]',
7640 uint16Tag = '[object Uint16Array]',
7641 uint32Tag = '[object Uint32Array]';
7643 /** Used to match property names within property paths. */
7644 var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,
7645 reIsPlainProp = /^\w*$/,
7646 rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g;
7649 * Used to match `RegExp` [special characters](http://www.regular-expressions.info/characters.html#special).
7650 * In addition to special characters the forward slash is escaped to allow for
7651 * easier `eval` use and `Function` compilation.
7653 var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g,
7654 reHasRegExpChars = RegExp(reRegExpChars.source);
7656 /** Used to match backslashes in property paths. */
7657 var reEscapeChar = /\\(\\)?/g;
7659 /** Used to match `RegExp` flags from their coerced string values. */
7660 var reFlags = /\w*$/;
7662 /** Used to detect host constructors (Safari > 5). */
7663 var reIsHostCtor = /^\[object .+?Constructor\]$/;
7665 /** Used to detect unsigned integer values. */
7666 var reIsUint = /^\d+$/;
7668 /** Used to fix the JScript `[[DontEnum]]` bug. */
7670 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
7671 'toLocaleString', 'toString', 'valueOf'
7674 /** Used to identify `toStringTag` values of typed arrays. */
7675 var typedArrayTags = {};
7676 typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
7677 typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
7678 typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
7679 typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
7680 typedArrayTags[uint32Tag] = true;
7681 typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
7682 typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
7683 typedArrayTags[dateTag] = typedArrayTags[errorTag] =
7684 typedArrayTags[funcTag] = typedArrayTags[mapTag] =
7685 typedArrayTags[numberTag] = typedArrayTags[objectTag] =
7686 typedArrayTags[regexpTag] = typedArrayTags[setTag] =
7687 typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
7689 /** Used to identify `toStringTag` values supported by `_.clone`. */
7690 var cloneableTags = {};
7691 cloneableTags[argsTag] = cloneableTags[arrayTag] =
7692 cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
7693 cloneableTags[dateTag] = cloneableTags[float32Tag] =
7694 cloneableTags[float64Tag] = cloneableTags[int8Tag] =
7695 cloneableTags[int16Tag] = cloneableTags[int32Tag] =
7696 cloneableTags[numberTag] = cloneableTags[objectTag] =
7697 cloneableTags[regexpTag] = cloneableTags[stringTag] =
7698 cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
7699 cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
7700 cloneableTags[errorTag] = cloneableTags[funcTag] =
7701 cloneableTags[mapTag] = cloneableTags[setTag] =
7702 cloneableTags[weakMapTag] = false;
7704 /** Used as an internal `_.debounce` options object by `_.throttle`. */
7705 var debounceOptions = {
7711 /** Used to determine if values are of the language type `Object`. */
7717 /** Detect free variable `exports`. */
7718 var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
7720 /** Detect free variable `module`. */
7721 var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
7723 /** Detect free variable `global` from Node.js. */
7724 var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global;
7726 /** Detect free variable `self`. */
7727 var freeSelf = objectTypes[typeof self] && self && self.Object && self;
7729 /** Detect free variable `window`. */
7730 var freeWindow = objectTypes[typeof window] && window && window.Object && window;
7732 /** Detect the popular CommonJS extension `module.exports`. */
7733 var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
7736 * Used as a reference to the global object.
7738 * The `this` value is used if it's the global object to avoid Greasemonkey's
7739 * restricted `window` object, otherwise the `window` object is used.
7741 var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this;
7743 /*--------------------------------------------------------------------------*/
7746 * The base implementation of `_.findIndex` and `_.findLastIndex` without
7747 * support for callback shorthands and `this` binding.
7750 * @param {Array} array The array to search.
7751 * @param {Function} predicate The function invoked per iteration.
7752 * @param {boolean} [fromRight] Specify iterating from right to left.
7753 * @returns {number} Returns the index of the matched value, else `-1`.
7755 function baseFindIndex(array, predicate, fromRight) {
7756 var length = array.length,
7757 index = fromRight ? length : -1;
7759 while ((fromRight ? index-- : ++index < length)) {
7760 if (predicate(array[index], index, array)) {
7768 * The base implementation of `_.indexOf` without support for binary searches.
7771 * @param {Array} array The array to search.
7772 * @param {*} value The value to search for.
7773 * @param {number} fromIndex The index to search from.
7774 * @returns {number} Returns the index of the matched value, else `-1`.
7776 function baseIndexOf(array, value, fromIndex) {
7777 if (value !== value) {
7778 return indexOfNaN(array, fromIndex);
7780 var index = fromIndex - 1,
7781 length = array.length;
7783 while (++index < length) {
7784 if (array[index] === value) {
7792 * The base implementation of `_.isFunction` without support for environments
7793 * with incorrect `typeof` results.
7796 * @param {*} value The value to check.
7797 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
7799 function baseIsFunction(value) {
7800 // Avoid a Chakra JIT bug in compatibility modes of IE 11.
7801 // See https://github.com/jashkenas/underscore/issues/1621 for more details.
7802 return typeof value == 'function' || false;
7806 * Converts `value` to a string if it's not one. An empty string is returned
7807 * for `null` or `undefined` values.
7810 * @param {*} value The value to process.
7811 * @returns {string} Returns the string.
7813 function baseToString(value) {
7814 if (typeof value == 'string') {
7817 return value == null ? '' : (value + '');
7821 * Gets the index at which the first occurrence of `NaN` is found in `array`.
7824 * @param {Array} array The array to search.
7825 * @param {number} fromIndex The index to search from.
7826 * @param {boolean} [fromRight] Specify iterating from right to left.
7827 * @returns {number} Returns the index of the matched `NaN`, else `-1`.
7829 function indexOfNaN(array, fromIndex, fromRight) {
7830 var length = array.length,
7831 index = fromIndex + (fromRight ? 0 : -1);
7833 while ((fromRight ? index-- : ++index < length)) {
7834 var other = array[index];
7835 if (other !== other) {
7843 * Checks if `value` is a host object in IE < 9.
7846 * @param {*} value The value to check.
7847 * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
7849 var isHostObject = (function() {
7851 Object({ 'toString': 0 } + '');
7853 return function() { return false; };
7855 return function(value) {
7856 // IE < 9 presents many host objects as `Object` objects that can coerce
7857 // to strings despite having improperly defined `toString` methods.
7858 return typeof value.toString != 'function' && typeof (value + '') == 'string';
7863 * Checks if `value` is object-like.
7866 * @param {*} value The value to check.
7867 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
7869 function isObjectLike(value) {
7870 return !!value && typeof value == 'object';
7874 * Replaces all `placeholder` elements in `array` with an internal placeholder
7875 * and returns an array of their indexes.
7878 * @param {Array} array The array to modify.
7879 * @param {*} placeholder The placeholder to replace.
7880 * @returns {Array} Returns the new array of placeholder indexes.
7882 function replaceHolders(array, placeholder) {
7884 length = array.length,
7888 while (++index < length) {
7889 if (array[index] === placeholder) {
7890 array[index] = PLACEHOLDER;
7891 result[++resIndex] = index;
7898 * An implementation of `_.uniq` optimized for sorted arrays without support
7899 * for callback shorthands and `this` binding.
7902 * @param {Array} array The array to inspect.
7903 * @param {Function} [iteratee] The function invoked per iteration.
7904 * @returns {Array} Returns the new duplicate-value-free array.
7906 function sortedUniq(array, iteratee) {
7909 length = array.length,
7913 while (++index < length) {
7914 var value = array[index],
7915 computed = iteratee ? iteratee(value, index, array) : value;
7917 if (!index || seen !== computed) {
7919 result[++resIndex] = value;
7925 /*--------------------------------------------------------------------------*/
7927 /** Used for native method references. */
7928 var arrayProto = Array.prototype,
7929 errorProto = Error.prototype,
7930 objectProto = Object.prototype,
7931 stringProto = String.prototype;
7933 /** Used to resolve the decompiled source of functions. */
7934 var fnToString = Function.prototype.toString;
7936 /** Used to check objects for own properties. */
7937 var hasOwnProperty = objectProto.hasOwnProperty;
7940 * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
7943 var objToString = objectProto.toString;
7945 /** Used to detect if a method is native. */
7946 var reIsNative = RegExp('^' +
7947 escapeRegExp(fnToString.call(hasOwnProperty))
7948 .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
7951 /** Native method references. */
7952 var ArrayBuffer = getNative(root, 'ArrayBuffer'),
7953 bufferSlice = getNative(ArrayBuffer && new ArrayBuffer(0), 'slice'),
7956 getPrototypeOf = getNative(Object, 'getPrototypeOf'),
7957 push = arrayProto.push,
7958 propertyIsEnumerable = objectProto.propertyIsEnumerable,
7959 Set = getNative(root, 'Set'),
7960 splice = arrayProto.splice,
7961 Uint8Array = getNative(root, 'Uint8Array'),
7962 WeakMap = getNative(root, 'WeakMap');
7964 /** Used to clone array buffers. */
7965 var Float64Array = (function() {
7966 // Safari 5 errors when using an array buffer to initialize a typed array
7967 // where the array buffer's `byteLength` is not a multiple of the typed
7968 // array's `BYTES_PER_ELEMENT`.
7970 var func = getNative(root, 'Float64Array'),
7971 result = new func(new ArrayBuffer(10), 0, 1) && func;
7973 return result || null;
7976 /* Native method references for those with the same name as other `lodash` methods. */
7977 var nativeCreate = getNative(Object, 'create'),
7978 nativeIsArray = getNative(Array, 'isArray'),
7979 nativeKeys = getNative(Object, 'keys'),
7980 nativeMax = Math.max,
7981 nativeMin = Math.min,
7982 nativeNow = getNative(Date, 'now');
7984 /** Used as references for `-Infinity` and `Infinity`. */
7985 var POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
7987 /** Used as references for the maximum length and index of an array. */
7988 var MAX_ARRAY_LENGTH = 4294967295,
7989 MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
7990 HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
7992 /** Used as the size, in bytes, of each `Float64Array` element. */
7993 var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0;
7996 * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer)
7997 * of an array-like value.
7999 var MAX_SAFE_INTEGER = 9007199254740991;
8001 /** Used to store function metadata. */
8002 var metaMap = WeakMap && new WeakMap;
8004 /** Used to lookup unminified function names. */
8007 /** Used to lookup a type array constructors by `toStringTag`. */
8009 ctorByTag[float32Tag] = root.Float32Array;
8010 ctorByTag[float64Tag] = root.Float64Array;
8011 ctorByTag[int8Tag] = root.Int8Array;
8012 ctorByTag[int16Tag] = root.Int16Array;
8013 ctorByTag[int32Tag] = root.Int32Array;
8014 ctorByTag[uint8Tag] = root.Uint8Array;
8015 ctorByTag[uint8ClampedTag] = root.Uint8ClampedArray;
8016 ctorByTag[uint16Tag] = root.Uint16Array;
8017 ctorByTag[uint32Tag] = root.Uint32Array;
8019 /** Used to avoid iterating over non-enumerable properties in IE < 9. */
8020 var nonEnumProps = {};
8021 nonEnumProps[arrayTag] = nonEnumProps[dateTag] = nonEnumProps[numberTag] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true };
8022 nonEnumProps[boolTag] = nonEnumProps[stringTag] = { 'constructor': true, 'toString': true, 'valueOf': true };
8023 nonEnumProps[errorTag] = nonEnumProps[funcTag] = nonEnumProps[regexpTag] = { 'constructor': true, 'toString': true };
8024 nonEnumProps[objectTag] = { 'constructor': true };
8026 arrayEach(shadowProps, function(key) {
8027 for (var tag in nonEnumProps) {
8028 if (hasOwnProperty.call(nonEnumProps, tag)) {
8029 var props = nonEnumProps[tag];
8030 props[key] = hasOwnProperty.call(props, key);
8035 /*------------------------------------------------------------------------*/
8038 * Creates a `lodash` object which wraps `value` to enable implicit chaining.
8039 * Methods that operate on and return arrays, collections, and functions can
8040 * be chained together. Methods that return a boolean or single value will
8041 * automatically end the chain returning the unwrapped value. Explicit chaining
8042 * may be enabled using `_.chain`. The execution of chained methods is lazy,
8043 * that is, execution is deferred until `_#value` is implicitly or explicitly
8046 * Lazy evaluation allows several methods to support shortcut fusion. Shortcut
8047 * fusion is an optimization that merges iteratees to avoid creating intermediate
8048 * arrays and reduce the number of iteratee executions.
8050 * Chaining is supported in custom builds as long as the `_#value` method is
8051 * directly or indirectly included in the build.
8053 * In addition to lodash methods, wrappers have `Array` and `String` methods.
8055 * The wrapper `Array` methods are:
8056 * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`,
8057 * `splice`, and `unshift`
8059 * The wrapper `String` methods are:
8060 * `replace` and `split`
8062 * The wrapper methods that support shortcut fusion are:
8063 * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`,
8064 * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`,
8065 * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`,
8068 * The chainable wrapper methods are:
8069 * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
8070 * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`,
8071 * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`,
8072 * `difference`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `fill`,
8073 * `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`, `forEach`,
8074 * `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`,
8075 * `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`,
8076 * `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
8077 * `memoize`, `merge`, `method`, `methodOf`, `mixin`, `negate`, `omit`, `once`,
8078 * `pairs`, `partial`, `partialRight`, `partition`, `pick`, `plant`, `pluck`,
8079 * `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`, `rearg`,
8080 * `reject`, `remove`, `rest`, `restParam`, `reverse`, `set`, `shuffle`,
8081 * `slice`, `sort`, `sortBy`, `sortByAll`, `sortByOrder`, `splice`, `spread`,
8082 * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, `throttle`,
8083 * `thru`, `times`, `toArray`, `toPlainObject`, `transform`, `union`, `uniq`,
8084 * `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, `where`, `without`,
8085 * `wrap`, `xor`, `zip`, `zipObject`, `zipWith`
8087 * The wrapper methods that are **not** chainable by default are:
8088 * `add`, `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`,
8089 * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`,
8090 * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `get`,
8091 * `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, `inRange`, `isArguments`,
8092 * `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`,
8093 * `isFinite` `isFunction`, `isMatch`, `isNative`, `isNaN`, `isNull`, `isNumber`,
8094 * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`,
8095 * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `lt`, `lte`,
8096 * `max`, `min`, `noConflict`, `noop`, `now`, `pad`, `padLeft`, `padRight`,
8097 * `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`,
8098 * `runInContext`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`,
8099 * `sortedLastIndex`, `startCase`, `startsWith`, `sum`, `template`, `trim`,
8100 * `trimLeft`, `trimRight`, `trunc`, `unescape`, `uniqueId`, `value`, and `words`
8102 * The wrapper method `sample` will return a wrapped value when `n` is provided,
8103 * otherwise an unwrapped value is returned.
8108 * @param {*} value The value to wrap in a `lodash` instance.
8109 * @returns {Object} Returns the new `lodash` wrapper instance.
8112 * var wrapped = _([1, 2, 3]);
8114 * // returns an unwrapped value
8115 * wrapped.reduce(function(total, n) {
8120 * // returns a wrapped value
8121 * var squares = wrapped.map(function(n) {
8125 * _.isArray(squares);
8128 * _.isArray(squares.value());
8131 function lodash(value) {
8132 if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
8133 if (value instanceof LodashWrapper) {
8136 if (hasOwnProperty.call(value, '__chain__') && hasOwnProperty.call(value, '__wrapped__')) {
8137 return wrapperClone(value);
8140 return new LodashWrapper(value);
8144 * The function whose prototype all chaining wrappers inherit from.
8148 function baseLodash() {
8149 // No operation performed.
8153 * The base constructor for creating `lodash` wrapper objects.
8156 * @param {*} value The value to wrap.
8157 * @param {boolean} [chainAll] Enable chaining for all wrapper methods.
8158 * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value.
8160 function LodashWrapper(value, chainAll, actions) {
8161 this.__wrapped__ = value;
8162 this.__actions__ = actions || [];
8163 this.__chain__ = !!chainAll;
8167 * An object environment feature flags.
8173 var support = lodash.support = {};
8176 var Ctor = function() { this.x = x; },
8177 object = { '0': x, 'length': x },
8180 Ctor.prototype = { 'valueOf': x, 'y': x };
8181 for (var key in new Ctor) { props.push(key); }
8184 * Detect if the `toStringTag` of `arguments` objects is resolvable
8185 * (all but Firefox < 4, IE < 9).
8187 * @memberOf _.support
8190 support.argsTag = objToString.call(arguments) == argsTag;
8193 * Detect if `name` or `message` properties of `Error.prototype` are
8194 * enumerable by default (IE < 9, Safari < 5.1).
8196 * @memberOf _.support
8199 support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') ||
8200 propertyIsEnumerable.call(errorProto, 'name');
8203 * Detect if `prototype` properties are enumerable by default.
8205 * Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
8206 * (if the prototype or a property on the prototype has been set)
8207 * incorrectly set the `[[Enumerable]]` value of a function's `prototype`
8208 * property to `true`.
8210 * @memberOf _.support
8213 support.enumPrototypes = propertyIsEnumerable.call(Ctor, 'prototype');
8216 * Detect if properties shadowing those on `Object.prototype` are non-enumerable.
8218 * In IE < 9 an object's own properties, shadowing non-enumerable ones,
8219 * are made non-enumerable as well (a.k.a the JScript `[[DontEnum]]` bug).
8221 * @memberOf _.support
8224 support.nonEnumShadows = !/valueOf/.test(props);
8227 * Detect if own properties are iterated after inherited properties (IE < 9).
8229 * @memberOf _.support
8232 support.ownLast = props[0] != 'x';
8235 * Detect if `Array#shift` and `Array#splice` augment array-like objects
8238 * Firefox < 10, compatibility modes of IE 8, and IE < 9 have buggy Array
8239 * `shift()` and `splice()` functions that fail to remove the last element,
8240 * `value[0]`, of array-like objects even though the "length" property is
8241 * set to `0`. The `shift()` method is buggy in compatibility modes of IE 8,
8242 * while `splice()` is buggy regardless of mode in IE < 9.
8244 * @memberOf _.support
8247 support.spliceObjects = (splice.call(object, 0, 1), !object[0]);
8250 * Detect lack of support for accessing string characters by index.
8252 * IE < 8 can't access characters by index. IE 8 can only access characters
8253 * by index on string literals, not string objects.
8255 * @memberOf _.support
8258 support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx';
8261 /*------------------------------------------------------------------------*/
8264 * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
8267 * @param {*} value The value to wrap.
8269 function LazyWrapper(value) {
8270 this.__wrapped__ = value;
8271 this.__actions__ = null;
8273 this.__dropCount__ = 0;
8274 this.__filtered__ = false;
8275 this.__iteratees__ = null;
8276 this.__takeCount__ = POSITIVE_INFINITY;
8277 this.__views__ = null;
8281 * Creates a clone of the lazy wrapper object.
8285 * @memberOf LazyWrapper
8286 * @returns {Object} Returns the cloned `LazyWrapper` object.
8288 function lazyClone() {
8289 var actions = this.__actions__,
8290 iteratees = this.__iteratees__,
8291 views = this.__views__,
8292 result = new LazyWrapper(this.__wrapped__);
8294 result.__actions__ = actions ? arrayCopy(actions) : null;
8295 result.__dir__ = this.__dir__;
8296 result.__filtered__ = this.__filtered__;
8297 result.__iteratees__ = iteratees ? arrayCopy(iteratees) : null;
8298 result.__takeCount__ = this.__takeCount__;
8299 result.__views__ = views ? arrayCopy(views) : null;
8304 * Reverses the direction of lazy iteration.
8308 * @memberOf LazyWrapper
8309 * @returns {Object} Returns the new reversed `LazyWrapper` object.
8311 function lazyReverse() {
8312 if (this.__filtered__) {
8313 var result = new LazyWrapper(this);
8314 result.__dir__ = -1;
8315 result.__filtered__ = true;
8317 result = this.clone();
8318 result.__dir__ *= -1;
8324 * Extracts the unwrapped value from its lazy wrapper.
8328 * @memberOf LazyWrapper
8329 * @returns {*} Returns the unwrapped value.
8331 function lazyValue() {
8332 var array = this.__wrapped__.value();
8333 if (!isArray(array)) {
8334 return baseWrapperValue(array, this.__actions__);
8336 var dir = this.__dir__,
8338 view = getView(0, array.length, this.__views__),
8341 length = end - start,
8342 index = isRight ? end : (start - 1),
8343 takeCount = nativeMin(length, this.__takeCount__),
8344 iteratees = this.__iteratees__,
8345 iterLength = iteratees ? iteratees.length : 0,
8350 while (length-- && resIndex < takeCount) {
8354 value = array[index];
8356 while (++iterIndex < iterLength) {
8357 var data = iteratees[iterIndex],
8358 iteratee = data.iteratee,
8361 if (type == LAZY_DROP_WHILE_FLAG) {
8362 if (data.done && (isRight ? (index > data.index) : (index < data.index))) {
8368 var limit = data.limit;
8369 if (!(data.done = limit > -1 ? (data.count++ >= limit) : !iteratee(value))) {
8374 var computed = iteratee(value);
8375 if (type == LAZY_MAP_FLAG) {
8377 } else if (!computed) {
8378 if (type == LAZY_FILTER_FLAG) {
8386 result[resIndex++] = value;
8391 /*------------------------------------------------------------------------*/
8395 * Creates a cache object to store unique values.
8398 * @param {Array} [values] The values to cache.
8400 function SetCache(values) {
8401 var length = values ? values.length : 0;
8403 this.data = { 'hash': nativeCreate(null), 'set': new Set };
8405 this.push(values[length]);
8410 * Checks if `value` is in `cache` mimicking the return signature of
8411 * `_.indexOf` by returning `0` if the value is found, else `-1`.
8414 * @param {Object} cache The cache to search.
8415 * @param {*} value The value to search for.
8416 * @returns {number} Returns `0` if `value` is found, else `-1`.
8418 function cacheIndexOf(cache, value) {
8419 var data = cache.data,
8420 result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value];
8422 return result ? 0 : -1;
8426 * Adds `value` to the cache.
8430 * @memberOf SetCache
8431 * @param {*} value The value to cache.
8433 function cachePush(value) {
8434 var data = this.data;
8435 if (typeof value == 'string' || isObject(value)) {
8436 data.set.add(value);
8438 data.hash[value] = true;
8442 /*------------------------------------------------------------------------*/
8445 * Copies the values of `source` to `array`.
8448 * @param {Array} source The array to copy values from.
8449 * @param {Array} [array=[]] The array to copy values to.
8450 * @returns {Array} Returns `array`.
8452 function arrayCopy(source, array) {
8454 length = source.length;
8456 array || (array = Array(length));
8457 while (++index < length) {
8458 array[index] = source[index];
8464 * A specialized version of `_.forEach` for arrays without support for callback
8465 * shorthands and `this` binding.
8468 * @param {Array} array The array to iterate over.
8469 * @param {Function} iteratee The function invoked per iteration.
8470 * @returns {Array} Returns `array`.
8472 function arrayEach(array, iteratee) {
8474 length = array.length;
8476 while (++index < length) {
8477 if (iteratee(array[index], index, array) === false) {
8485 * A specialized version of `_.every` for arrays without support for callback
8486 * shorthands and `this` binding.
8489 * @param {Array} array The array to iterate over.
8490 * @param {Function} predicate The function invoked per iteration.
8491 * @returns {boolean} Returns `true` if all elements pass the predicate check,
8494 function arrayEvery(array, predicate) {
8496 length = array.length;
8498 while (++index < length) {
8499 if (!predicate(array[index], index, array)) {
8507 * A specialized version of `_.filter` for arrays without support for callback
8508 * shorthands and `this` binding.
8511 * @param {Array} array The array to iterate over.
8512 * @param {Function} predicate The function invoked per iteration.
8513 * @returns {Array} Returns the new filtered array.
8515 function arrayFilter(array, predicate) {
8517 length = array.length,
8521 while (++index < length) {
8522 var value = array[index];
8523 if (predicate(value, index, array)) {
8524 result[++resIndex] = value;
8531 * A specialized version of `_.map` for arrays without support for callback
8532 * shorthands and `this` binding.
8535 * @param {Array} array The array to iterate over.
8536 * @param {Function} iteratee The function invoked per iteration.
8537 * @returns {Array} Returns the new mapped array.
8539 function arrayMap(array, iteratee) {
8541 length = array.length,
8542 result = Array(length);
8544 while (++index < length) {
8545 result[index] = iteratee(array[index], index, array);
8551 * A specialized version of `_.reduce` for arrays without support for callback
8552 * shorthands and `this` binding.
8555 * @param {Array} array The array to iterate over.
8556 * @param {Function} iteratee The function invoked per iteration.
8557 * @param {*} [accumulator] The initial value.
8558 * @param {boolean} [initFromArray] Specify using the first element of `array`
8559 * as the initial value.
8560 * @returns {*} Returns the accumulated value.
8562 function arrayReduce(array, iteratee, accumulator, initFromArray) {
8564 length = array.length;
8566 if (initFromArray && length) {
8567 accumulator = array[++index];
8569 while (++index < length) {
8570 accumulator = iteratee(accumulator, array[index], index, array);
8576 * A specialized version of `_.some` for arrays without support for callback
8577 * shorthands and `this` binding.
8580 * @param {Array} array The array to iterate over.
8581 * @param {Function} predicate The function invoked per iteration.
8582 * @returns {boolean} Returns `true` if any element passes the predicate check,
8585 function arraySome(array, predicate) {
8587 length = array.length;
8589 while (++index < length) {
8590 if (predicate(array[index], index, array)) {
8598 * A specialized version of `_.assign` for customizing assigned values without
8599 * support for argument juggling, multiple sources, and `this` binding `customizer`
8603 * @param {Object} object The destination object.
8604 * @param {Object} source The source object.
8605 * @param {Function} customizer The function to customize assigned values.
8606 * @returns {Object} Returns `object`.
8608 function assignWith(object, source, customizer) {
8610 props = keys(source),
8611 length = props.length;
8613 while (++index < length) {
8614 var key = props[index],
8615 value = object[key],
8616 result = customizer(value, source[key], key, object, source);
8618 if ((result === result ? (result !== value) : (value === value)) ||
8619 (value === undefined && !(key in object))) {
8620 object[key] = result;
8627 * The base implementation of `_.assign` without support for argument juggling,
8628 * multiple sources, and `customizer` functions.
8631 * @param {Object} object The destination object.
8632 * @param {Object} source The source object.
8633 * @returns {Object} Returns `object`.
8635 function baseAssign(object, source) {
8636 return source == null
8638 : baseCopy(source, keys(source), object);
8642 * Copies properties of `source` to `object`.
8645 * @param {Object} source The object to copy properties from.
8646 * @param {Array} props The property names to copy.
8647 * @param {Object} [object={}] The object to copy properties to.
8648 * @returns {Object} Returns `object`.
8650 function baseCopy(source, props, object) {
8651 object || (object = {});
8654 length = props.length;
8656 while (++index < length) {
8657 var key = props[index];
8658 object[key] = source[key];
8664 * The base implementation of `_.callback` which supports specifying the
8665 * number of arguments to provide to `func`.
8668 * @param {*} [func=_.identity] The value to convert to a callback.
8669 * @param {*} [thisArg] The `this` binding of `func`.
8670 * @param {number} [argCount] The number of arguments to provide to `func`.
8671 * @returns {Function} Returns the callback.
8673 function baseCallback(func, thisArg, argCount) {
8674 var type = typeof func;
8675 if (type == 'function') {
8676 return thisArg === undefined
8678 : bindCallback(func, thisArg, argCount);
8683 if (type == 'object') {
8684 return baseMatches(func);
8686 return thisArg === undefined
8688 : baseMatchesProperty(func, thisArg);
8692 * The base implementation of `_.clone` without support for argument juggling
8693 * and `this` binding `customizer` functions.
8696 * @param {*} value The value to clone.
8697 * @param {boolean} [isDeep] Specify a deep clone.
8698 * @param {Function} [customizer] The function to customize cloning values.
8699 * @param {string} [key] The key of `value`.
8700 * @param {Object} [object] The object `value` belongs to.
8701 * @param {Array} [stackA=[]] Tracks traversed source objects.
8702 * @param {Array} [stackB=[]] Associates clones with source counterparts.
8703 * @returns {*} Returns the cloned value.
8705 function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
8708 result = object ? customizer(value, key, object) : customizer(value);
8710 if (result !== undefined) {
8713 if (!isObject(value)) {
8716 var isArr = isArray(value);
8718 result = initCloneArray(value);
8720 return arrayCopy(value, result);
8723 var tag = objToString.call(value),
8724 isFunc = tag == funcTag;
8726 if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
8727 if (isHostObject(value)) {
8728 return object ? value : {};
8730 result = initCloneObject(isFunc ? {} : value);
8732 return baseAssign(result, value);
8735 return cloneableTags[tag]
8736 ? initCloneByTag(value, tag, isDeep)
8737 : (object ? value : {});
8740 // Check for circular references and return corresponding clone.
8741 stackA || (stackA = []);
8742 stackB || (stackB = []);
8744 var length = stackA.length;
8746 if (stackA[length] == value) {
8747 return stackB[length];
8750 // Add the source value to the stack of traversed objects and associate it with its clone.
8752 stackB.push(result);
8754 // Recursively populate clone (susceptible to call stack limits).
8755 (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
8756 result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
8762 * The base implementation of `_.create` without support for assigning
8763 * properties to the created object.
8766 * @param {Object} prototype The object to inherit from.
8767 * @returns {Object} Returns the new object.
8769 var baseCreate = (function() {
8770 function object() {}
8771 return function(prototype) {
8772 if (isObject(prototype)) {
8773 object.prototype = prototype;
8774 var result = new object;
8775 object.prototype = null;
8777 return result || {};
8782 * The base implementation of `_.difference` which accepts a single array
8783 * of values to exclude.
8786 * @param {Array} array The array to inspect.
8787 * @param {Array} values The values to exclude.
8788 * @returns {Array} Returns the new array of filtered values.
8790 function baseDifference(array, values) {
8791 var length = array ? array.length : 0,
8798 indexOf = getIndexOf(),
8799 isCommon = indexOf == baseIndexOf,
8800 cache = (isCommon && values.length >= 200) ? createCache(values) : null,
8801 valuesLength = values.length;
8804 indexOf = cacheIndexOf;
8809 while (++index < length) {
8810 var value = array[index];
8812 if (isCommon && value === value) {
8813 var valuesIndex = valuesLength;
8814 while (valuesIndex--) {
8815 if (values[valuesIndex] === value) {
8821 else if (indexOf(values, value, 0) < 0) {
8829 * The base implementation of `_.forEach` without support for callback
8830 * shorthands and `this` binding.
8833 * @param {Array|Object|string} collection The collection to iterate over.
8834 * @param {Function} iteratee The function invoked per iteration.
8835 * @returns {Array|Object|string} Returns `collection`.
8837 var baseEach = createBaseEach(baseForOwn);
8840 * The base implementation of `_.every` without support for callback
8841 * shorthands and `this` binding.
8844 * @param {Array|Object|string} collection The collection to iterate over.
8845 * @param {Function} predicate The function invoked per iteration.
8846 * @returns {boolean} Returns `true` if all elements pass the predicate check,
8849 function baseEvery(collection, predicate) {
8851 baseEach(collection, function(value, index, collection) {
8852 result = !!predicate(value, index, collection);
8859 * The base implementation of `_.filter` without support for callback
8860 * shorthands and `this` binding.
8863 * @param {Array|Object|string} collection The collection to iterate over.
8864 * @param {Function} predicate The function invoked per iteration.
8865 * @returns {Array} Returns the new filtered array.
8867 function baseFilter(collection, predicate) {
8869 baseEach(collection, function(value, index, collection) {
8870 if (predicate(value, index, collection)) {
8878 * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`,
8879 * without support for callback shorthands and `this` binding, which iterates
8880 * over `collection` using the provided `eachFunc`.
8883 * @param {Array|Object|string} collection The collection to search.
8884 * @param {Function} predicate The function invoked per iteration.
8885 * @param {Function} eachFunc The function to iterate over `collection`.
8886 * @param {boolean} [retKey] Specify returning the key of the found element
8887 * instead of the element itself.
8888 * @returns {*} Returns the found element or its key, else `undefined`.
8890 function baseFind(collection, predicate, eachFunc, retKey) {
8892 eachFunc(collection, function(value, key, collection) {
8893 if (predicate(value, key, collection)) {
8894 result = retKey ? key : value;
8902 * The base implementation of `_.flatten` with added support for restricting
8903 * flattening and specifying the start index.
8906 * @param {Array} array The array to flatten.
8907 * @param {boolean} [isDeep] Specify a deep flatten.
8908 * @param {boolean} [isStrict] Restrict flattening to arrays-like objects.
8909 * @returns {Array} Returns the new flattened array.
8911 function baseFlatten(array, isDeep, isStrict) {
8913 length = array.length,
8917 while (++index < length) {
8918 var value = array[index];
8919 if (isObjectLike(value) && isArrayLike(value) &&
8920 (isStrict || isArray(value) || isArguments(value))) {
8922 // Recursively flatten arrays (susceptible to call stack limits).
8923 value = baseFlatten(value, isDeep, isStrict);
8926 valLength = value.length;
8928 while (++valIndex < valLength) {
8929 result[++resIndex] = value[valIndex];
8931 } else if (!isStrict) {
8932 result[++resIndex] = value;
8939 * The base implementation of `baseForIn` and `baseForOwn` which iterates
8940 * over `object` properties returned by `keysFunc` invoking `iteratee` for
8941 * each property. Iteratee functions may exit iteration early by explicitly
8942 * returning `false`.
8945 * @param {Object} object The object to iterate over.
8946 * @param {Function} iteratee The function invoked per iteration.
8947 * @param {Function} keysFunc The function to get the keys of `object`.
8948 * @returns {Object} Returns `object`.
8950 var baseFor = createBaseFor();
8953 * The base implementation of `_.forIn` without support for callback
8954 * shorthands and `this` binding.
8957 * @param {Object} object The object to iterate over.
8958 * @param {Function} iteratee The function invoked per iteration.
8959 * @returns {Object} Returns `object`.
8961 function baseForIn(object, iteratee) {
8962 return baseFor(object, iteratee, keysIn);
8966 * The base implementation of `_.forOwn` without support for callback
8967 * shorthands and `this` binding.
8970 * @param {Object} object The object to iterate over.
8971 * @param {Function} iteratee The function invoked per iteration.
8972 * @returns {Object} Returns `object`.
8974 function baseForOwn(object, iteratee) {
8975 return baseFor(object, iteratee, keys);
8979 * The base implementation of `_.functions` which creates an array of
8980 * `object` function property names filtered from those provided.
8983 * @param {Object} object The object to inspect.
8984 * @param {Array} props The property names to filter.
8985 * @returns {Array} Returns the new array of filtered property names.
8987 function baseFunctions(object, props) {
8989 length = props.length,
8993 while (++index < length) {
8994 var key = props[index];
8995 if (isFunction(object[key])) {
8996 result[++resIndex] = key;
9003 * The base implementation of `get` without support for string paths
9004 * and default values.
9007 * @param {Object} object The object to query.
9008 * @param {Array} path The path of the property to get.
9009 * @param {string} [pathKey] The key representation of path.
9010 * @returns {*} Returns the resolved value.
9012 function baseGet(object, path, pathKey) {
9013 if (object == null) {
9016 object = toObject(object);
9017 if (pathKey !== undefined && pathKey in object) {
9021 length = path.length;
9023 while (object != null && index < length) {
9024 object = toObject(object)[path[index++]];
9026 return (index && index == length) ? object : undefined;
9030 * The base implementation of `_.isEqual` without support for `this` binding
9031 * `customizer` functions.
9034 * @param {*} value The value to compare.
9035 * @param {*} other The other value to compare.
9036 * @param {Function} [customizer] The function to customize comparing values.
9037 * @param {boolean} [isLoose] Specify performing partial comparisons.
9038 * @param {Array} [stackA] Tracks traversed `value` objects.
9039 * @param {Array} [stackB] Tracks traversed `other` objects.
9040 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
9042 function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) {
9043 if (value === other) {
9046 if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
9047 return value !== value && other !== other;
9049 return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB);
9053 * A specialized version of `baseIsEqual` for arrays and objects which performs
9054 * deep comparisons and tracks traversed objects enabling objects with circular
9055 * references to be compared.
9058 * @param {Object} object The object to compare.
9059 * @param {Object} other The other object to compare.
9060 * @param {Function} equalFunc The function to determine equivalents of values.
9061 * @param {Function} [customizer] The function to customize comparing objects.
9062 * @param {boolean} [isLoose] Specify performing partial comparisons.
9063 * @param {Array} [stackA=[]] Tracks traversed `value` objects.
9064 * @param {Array} [stackB=[]] Tracks traversed `other` objects.
9065 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
9067 function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
9068 var objIsArr = isArray(object),
9069 othIsArr = isArray(other),
9074 objTag = objToString.call(object);
9075 if (objTag == argsTag) {
9077 } else if (objTag != objectTag) {
9078 objIsArr = isTypedArray(object);
9082 othTag = objToString.call(other);
9083 if (othTag == argsTag) {
9085 } else if (othTag != objectTag) {
9086 othIsArr = isTypedArray(other);
9089 var objIsObj = objTag == objectTag && !isHostObject(object),
9090 othIsObj = othTag == objectTag && !isHostObject(other),
9091 isSameTag = objTag == othTag;
9093 if (isSameTag && !(objIsArr || objIsObj)) {
9094 return equalByTag(object, other, objTag);
9097 var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
9098 othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
9100 if (objIsWrapped || othIsWrapped) {
9101 return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB);
9107 // Assume cyclic values are equal.
9108 // For more information on detecting circular references see https://es5.github.io/#JO.
9109 stackA || (stackA = []);
9110 stackB || (stackB = []);
9112 var length = stackA.length;
9114 if (stackA[length] == object) {
9115 return stackB[length] == other;
9118 // Add `object` and `other` to the stack of traversed objects.
9119 stackA.push(object);
9122 var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB);
9131 * The base implementation of `_.isMatch` without support for callback
9132 * shorthands and `this` binding.
9135 * @param {Object} object The object to inspect.
9136 * @param {Array} matchData The propery names, values, and compare flags to match.
9137 * @param {Function} [customizer] The function to customize comparing objects.
9138 * @returns {boolean} Returns `true` if `object` is a match, else `false`.
9140 function baseIsMatch(object, matchData, customizer) {
9141 var index = matchData.length,
9143 noCustomizer = !customizer;
9145 if (object == null) {
9148 object = toObject(object);
9150 var data = matchData[index];
9151 if ((noCustomizer && data[2])
9152 ? data[1] !== object[data[0]]
9153 : !(data[0] in object)
9158 while (++index < length) {
9159 data = matchData[index];
9161 objValue = object[key],
9164 if (noCustomizer && data[2]) {
9165 if (objValue === undefined && !(key in object)) {
9169 var result = customizer ? customizer(objValue, srcValue, key) : undefined;
9170 if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) {
9179 * The base implementation of `_.map` without support for callback shorthands
9180 * and `this` binding.
9183 * @param {Array|Object|string} collection The collection to iterate over.
9184 * @param {Function} iteratee The function invoked per iteration.
9185 * @returns {Array} Returns the new mapped array.
9187 function baseMap(collection, iteratee) {
9189 result = isArrayLike(collection) ? Array(collection.length) : [];
9191 baseEach(collection, function(value, key, collection) {
9192 result[++index] = iteratee(value, key, collection);
9198 * The base implementation of `_.matches` which does not clone `source`.
9201 * @param {Object} source The object of property values to match.
9202 * @returns {Function} Returns the new function.
9204 function baseMatches(source) {
9205 var matchData = getMatchData(source);
9206 if (matchData.length == 1 && matchData[0][2]) {
9207 var key = matchData[0][0],
9208 value = matchData[0][1];
9210 return function(object) {
9211 if (object == null) {
9214 object = toObject(object);
9215 return object[key] === value && (value !== undefined || (key in object));
9218 return function(object) {
9219 return baseIsMatch(object, matchData);
9224 * The base implementation of `_.matchesProperty` which does not clone `srcValue`.
9227 * @param {string} path The path of the property to get.
9228 * @param {*} srcValue The value to compare.
9229 * @returns {Function} Returns the new function.
9231 function baseMatchesProperty(path, srcValue) {
9232 var isArr = isArray(path),
9233 isCommon = isKey(path) && isStrictComparable(srcValue),
9234 pathKey = (path + '');
9236 path = toPath(path);
9237 return function(object) {
9238 if (object == null) {
9242 object = toObject(object);
9243 if ((isArr || !isCommon) && !(key in object)) {
9244 object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
9245 if (object == null) {
9249 object = toObject(object);
9251 return object[key] === srcValue
9252 ? (srcValue !== undefined || (key in object))
9253 : baseIsEqual(srcValue, object[key], undefined, true);
9258 * The base implementation of `_.merge` without support for argument juggling,
9259 * multiple sources, and `this` binding `customizer` functions.
9262 * @param {Object} object The destination object.
9263 * @param {Object} source The source object.
9264 * @param {Function} [customizer] The function to customize merging properties.
9265 * @param {Array} [stackA=[]] Tracks traversed source objects.
9266 * @param {Array} [stackB=[]] Associates values with source counterparts.
9267 * @returns {Object} Returns `object`.
9269 function baseMerge(object, source, customizer, stackA, stackB) {
9270 if (!isObject(object)) {
9273 var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)),
9274 props = isSrcArr ? null : keys(source);
9276 arrayEach(props || source, function(srcValue, key) {
9279 srcValue = source[key];
9281 if (isObjectLike(srcValue)) {
9282 stackA || (stackA = []);
9283 stackB || (stackB = []);
9284 baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
9287 var value = object[key],
9288 result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
9289 isCommon = result === undefined;
9294 if ((result !== undefined || (isSrcArr && !(key in object))) &&
9295 (isCommon || (result === result ? (result !== value) : (value === value)))) {
9296 object[key] = result;
9304 * A specialized version of `baseMerge` for arrays and objects which performs
9305 * deep merges and tracks traversed objects enabling objects with circular
9306 * references to be merged.
9309 * @param {Object} object The destination object.
9310 * @param {Object} source The source object.
9311 * @param {string} key The key of the value to merge.
9312 * @param {Function} mergeFunc The function to merge values.
9313 * @param {Function} [customizer] The function to customize merging properties.
9314 * @param {Array} [stackA=[]] Tracks traversed source objects.
9315 * @param {Array} [stackB=[]] Associates values with source counterparts.
9316 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
9318 function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
9319 var length = stackA.length,
9320 srcValue = source[key];
9323 if (stackA[length] == srcValue) {
9324 object[key] = stackB[length];
9328 var value = object[key],
9329 result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
9330 isCommon = result === undefined;
9334 if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) {
9335 result = isArray(value)
9337 : (isArrayLike(value) ? arrayCopy(value) : []);
9339 else if (isPlainObject(srcValue) || isArguments(srcValue)) {
9340 result = isArguments(value)
9341 ? toPlainObject(value)
9342 : (isPlainObject(value) ? value : {});
9348 // Add the source value to the stack of traversed objects and associate
9349 // it with its merged value.
9350 stackA.push(srcValue);
9351 stackB.push(result);
9354 // Recursively merge objects and arrays (susceptible to call stack limits).
9355 object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
9356 } else if (result === result ? (result !== value) : (value === value)) {
9357 object[key] = result;
9362 * The base implementation of `_.property` without support for deep paths.
9365 * @param {string} key The key of the property to get.
9366 * @returns {Function} Returns the new function.
9368 function baseProperty(key) {
9369 return function(object) {
9370 return object == null ? undefined : toObject(object)[key];
9375 * A specialized version of `baseProperty` which supports deep paths.
9378 * @param {Array|string} path The path of the property to get.
9379 * @returns {Function} Returns the new function.
9381 function basePropertyDeep(path) {
9382 var pathKey = (path + '');
9383 path = toPath(path);
9384 return function(object) {
9385 return baseGet(object, path, pathKey);
9390 * The base implementation of `_.reduce` and `_.reduceRight` without support
9391 * for callback shorthands and `this` binding, which iterates over `collection`
9392 * using the provided `eachFunc`.
9395 * @param {Array|Object|string} collection The collection to iterate over.
9396 * @param {Function} iteratee The function invoked per iteration.
9397 * @param {*} accumulator The initial value.
9398 * @param {boolean} initFromCollection Specify using the first or last element
9399 * of `collection` as the initial value.
9400 * @param {Function} eachFunc The function to iterate over `collection`.
9401 * @returns {*} Returns the accumulated value.
9403 function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) {
9404 eachFunc(collection, function(value, index, collection) {
9405 accumulator = initFromCollection
9406 ? (initFromCollection = false, value)
9407 : iteratee(accumulator, value, index, collection);
9413 * The base implementation of `setData` without support for hot loop detection.
9416 * @param {Function} func The function to associate metadata with.
9417 * @param {*} data The metadata.
9418 * @returns {Function} Returns `func`.
9420 var baseSetData = !metaMap ? identity : function(func, data) {
9421 metaMap.set(func, data);
9426 * The base implementation of `_.slice` without an iteratee call guard.
9429 * @param {Array} array The array to slice.
9430 * @param {number} [start=0] The start position.
9431 * @param {number} [end=array.length] The end position.
9432 * @returns {Array} Returns the slice of `array`.
9434 function baseSlice(array, start, end) {
9436 length = array.length;
9438 start = start == null ? 0 : (+start || 0);
9440 start = -start > length ? 0 : (length + start);
9442 end = (end === undefined || end > length) ? length : (+end || 0);
9446 length = start > end ? 0 : ((end - start) >>> 0);
9449 var result = Array(length);
9450 while (++index < length) {
9451 result[index] = array[index + start];
9457 * The base implementation of `_.some` without support for callback shorthands
9458 * and `this` binding.
9461 * @param {Array|Object|string} collection The collection to iterate over.
9462 * @param {Function} predicate The function invoked per iteration.
9463 * @returns {boolean} Returns `true` if any element passes the predicate check,
9466 function baseSome(collection, predicate) {
9469 baseEach(collection, function(value, index, collection) {
9470 result = predicate(value, index, collection);
9477 * The base implementation of `_.uniq` without support for callback shorthands
9478 * and `this` binding.
9481 * @param {Array} array The array to inspect.
9482 * @param {Function} [iteratee] The function invoked per iteration.
9483 * @returns {Array} Returns the new duplicate-value-free array.
9485 function baseUniq(array, iteratee) {
9487 indexOf = getIndexOf(),
9488 length = array.length,
9489 isCommon = indexOf == baseIndexOf,
9490 isLarge = isCommon && length >= 200,
9491 seen = isLarge ? createCache() : null,
9495 indexOf = cacheIndexOf;
9499 seen = iteratee ? [] : result;
9502 while (++index < length) {
9503 var value = array[index],
9504 computed = iteratee ? iteratee(value, index, array) : value;
9506 if (isCommon && value === value) {
9507 var seenIndex = seen.length;
9508 while (seenIndex--) {
9509 if (seen[seenIndex] === computed) {
9514 seen.push(computed);
9518 else if (indexOf(seen, computed, 0) < 0) {
9519 if (iteratee || isLarge) {
9520 seen.push(computed);
9529 * The base implementation of `_.values` and `_.valuesIn` which creates an
9530 * array of `object` property values corresponding to the property names
9534 * @param {Object} object The object to query.
9535 * @param {Array} props The property names to get values for.
9536 * @returns {Object} Returns the array of property values.
9538 function baseValues(object, props) {
9540 length = props.length,
9541 result = Array(length);
9543 while (++index < length) {
9544 result[index] = object[props[index]];
9550 * The base implementation of `wrapperValue` which returns the result of
9551 * performing a sequence of actions on the unwrapped `value`, where each
9552 * successive action is supplied the return value of the previous.
9555 * @param {*} value The unwrapped value.
9556 * @param {Array} actions Actions to peform to resolve the unwrapped value.
9557 * @returns {*} Returns the resolved value.
9559 function baseWrapperValue(value, actions) {
9561 if (result instanceof LazyWrapper) {
9562 result = result.value();
9565 length = actions.length;
9567 while (++index < length) {
9568 var args = [result],
9569 action = actions[index];
9571 push.apply(args, action.args);
9572 result = action.func.apply(action.thisArg, args);
9578 * Performs a binary search of `array` to determine the index at which `value`
9579 * should be inserted into `array` in order to maintain its sort order.
9582 * @param {Array} array The sorted array to inspect.
9583 * @param {*} value The value to evaluate.
9584 * @param {boolean} [retHighest] Specify returning the highest qualified index.
9585 * @returns {number} Returns the index at which `value` should be inserted
9588 function binaryIndex(array, value, retHighest) {
9590 high = array ? array.length : low;
9592 if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
9593 while (low < high) {
9594 var mid = (low + high) >>> 1,
9595 computed = array[mid];
9597 if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) {
9605 return binaryIndexBy(array, value, identity, retHighest);
9609 * This function is like `binaryIndex` except that it invokes `iteratee` for
9610 * `value` and each element of `array` to compute their sort ranking. The
9611 * iteratee is invoked with one argument; (value).
9614 * @param {Array} array The sorted array to inspect.
9615 * @param {*} value The value to evaluate.
9616 * @param {Function} iteratee The function invoked per iteration.
9617 * @param {boolean} [retHighest] Specify returning the highest qualified index.
9618 * @returns {number} Returns the index at which `value` should be inserted
9621 function binaryIndexBy(array, value, iteratee, retHighest) {
9622 value = iteratee(value);
9625 high = array ? array.length : 0,
9626 valIsNaN = value !== value,
9627 valIsNull = value === null,
9628 valIsUndef = value === undefined;
9630 while (low < high) {
9631 var mid = floor((low + high) / 2),
9632 computed = iteratee(array[mid]),
9633 isDef = computed !== undefined,
9634 isReflexive = computed === computed;
9637 var setLow = isReflexive || retHighest;
9638 } else if (valIsNull) {
9639 setLow = isReflexive && isDef && (retHighest || computed != null);
9640 } else if (valIsUndef) {
9641 setLow = isReflexive && (retHighest || isDef);
9642 } else if (computed == null) {
9645 setLow = retHighest ? (computed <= value) : (computed < value);
9653 return nativeMin(high, MAX_ARRAY_INDEX);
9657 * A specialized version of `baseCallback` which only supports `this` binding
9658 * and specifying the number of arguments to provide to `func`.
9661 * @param {Function} func The function to bind.
9662 * @param {*} thisArg The `this` binding of `func`.
9663 * @param {number} [argCount] The number of arguments to provide to `func`.
9664 * @returns {Function} Returns the callback.
9666 function bindCallback(func, thisArg, argCount) {
9667 if (typeof func != 'function') {
9670 if (thisArg === undefined) {
9674 case 1: return function(value) {
9675 return func.call(thisArg, value);
9677 case 3: return function(value, index, collection) {
9678 return func.call(thisArg, value, index, collection);
9680 case 4: return function(accumulator, value, index, collection) {
9681 return func.call(thisArg, accumulator, value, index, collection);
9683 case 5: return function(value, other, key, object, source) {
9684 return func.call(thisArg, value, other, key, object, source);
9688 return func.apply(thisArg, arguments);
9693 * Creates a clone of the given array buffer.
9696 * @param {ArrayBuffer} buffer The array buffer to clone.
9697 * @returns {ArrayBuffer} Returns the cloned array buffer.
9699 function bufferClone(buffer) {
9700 return bufferSlice.call(buffer, 0);
9703 // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`.
9704 bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) {
9705 var byteLength = buffer.byteLength,
9706 floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0,
9707 offset = floatLength * FLOAT64_BYTES_PER_ELEMENT,
9708 result = new ArrayBuffer(byteLength);
9711 var view = new Float64Array(result, 0, floatLength);
9712 view.set(new Float64Array(buffer, 0, floatLength));
9714 if (byteLength != offset) {
9715 view = new Uint8Array(result, offset);
9716 view.set(new Uint8Array(buffer, offset));
9723 * Creates an array that is the composition of partially applied arguments,
9724 * placeholders, and provided arguments into a single array of arguments.
9727 * @param {Array|Object} args The provided arguments.
9728 * @param {Array} partials The arguments to prepend to those provided.
9729 * @param {Array} holders The `partials` placeholder indexes.
9730 * @returns {Array} Returns the new array of composed arguments.
9732 function composeArgs(args, partials, holders) {
9733 var holdersLength = holders.length,
9735 argsLength = nativeMax(args.length - holdersLength, 0),
9737 leftLength = partials.length,
9738 result = Array(argsLength + leftLength);
9740 while (++leftIndex < leftLength) {
9741 result[leftIndex] = partials[leftIndex];
9743 while (++argsIndex < holdersLength) {
9744 result[holders[argsIndex]] = args[argsIndex];
9746 while (argsLength--) {
9747 result[leftIndex++] = args[argsIndex++];
9753 * This function is like `composeArgs` except that the arguments composition
9754 * is tailored for `_.partialRight`.
9757 * @param {Array|Object} args The provided arguments.
9758 * @param {Array} partials The arguments to append to those provided.
9759 * @param {Array} holders The `partials` placeholder indexes.
9760 * @returns {Array} Returns the new array of composed arguments.
9762 function composeArgsRight(args, partials, holders) {
9763 var holdersIndex = -1,
9764 holdersLength = holders.length,
9766 argsLength = nativeMax(args.length - holdersLength, 0),
9768 rightLength = partials.length,
9769 result = Array(argsLength + rightLength);
9771 while (++argsIndex < argsLength) {
9772 result[argsIndex] = args[argsIndex];
9774 var offset = argsIndex;
9775 while (++rightIndex < rightLength) {
9776 result[offset + rightIndex] = partials[rightIndex];
9778 while (++holdersIndex < holdersLength) {
9779 result[offset + holders[holdersIndex]] = args[argsIndex++];
9785 * Creates a function that aggregates a collection, creating an accumulator
9786 * object composed from the results of running each element in the collection
9787 * through an iteratee.
9789 * **Note:** This function is used to create `_.countBy`, `_.groupBy`, `_.indexBy`,
9790 * and `_.partition`.
9793 * @param {Function} setter The function to set keys and values of the accumulator object.
9794 * @param {Function} [initializer] The function to initialize the accumulator object.
9795 * @returns {Function} Returns the new aggregator function.
9797 function createAggregator(setter, initializer) {
9798 return function(collection, iteratee, thisArg) {
9799 var result = initializer ? initializer() : {};
9800 iteratee = getCallback(iteratee, thisArg, 3);
9802 if (isArray(collection)) {
9804 length = collection.length;
9806 while (++index < length) {
9807 var value = collection[index];
9808 setter(result, value, iteratee(value, index, collection), collection);
9811 baseEach(collection, function(value, key, collection) {
9812 setter(result, value, iteratee(value, key, collection), collection);
9820 * Creates a function that assigns properties of source object(s) to a given
9821 * destination object.
9823 * **Note:** This function is used to create `_.assign`, `_.defaults`, and `_.merge`.
9826 * @param {Function} assigner The function to assign values.
9827 * @returns {Function} Returns the new assigner function.
9829 function createAssigner(assigner) {
9830 return restParam(function(object, sources) {
9832 length = object == null ? 0 : sources.length,
9833 customizer = length > 2 ? sources[length - 2] : undefined,
9834 guard = length > 2 ? sources[2] : undefined,
9835 thisArg = length > 1 ? sources[length - 1] : undefined;
9837 if (typeof customizer == 'function') {
9838 customizer = bindCallback(customizer, thisArg, 5);
9841 customizer = typeof thisArg == 'function' ? thisArg : undefined;
9842 length -= (customizer ? 1 : 0);
9844 if (guard && isIterateeCall(sources[0], sources[1], guard)) {
9845 customizer = length < 3 ? undefined : customizer;
9848 while (++index < length) {
9849 var source = sources[index];
9851 assigner(object, source, customizer);
9859 * Creates a `baseEach` or `baseEachRight` function.
9862 * @param {Function} eachFunc The function to iterate over a collection.
9863 * @param {boolean} [fromRight] Specify iterating from right to left.
9864 * @returns {Function} Returns the new base function.
9866 function createBaseEach(eachFunc, fromRight) {
9867 return function(collection, iteratee) {
9868 var length = collection ? getLength(collection) : 0;
9869 if (!isLength(length)) {
9870 return eachFunc(collection, iteratee);
9872 var index = fromRight ? length : -1,
9873 iterable = toObject(collection);
9875 while ((fromRight ? index-- : ++index < length)) {
9876 if (iteratee(iterable[index], index, iterable) === false) {
9885 * Creates a base function for `_.forIn` or `_.forInRight`.
9888 * @param {boolean} [fromRight] Specify iterating from right to left.
9889 * @returns {Function} Returns the new base function.
9891 function createBaseFor(fromRight) {
9892 return function(object, iteratee, keysFunc) {
9893 var iterable = toObject(object),
9894 props = keysFunc(object),
9895 length = props.length,
9896 index = fromRight ? length : -1;
9898 while ((fromRight ? index-- : ++index < length)) {
9899 var key = props[index];
9900 if (iteratee(iterable[key], key, iterable) === false) {
9909 * Creates a function that wraps `func` and invokes it with the `this`
9910 * binding of `thisArg`.
9913 * @param {Function} func The function to bind.
9914 * @param {*} [thisArg] The `this` binding of `func`.
9915 * @returns {Function} Returns the new bound function.
9917 function createBindWrapper(func, thisArg) {
9918 var Ctor = createCtorWrapper(func);
9920 function wrapper() {
9921 var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
9922 return fn.apply(thisArg, arguments);
9928 * Creates a `Set` cache object to optimize linear searches of large arrays.
9931 * @param {Array} [values] The values to cache.
9932 * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`.
9934 var createCache = !(nativeCreate && Set) ? constant(null) : function(values) {
9935 return new SetCache(values);
9939 * Creates a function that produces an instance of `Ctor` regardless of
9940 * whether it was invoked as part of a `new` expression or by `call` or `apply`.
9943 * @param {Function} Ctor The constructor to wrap.
9944 * @returns {Function} Returns the new wrapped function.
9946 function createCtorWrapper(Ctor) {
9948 // Use a `switch` statement to work with class constructors.
9949 // See https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-function-objects-call-thisargument-argumentslist
9950 // for more details.
9951 var args = arguments;
9952 switch (args.length) {
9953 case 0: return new Ctor;
9954 case 1: return new Ctor(args[0]);
9955 case 2: return new Ctor(args[0], args[1]);
9956 case 3: return new Ctor(args[0], args[1], args[2]);
9957 case 4: return new Ctor(args[0], args[1], args[2], args[3]);
9958 case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
9960 var thisBinding = baseCreate(Ctor.prototype),
9961 result = Ctor.apply(thisBinding, args);
9963 // Mimic the constructor's `return` behavior.
9964 // See https://es5.github.io/#x13.2.2 for more details.
9965 return isObject(result) ? result : thisBinding;
9970 * Creates a `_.find` or `_.findLast` function.
9973 * @param {Function} eachFunc The function to iterate over a collection.
9974 * @param {boolean} [fromRight] Specify iterating from right to left.
9975 * @returns {Function} Returns the new find function.
9977 function createFind(eachFunc, fromRight) {
9978 return function(collection, predicate, thisArg) {
9979 predicate = getCallback(predicate, thisArg, 3);
9980 if (isArray(collection)) {
9981 var index = baseFindIndex(collection, predicate, fromRight);
9982 return index > -1 ? collection[index] : undefined;
9984 return baseFind(collection, predicate, eachFunc);
9989 * Creates a function for `_.forEach` or `_.forEachRight`.
9992 * @param {Function} arrayFunc The function to iterate over an array.
9993 * @param {Function} eachFunc The function to iterate over a collection.
9994 * @returns {Function} Returns the new each function.
9996 function createForEach(arrayFunc, eachFunc) {
9997 return function(collection, iteratee, thisArg) {
9998 return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))
9999 ? arrayFunc(collection, iteratee)
10000 : eachFunc(collection, bindCallback(iteratee, thisArg, 3));
10005 * Creates a function for `_.forOwn` or `_.forOwnRight`.
10008 * @param {Function} objectFunc The function to iterate over an object.
10009 * @returns {Function} Returns the new each function.
10011 function createForOwn(objectFunc) {
10012 return function(object, iteratee, thisArg) {
10013 if (typeof iteratee != 'function' || thisArg !== undefined) {
10014 iteratee = bindCallback(iteratee, thisArg, 3);
10016 return objectFunc(object, iteratee);
10021 * Creates a function for `_.reduce` or `_.reduceRight`.
10024 * @param {Function} arrayFunc The function to iterate over an array.
10025 * @param {Function} eachFunc The function to iterate over a collection.
10026 * @returns {Function} Returns the new each function.
10028 function createReduce(arrayFunc, eachFunc) {
10029 return function(collection, iteratee, accumulator, thisArg) {
10030 var initFromArray = arguments.length < 3;
10031 return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))
10032 ? arrayFunc(collection, iteratee, accumulator, initFromArray)
10033 : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc);
10038 * Creates a function that wraps `func` and invokes it with optional `this`
10039 * binding of, partial application, and currying.
10042 * @param {Function|string} func The function or method name to reference.
10043 * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
10044 * @param {*} [thisArg] The `this` binding of `func`.
10045 * @param {Array} [partials] The arguments to prepend to those provided to the new function.
10046 * @param {Array} [holders] The `partials` placeholder indexes.
10047 * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
10048 * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
10049 * @param {Array} [argPos] The argument positions of the new function.
10050 * @param {number} [ary] The arity cap of `func`.
10051 * @param {number} [arity] The arity of `func`.
10052 * @returns {Function} Returns the new wrapped function.
10054 function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
10055 var isAry = bitmask & ARY_FLAG,
10056 isBind = bitmask & BIND_FLAG,
10057 isBindKey = bitmask & BIND_KEY_FLAG,
10058 isCurry = bitmask & CURRY_FLAG,
10059 isCurryBound = bitmask & CURRY_BOUND_FLAG,
10060 isCurryRight = bitmask & CURRY_RIGHT_FLAG,
10061 Ctor = isBindKey ? null : createCtorWrapper(func);
10063 function wrapper() {
10064 // Avoid `arguments` object use disqualifying optimizations by
10065 // converting it to an array before providing it to other functions.
10066 var length = arguments.length,
10068 args = Array(length);
10071 args[index] = arguments[index];
10074 args = composeArgs(args, partials, holders);
10076 if (partialsRight) {
10077 args = composeArgsRight(args, partialsRight, holdersRight);
10079 if (isCurry || isCurryRight) {
10080 var placeholder = wrapper.placeholder,
10081 argsHolders = replaceHolders(args, placeholder);
10083 length -= argsHolders.length;
10084 if (length < arity) {
10085 var newArgPos = argPos ? arrayCopy(argPos) : null,
10086 newArity = nativeMax(arity - length, 0),
10087 newsHolders = isCurry ? argsHolders : null,
10088 newHoldersRight = isCurry ? null : argsHolders,
10089 newPartials = isCurry ? args : null,
10090 newPartialsRight = isCurry ? null : args;
10092 bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
10093 bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
10095 if (!isCurryBound) {
10096 bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
10098 var newData = [func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity],
10099 result = createHybridWrapper.apply(undefined, newData);
10101 if (isLaziable(func)) {
10102 setData(result, newData);
10104 result.placeholder = placeholder;
10108 var thisBinding = isBind ? thisArg : this,
10109 fn = isBindKey ? thisBinding[func] : func;
10112 args = reorder(args, argPos);
10114 if (isAry && ary < args.length) {
10117 if (this && this !== root && this instanceof wrapper) {
10118 fn = Ctor || createCtorWrapper(func);
10120 return fn.apply(thisBinding, args);
10126 * Creates a function that wraps `func` and invokes it with the optional `this`
10127 * binding of `thisArg` and the `partials` prepended to those provided to
10131 * @param {Function} func The function to partially apply arguments to.
10132 * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
10133 * @param {*} thisArg The `this` binding of `func`.
10134 * @param {Array} partials The arguments to prepend to those provided to the new function.
10135 * @returns {Function} Returns the new bound function.
10137 function createPartialWrapper(func, bitmask, thisArg, partials) {
10138 var isBind = bitmask & BIND_FLAG,
10139 Ctor = createCtorWrapper(func);
10141 function wrapper() {
10142 // Avoid `arguments` object use disqualifying optimizations by
10143 // converting it to an array before providing it `func`.
10144 var argsIndex = -1,
10145 argsLength = arguments.length,
10147 leftLength = partials.length,
10148 args = Array(argsLength + leftLength);
10150 while (++leftIndex < leftLength) {
10151 args[leftIndex] = partials[leftIndex];
10153 while (argsLength--) {
10154 args[leftIndex++] = arguments[++argsIndex];
10156 var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
10157 return fn.apply(isBind ? thisArg : this, args);
10163 * Creates a function that either curries or invokes `func` with optional
10164 * `this` binding and partially applied arguments.
10167 * @param {Function|string} func The function or method name to reference.
10168 * @param {number} bitmask The bitmask of flags.
10169 * The bitmask may be composed of the following flags:
10172 * 4 - `_.curry` or `_.curryRight` of a bound function
10174 * 16 - `_.curryRight`
10176 * 64 - `_.partialRight`
10179 * @param {*} [thisArg] The `this` binding of `func`.
10180 * @param {Array} [partials] The arguments to be partially applied.
10181 * @param {Array} [holders] The `partials` placeholder indexes.
10182 * @param {Array} [argPos] The argument positions of the new function.
10183 * @param {number} [ary] The arity cap of `func`.
10184 * @param {number} [arity] The arity of `func`.
10185 * @returns {Function} Returns the new wrapped function.
10187 function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
10188 var isBindKey = bitmask & BIND_KEY_FLAG;
10189 if (!isBindKey && typeof func != 'function') {
10190 throw new TypeError(FUNC_ERROR_TEXT);
10192 var length = partials ? partials.length : 0;
10194 bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
10195 partials = holders = null;
10197 length -= (holders ? holders.length : 0);
10198 if (bitmask & PARTIAL_RIGHT_FLAG) {
10199 var partialsRight = partials,
10200 holdersRight = holders;
10202 partials = holders = null;
10204 var data = isBindKey ? null : getData(func),
10205 newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
10208 mergeData(newData, data);
10209 bitmask = newData[1];
10210 arity = newData[9];
10212 newData[9] = arity == null
10213 ? (isBindKey ? 0 : func.length)
10214 : (nativeMax(arity - length, 0) || 0);
10216 if (bitmask == BIND_FLAG) {
10217 var result = createBindWrapper(newData[0], newData[2]);
10218 } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
10219 result = createPartialWrapper.apply(undefined, newData);
10221 result = createHybridWrapper.apply(undefined, newData);
10223 var setter = data ? baseSetData : setData;
10224 return setter(result, newData);
10228 * A specialized version of `baseIsEqualDeep` for arrays with support for
10229 * partial deep comparisons.
10232 * @param {Array} array The array to compare.
10233 * @param {Array} other The other array to compare.
10234 * @param {Function} equalFunc The function to determine equivalents of values.
10235 * @param {Function} [customizer] The function to customize comparing arrays.
10236 * @param {boolean} [isLoose] Specify performing partial comparisons.
10237 * @param {Array} [stackA] Tracks traversed `value` objects.
10238 * @param {Array} [stackB] Tracks traversed `other` objects.
10239 * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
10241 function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) {
10243 arrLength = array.length,
10244 othLength = other.length;
10246 if (arrLength != othLength && !(isLoose && othLength > arrLength)) {
10249 // Ignore non-index properties.
10250 while (++index < arrLength) {
10251 var arrValue = array[index],
10252 othValue = other[index],
10253 result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined;
10255 if (result !== undefined) {
10261 // Recursively compare arrays (susceptible to call stack limits).
10263 if (!arraySome(other, function(othValue) {
10264 return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB);
10268 } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) {
10276 * A specialized version of `baseIsEqualDeep` for comparing objects of
10277 * the same `toStringTag`.
10279 * **Note:** This function only supports comparing values with tags of
10280 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
10283 * @param {Object} value The object to compare.
10284 * @param {Object} other The other object to compare.
10285 * @param {string} tag The `toStringTag` of the objects to compare.
10286 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
10288 function equalByTag(object, other, tag) {
10292 // Coerce dates and booleans to numbers, dates to milliseconds and booleans
10293 // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
10294 return +object == +other;
10297 return object.name == other.name && object.message == other.message;
10300 // Treat `NaN` vs. `NaN` as equal.
10301 return (object != +object)
10303 : object == +other;
10307 // Coerce regexes to strings and treat strings primitives and string
10308 // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details.
10309 return object == (other + '');
10315 * A specialized version of `baseIsEqualDeep` for objects with support for
10316 * partial deep comparisons.
10319 * @param {Object} object The object to compare.
10320 * @param {Object} other The other object to compare.
10321 * @param {Function} equalFunc The function to determine equivalents of values.
10322 * @param {Function} [customizer] The function to customize comparing values.
10323 * @param {boolean} [isLoose] Specify performing partial comparisons.
10324 * @param {Array} [stackA] Tracks traversed `value` objects.
10325 * @param {Array} [stackB] Tracks traversed `other` objects.
10326 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
10328 function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
10329 var objProps = keys(object),
10330 objLength = objProps.length,
10331 othProps = keys(other),
10332 othLength = othProps.length;
10334 if (objLength != othLength && !isLoose) {
10337 var index = objLength;
10339 var key = objProps[index];
10340 if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) {
10344 var skipCtor = isLoose;
10345 while (++index < objLength) {
10346 key = objProps[index];
10347 var objValue = object[key],
10348 othValue = other[key],
10349 result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined;
10351 // Recursively compare objects (susceptible to call stack limits).
10352 if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) {
10355 skipCtor || (skipCtor = key == 'constructor');
10358 var objCtor = object.constructor,
10359 othCtor = other.constructor;
10361 // Non `Object` object instances with different constructors are not equal.
10362 if (objCtor != othCtor &&
10363 ('constructor' in object && 'constructor' in other) &&
10364 !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
10365 typeof othCtor == 'function' && othCtor instanceof othCtor)) {
10373 * Gets the appropriate "callback" function. If the `_.callback` method is
10374 * customized this function returns the custom method, otherwise it returns
10375 * the `baseCallback` function. If arguments are provided the chosen function
10376 * is invoked with them and its result is returned.
10379 * @returns {Function} Returns the chosen function or its result.
10381 function getCallback(func, thisArg, argCount) {
10382 var result = lodash.callback || callback;
10383 result = result === callback ? baseCallback : result;
10384 return argCount ? result(func, thisArg, argCount) : result;
10388 * Gets metadata for `func`.
10391 * @param {Function} func The function to query.
10392 * @returns {*} Returns the metadata for `func`.
10394 var getData = !metaMap ? noop : function(func) {
10395 return metaMap.get(func);
10399 * Gets the name of `func`.
10402 * @param {Function} func The function to query.
10403 * @returns {string} Returns the function name.
10405 function getFuncName(func) {
10406 var result = func.name,
10407 array = realNames[result],
10408 length = array ? array.length : 0;
10411 var data = array[length],
10412 otherFunc = data.func;
10413 if (otherFunc == null || otherFunc == func) {
10421 * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
10422 * customized this function returns the custom method, otherwise it returns
10423 * the `baseIndexOf` function. If arguments are provided the chosen function
10424 * is invoked with them and its result is returned.
10427 * @returns {Function|number} Returns the chosen function or its result.
10429 function getIndexOf(collection, target, fromIndex) {
10430 var result = lodash.indexOf || indexOf;
10431 result = result === indexOf ? baseIndexOf : result;
10432 return collection ? result(collection, target, fromIndex) : result;
10436 * Gets the "length" property value of `object`.
10438 * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
10439 * that affects Safari on at least iOS 8.1-8.3 ARM64.
10442 * @param {Object} object The object to query.
10443 * @returns {*} Returns the "length" value.
10445 var getLength = baseProperty('length');
10448 * Gets the propery names, values, and compare flags of `object`.
10451 * @param {Object} object The object to query.
10452 * @returns {Array} Returns the match data of `object`.
10454 function getMatchData(object) {
10455 var result = pairs(object),
10456 length = result.length;
10459 result[length][2] = isStrictComparable(result[length][1]);
10465 * Gets the native function at `key` of `object`.
10468 * @param {Object} object The object to query.
10469 * @param {string} key The key of the method to get.
10470 * @returns {*} Returns the function if it's native, else `undefined`.
10472 function getNative(object, key) {
10473 var value = object == null ? undefined : object[key];
10474 return isNative(value) ? value : undefined;
10478 * Gets the view, applying any `transforms` to the `start` and `end` positions.
10481 * @param {number} start The start of the view.
10482 * @param {number} end The end of the view.
10483 * @param {Array} [transforms] The transformations to apply to the view.
10484 * @returns {Object} Returns an object containing the `start` and `end`
10485 * positions of the view.
10487 function getView(start, end, transforms) {
10489 length = transforms ? transforms.length : 0;
10491 while (++index < length) {
10492 var data = transforms[index],
10495 switch (data.type) {
10496 case 'drop': start += size; break;
10497 case 'dropRight': end -= size; break;
10498 case 'take': end = nativeMin(end, start + size); break;
10499 case 'takeRight': start = nativeMax(start, end - size); break;
10502 return { 'start': start, 'end': end };
10506 * Initializes an array clone.
10509 * @param {Array} array The array to clone.
10510 * @returns {Array} Returns the initialized clone.
10512 function initCloneArray(array) {
10513 var length = array.length,
10514 result = new array.constructor(length);
10516 // Add array properties assigned by `RegExp#exec`.
10517 if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
10518 result.index = array.index;
10519 result.input = array.input;
10525 * Initializes an object clone.
10528 * @param {Object} object The object to clone.
10529 * @returns {Object} Returns the initialized clone.
10531 function initCloneObject(object) {
10532 var Ctor = object.constructor;
10533 if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
10540 * Initializes an object clone based on its `toStringTag`.
10542 * **Note:** This function only supports cloning values with tags of
10543 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
10546 * @param {Object} object The object to clone.
10547 * @param {string} tag The `toStringTag` of the object to clone.
10548 * @param {boolean} [isDeep] Specify a deep clone.
10549 * @returns {Object} Returns the initialized clone.
10551 function initCloneByTag(object, tag, isDeep) {
10552 var Ctor = object.constructor;
10554 case arrayBufferTag:
10555 return bufferClone(object);
10559 return new Ctor(+object);
10561 case float32Tag: case float64Tag:
10562 case int8Tag: case int16Tag: case int32Tag:
10563 case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
10564 // Safari 5 mobile incorrectly has `Object` as the constructor of typed arrays.
10565 if (Ctor instanceof Ctor) {
10566 Ctor = ctorByTag[tag];
10568 var buffer = object.buffer;
10569 return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
10573 return new Ctor(object);
10576 var result = new Ctor(object.source, reFlags.exec(object));
10577 result.lastIndex = object.lastIndex;
10583 * Checks if `value` is array-like.
10586 * @param {*} value The value to check.
10587 * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
10589 function isArrayLike(value) {
10590 return value != null && isLength(getLength(value));
10594 * Checks if `value` is a valid array-like index.
10597 * @param {*} value The value to check.
10598 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
10599 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
10601 function isIndex(value, length) {
10602 value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
10603 length = length == null ? MAX_SAFE_INTEGER : length;
10604 return value > -1 && value % 1 == 0 && value < length;
10608 * Checks if the provided arguments are from an iteratee call.
10611 * @param {*} value The potential iteratee value argument.
10612 * @param {*} index The potential iteratee index or key argument.
10613 * @param {*} object The potential iteratee object argument.
10614 * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
10616 function isIterateeCall(value, index, object) {
10617 if (!isObject(object)) {
10620 var type = typeof index;
10621 if (type == 'number'
10622 ? (isArrayLike(object) && isIndex(index, object.length))
10623 : (type == 'string' && index in object)) {
10624 var other = object[index];
10625 return value === value ? (value === other) : (other !== other);
10631 * Checks if `value` is a property name and not a property path.
10634 * @param {*} value The value to check.
10635 * @param {Object} [object] The object to query keys on.
10636 * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
10638 function isKey(value, object) {
10639 var type = typeof value;
10640 if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') {
10643 if (isArray(value)) {
10646 var result = !reIsDeepProp.test(value);
10647 return result || (object != null && value in toObject(object));
10651 * Checks if `func` has a lazy counterpart.
10654 * @param {Function} func The function to check.
10655 * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`.
10657 function isLaziable(func) {
10658 var funcName = getFuncName(func);
10659 if (!(funcName in LazyWrapper.prototype)) {
10662 var other = lodash[funcName];
10663 if (func === other) {
10666 var data = getData(other);
10667 return !!data && func === data[0];
10671 * Checks if `value` is a valid array-like length.
10673 * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength).
10676 * @param {*} value The value to check.
10677 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
10679 function isLength(value) {
10680 return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
10684 * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
10687 * @param {*} value The value to check.
10688 * @returns {boolean} Returns `true` if `value` if suitable for strict
10689 * equality comparisons, else `false`.
10691 function isStrictComparable(value) {
10692 return value === value && !isObject(value);
10696 * Merges the function metadata of `source` into `data`.
10698 * Merging metadata reduces the number of wrappers required to invoke a function.
10699 * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
10700 * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
10701 * augment function arguments, making the order in which they are executed important,
10702 * preventing the merging of metadata. However, we make an exception for a safe
10703 * common case where curried functions have `_.ary` and or `_.rearg` applied.
10706 * @param {Array} data The destination metadata.
10707 * @param {Array} source The source metadata.
10708 * @returns {Array} Returns `data`.
10710 function mergeData(data, source) {
10711 var bitmask = data[1],
10712 srcBitmask = source[1],
10713 newBitmask = bitmask | srcBitmask,
10714 isCommon = newBitmask < ARY_FLAG;
10717 (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) ||
10718 (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) ||
10719 (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG);
10721 // Exit early if metadata can't be merged.
10722 if (!(isCommon || isCombo)) {
10725 // Use source `thisArg` if available.
10726 if (srcBitmask & BIND_FLAG) {
10727 data[2] = source[2];
10728 // Set when currying a bound function.
10729 newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
10731 // Compose partial arguments.
10732 var value = source[3];
10734 var partials = data[3];
10735 data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
10736 data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
10738 // Compose partial right arguments.
10741 partials = data[5];
10742 data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
10743 data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
10745 // Use source `argPos` if available.
10748 data[7] = arrayCopy(value);
10750 // Use source `ary` if it's smaller.
10751 if (srcBitmask & ARY_FLAG) {
10752 data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
10754 // Use source `arity` if one is not provided.
10755 if (data[9] == null) {
10756 data[9] = source[9];
10758 // Use source `func` and merge bitmasks.
10759 data[0] = source[0];
10760 data[1] = newBitmask;
10766 * A specialized version of `_.pick` which picks `object` properties specified
10770 * @param {Object} object The source object.
10771 * @param {string[]} props The property names to pick.
10772 * @returns {Object} Returns the new object.
10774 function pickByArray(object, props) {
10775 object = toObject(object);
10778 length = props.length,
10781 while (++index < length) {
10782 var key = props[index];
10783 if (key in object) {
10784 result[key] = object[key];
10791 * A specialized version of `_.pick` which picks `object` properties `predicate`
10792 * returns truthy for.
10795 * @param {Object} object The source object.
10796 * @param {Function} predicate The function invoked per iteration.
10797 * @returns {Object} Returns the new object.
10799 function pickByCallback(object, predicate) {
10801 baseForIn(object, function(value, key, object) {
10802 if (predicate(value, key, object)) {
10803 result[key] = value;
10810 * Reorder `array` according to the specified indexes where the element at
10811 * the first index is assigned as the first element, the element at
10812 * the second index is assigned as the second element, and so on.
10815 * @param {Array} array The array to reorder.
10816 * @param {Array} indexes The arranged array indexes.
10817 * @returns {Array} Returns `array`.
10819 function reorder(array, indexes) {
10820 var arrLength = array.length,
10821 length = nativeMin(indexes.length, arrLength),
10822 oldArray = arrayCopy(array);
10825 var index = indexes[length];
10826 array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
10832 * Sets metadata for `func`.
10834 * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
10835 * period of time, it will trip its breaker and transition to an identity function
10836 * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070)
10837 * for more details.
10840 * @param {Function} func The function to associate metadata with.
10841 * @param {*} data The metadata.
10842 * @returns {Function} Returns `func`.
10844 var setData = (function() {
10848 return function(key, value) {
10850 remaining = HOT_SPAN - (stamp - lastCalled);
10852 lastCalled = stamp;
10853 if (remaining > 0) {
10854 if (++count >= HOT_COUNT) {
10860 return baseSetData(key, value);
10865 * A fallback implementation of `_.isPlainObject` which checks if `value`
10866 * is an object created by the `Object` constructor or has a `[[Prototype]]`
10870 * @param {*} value The value to check.
10871 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
10873 function shimIsPlainObject(value) {
10875 support = lodash.support;
10877 // Exit early for non `Object` objects.
10878 if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isHostObject(value)) ||
10879 (!hasOwnProperty.call(value, 'constructor') &&
10880 (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor))) ||
10881 (!support.argsTag && isArguments(value))) {
10884 // IE < 9 iterates inherited properties before own properties. If the first
10885 // iterated property is an object's own property then there are no inherited
10886 // enumerable properties.
10888 if (support.ownLast) {
10889 baseForIn(value, function(subValue, key, object) {
10890 result = hasOwnProperty.call(object, key);
10893 return result !== false;
10895 // In most environments an object's own properties are iterated before
10896 // its inherited properties. If the last iterated property is an object's
10897 // own property then there are no inherited enumerable properties.
10898 baseForIn(value, function(subValue, key) {
10901 return result === undefined || hasOwnProperty.call(value, result);
10905 * A fallback implementation of `Object.keys` which creates an array of the
10906 * own enumerable property names of `object`.
10909 * @param {Object} object The object to query.
10910 * @returns {Array} Returns the array of property names.
10912 function shimKeys(object) {
10913 var props = keysIn(object),
10914 propsLength = props.length,
10915 length = propsLength && object.length;
10917 var allowIndexes = !!length && isLength(length) &&
10918 (isArray(object) || isArguments(object) || isString(object));
10923 while (++index < propsLength) {
10924 var key = props[index];
10925 if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
10933 * Converts `value` to an object if it's not one.
10936 * @param {*} value The value to process.
10937 * @returns {Object} Returns the object.
10939 function toObject(value) {
10940 if (lodash.support.unindexedChars && isString(value)) {
10942 length = value.length,
10943 result = Object(value);
10945 while (++index < length) {
10946 result[index] = value.charAt(index);
10950 return isObject(value) ? value : Object(value);
10954 * Converts `value` to property path array if it's not one.
10957 * @param {*} value The value to process.
10958 * @returns {Array} Returns the property path array.
10960 function toPath(value) {
10961 if (isArray(value)) {
10965 baseToString(value).replace(rePropName, function(match, number, quote, string) {
10966 result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
10972 * Creates a clone of `wrapper`.
10975 * @param {Object} wrapper The wrapper to clone.
10976 * @returns {Object} Returns the cloned wrapper.
10978 function wrapperClone(wrapper) {
10979 return wrapper instanceof LazyWrapper
10981 : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__));
10984 /*------------------------------------------------------------------------*/
10987 * Creates an array of elements split into groups the length of `size`.
10988 * If `collection` can't be split evenly, the final chunk will be the remaining
10994 * @param {Array} array The array to process.
10995 * @param {number} [size=1] The length of each chunk.
10996 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
10997 * @returns {Array} Returns the new array containing chunks.
11000 * _.chunk(['a', 'b', 'c', 'd'], 2);
11001 * // => [['a', 'b'], ['c', 'd']]
11003 * _.chunk(['a', 'b', 'c', 'd'], 3);
11004 * // => [['a', 'b', 'c'], ['d']]
11006 function chunk(array, size, guard) {
11007 if (guard ? isIterateeCall(array, size, guard) : size == null) {
11010 size = nativeMax(+size || 1, 1);
11013 length = array ? array.length : 0,
11015 result = Array(ceil(length / size));
11017 while (index < length) {
11018 result[++resIndex] = baseSlice(array, index, (index += size));
11024 * Creates an array with all falsey values removed. The values `false`, `null`,
11025 * `0`, `""`, `undefined`, and `NaN` are falsey.
11030 * @param {Array} array The array to compact.
11031 * @returns {Array} Returns the new array of filtered values.
11034 * _.compact([0, 1, false, 2, '', 3]);
11037 function compact(array) {
11039 length = array ? array.length : 0,
11043 while (++index < length) {
11044 var value = array[index];
11046 result[++resIndex] = value;
11053 * Creates an array of unique `array` values not included in the other
11054 * provided arrays using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11055 * for equality comparisons.
11060 * @param {Array} array The array to inspect.
11061 * @param {...Array} [values] The arrays of values to exclude.
11062 * @returns {Array} Returns the new array of filtered values.
11065 * _.difference([1, 2, 3], [4, 2]);
11068 var difference = restParam(function(array, values) {
11069 return isArrayLike(array)
11070 ? baseDifference(array, baseFlatten(values, false, true))
11075 * Gets the first element of `array`.
11081 * @param {Array} array The array to query.
11082 * @returns {*} Returns the first element of `array`.
11085 * _.first([1, 2, 3]);
11091 function first(array) {
11092 return array ? array[0] : undefined;
11096 * Flattens a nested array. If `isDeep` is `true` the array is recursively
11097 * flattened, otherwise it is only flattened a single level.
11102 * @param {Array} array The array to flatten.
11103 * @param {boolean} [isDeep] Specify a deep flatten.
11104 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
11105 * @returns {Array} Returns the new flattened array.
11108 * _.flatten([1, [2, 3, [4]]]);
11109 * // => [1, 2, 3, [4]]
11111 * // using `isDeep`
11112 * _.flatten([1, [2, 3, [4]]], true);
11113 * // => [1, 2, 3, 4]
11115 function flatten(array, isDeep, guard) {
11116 var length = array ? array.length : 0;
11117 if (guard && isIterateeCall(array, isDeep, guard)) {
11120 return length ? baseFlatten(array, isDeep) : [];
11124 * Gets the index at which the first occurrence of `value` is found in `array`
11125 * using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11126 * for equality comparisons. If `fromIndex` is negative, it is used as the offset
11127 * from the end of `array`. If `array` is sorted providing `true` for `fromIndex`
11128 * performs a faster binary search.
11133 * @param {Array} array The array to search.
11134 * @param {*} value The value to search for.
11135 * @param {boolean|number} [fromIndex=0] The index to search from or `true`
11136 * to perform a binary search on a sorted array.
11137 * @returns {number} Returns the index of the matched value, else `-1`.
11140 * _.indexOf([1, 2, 1, 2], 2);
11143 * // using `fromIndex`
11144 * _.indexOf([1, 2, 1, 2], 2, 2);
11147 * // performing a binary search
11148 * _.indexOf([1, 1, 2, 2], 2, true);
11151 function indexOf(array, value, fromIndex) {
11152 var length = array ? array.length : 0;
11156 if (typeof fromIndex == 'number') {
11157 fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex;
11158 } else if (fromIndex) {
11159 var index = binaryIndex(array, value),
11160 other = array[index];
11162 if (value === value ? (value === other) : (other !== other)) {
11167 return baseIndexOf(array, value, fromIndex || 0);
11171 * Creates an array of unique values that are included in all of the provided
11172 * arrays using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11173 * for equality comparisons.
11178 * @param {...Array} [arrays] The arrays to inspect.
11179 * @returns {Array} Returns the new array of shared values.
11181 * _.intersection([1, 2], [4, 2], [2, 1]);
11184 var intersection = restParam(function(arrays) {
11185 var othLength = arrays.length,
11186 othIndex = othLength,
11187 caches = Array(length),
11188 indexOf = getIndexOf(),
11189 isCommon = indexOf == baseIndexOf,
11192 while (othIndex--) {
11193 var value = arrays[othIndex] = isArrayLike(value = arrays[othIndex]) ? value : [];
11194 caches[othIndex] = (isCommon && value.length >= 120) ? createCache(othIndex && value) : null;
11196 var array = arrays[0],
11198 length = array ? array.length : 0,
11202 while (++index < length) {
11203 value = array[index];
11204 if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) {
11205 var othIndex = othLength;
11206 while (--othIndex) {
11207 var cache = caches[othIndex];
11208 if ((cache ? cacheIndexOf(cache, value) : indexOf(arrays[othIndex], value, 0)) < 0) {
11215 result.push(value);
11222 * Gets the last element of `array`.
11227 * @param {Array} array The array to query.
11228 * @returns {*} Returns the last element of `array`.
11231 * _.last([1, 2, 3]);
11234 function last(array) {
11235 var length = array ? array.length : 0;
11236 return length ? array[length - 1] : undefined;
11240 * Creates an array of unique values, in order, from all of the provided arrays
11241 * using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11242 * for equality comparisons.
11247 * @param {...Array} [arrays] The arrays to inspect.
11248 * @returns {Array} Returns the new array of combined values.
11251 * _.union([1, 2], [4, 2], [2, 1]);
11254 var union = restParam(function(arrays) {
11255 return baseUniq(baseFlatten(arrays, false, true));
11259 * Creates a duplicate-free version of an array, using
11260 * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11261 * for equality comparisons, in which only the first occurence of each element
11262 * is kept. Providing `true` for `isSorted` performs a faster search algorithm
11263 * for sorted arrays. If an iteratee function is provided it is invoked for
11264 * each element in the array to generate the criterion by which uniqueness
11265 * is computed. The `iteratee` is bound to `thisArg` and invoked with three
11266 * arguments: (value, index, array).
11268 * If a property name is provided for `iteratee` the created `_.property`
11269 * style callback returns the property value of the given element.
11271 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11272 * style callback returns `true` for elements that have a matching property
11273 * value, else `false`.
11275 * If an object is provided for `iteratee` the created `_.matches` style
11276 * callback returns `true` for elements that have the properties of the given
11277 * object, else `false`.
11283 * @param {Array} array The array to inspect.
11284 * @param {boolean} [isSorted] Specify the array is sorted.
11285 * @param {Function|Object|string} [iteratee] The function invoked per iteration.
11286 * @param {*} [thisArg] The `this` binding of `iteratee`.
11287 * @returns {Array} Returns the new duplicate-value-free array.
11290 * _.uniq([2, 1, 2]);
11293 * // using `isSorted`
11294 * _.uniq([1, 1, 2], true);
11297 * // using an iteratee function
11298 * _.uniq([1, 2.5, 1.5, 2], function(n) {
11299 * return this.floor(n);
11303 * // using the `_.property` callback shorthand
11304 * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
11305 * // => [{ 'x': 1 }, { 'x': 2 }]
11307 function uniq(array, isSorted, iteratee, thisArg) {
11308 var length = array ? array.length : 0;
11312 if (isSorted != null && typeof isSorted != 'boolean') {
11313 thisArg = iteratee;
11314 iteratee = isIterateeCall(array, isSorted, thisArg) ? null : isSorted;
11317 var callback = getCallback();
11318 if (!(iteratee == null && callback === baseCallback)) {
11319 iteratee = callback(iteratee, thisArg, 3);
11321 return (isSorted && getIndexOf() == baseIndexOf)
11322 ? sortedUniq(array, iteratee)
11323 : baseUniq(array, iteratee);
11327 * Creates an array excluding all provided values using
11328 * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11329 * for equality comparisons.
11334 * @param {Array} array The array to filter.
11335 * @param {...*} [values] The values to exclude.
11336 * @returns {Array} Returns the new array of filtered values.
11339 * _.without([1, 2, 1, 3], 1, 2);
11342 var without = restParam(function(array, values) {
11343 return isArrayLike(array)
11344 ? baseDifference(array, values)
11348 /*------------------------------------------------------------------------*/
11351 * Creates a `lodash` object that wraps `value` with explicit method
11352 * chaining enabled.
11357 * @param {*} value The value to wrap.
11358 * @returns {Object} Returns the new `lodash` wrapper instance.
11362 * { 'user': 'barney', 'age': 36 },
11363 * { 'user': 'fred', 'age': 40 },
11364 * { 'user': 'pebbles', 'age': 1 }
11367 * var youngest = _.chain(users)
11369 * .map(function(chr) {
11370 * return chr.user + ' is ' + chr.age;
11374 * // => 'pebbles is 1'
11376 function chain(value) {
11377 var result = lodash(value);
11378 result.__chain__ = true;
11383 * This method invokes `interceptor` and returns `value`. The interceptor is
11384 * bound to `thisArg` and invoked with one argument; (value). The purpose of
11385 * this method is to "tap into" a method chain in order to perform operations
11386 * on intermediate results within the chain.
11391 * @param {*} value The value to provide to `interceptor`.
11392 * @param {Function} interceptor The function to invoke.
11393 * @param {*} [thisArg] The `this` binding of `interceptor`.
11394 * @returns {*} Returns `value`.
11398 * .tap(function(array) {
11405 function tap(value, interceptor, thisArg) {
11406 interceptor.call(thisArg, value);
11411 * This method is like `_.tap` except that it returns the result of `interceptor`.
11416 * @param {*} value The value to provide to `interceptor`.
11417 * @param {Function} interceptor The function to invoke.
11418 * @param {*} [thisArg] The `this` binding of `interceptor`.
11419 * @returns {*} Returns the result of `interceptor`.
11425 * .thru(function(value) {
11431 function thru(value, interceptor, thisArg) {
11432 return interceptor.call(thisArg, value);
11436 * Enables explicit method chaining on the wrapper object.
11441 * @returns {Object} Returns the new `lodash` wrapper instance.
11445 * { 'user': 'barney', 'age': 36 },
11446 * { 'user': 'fred', 'age': 40 }
11449 * // without explicit chaining
11450 * _(users).first();
11451 * // => { 'user': 'barney', 'age': 36 }
11453 * // with explicit chaining
11458 * // => { 'user': 'barney' }
11460 function wrapperChain() {
11461 return chain(this);
11465 * Executes the chained sequence and returns the wrapped result.
11470 * @returns {Object} Returns the new `lodash` wrapper instance.
11473 * var array = [1, 2];
11474 * var wrapper = _(array).push(3);
11476 * console.log(array);
11479 * wrapper = wrapper.commit();
11480 * console.log(array);
11486 * console.log(array);
11489 function wrapperCommit() {
11490 return new LodashWrapper(this.value(), this.__chain__);
11494 * Creates a clone of the chained sequence planting `value` as the wrapped value.
11499 * @returns {Object} Returns the new `lodash` wrapper instance.
11502 * var array = [1, 2];
11503 * var wrapper = _(array).map(function(value) {
11504 * return Math.pow(value, 2);
11507 * var other = [3, 4];
11508 * var otherWrapper = wrapper.plant(other);
11510 * otherWrapper.value();
11516 function wrapperPlant(value) {
11520 while (parent instanceof baseLodash) {
11521 var clone = wrapperClone(parent);
11523 previous.__wrapped__ = clone;
11527 var previous = clone;
11528 parent = parent.__wrapped__;
11530 previous.__wrapped__ = value;
11535 * Reverses the wrapped array so the first element becomes the last, the
11536 * second element becomes the second to last, and so on.
11538 * **Note:** This method mutates the wrapped array.
11543 * @returns {Object} Returns the new reversed `lodash` wrapper instance.
11546 * var array = [1, 2, 3];
11548 * _(array).reverse().value()
11551 * console.log(array);
11554 function wrapperReverse() {
11555 var value = this.__wrapped__;
11556 if (value instanceof LazyWrapper) {
11557 if (this.__actions__.length) {
11558 value = new LazyWrapper(this);
11560 return new LodashWrapper(value.reverse(), this.__chain__);
11562 return this.thru(function(value) {
11563 return value.reverse();
11568 * Produces the result of coercing the unwrapped value to a string.
11573 * @returns {string} Returns the coerced string value.
11576 * _([1, 2, 3]).toString();
11579 function wrapperToString() {
11580 return (this.value() + '');
11584 * Executes the chained sequence to extract the unwrapped value.
11588 * @alias run, toJSON, valueOf
11590 * @returns {*} Returns the resolved unwrapped value.
11593 * _([1, 2, 3]).value();
11596 function wrapperValue() {
11597 return baseWrapperValue(this.__wrapped__, this.__actions__);
11600 /*------------------------------------------------------------------------*/
11603 * Checks if `predicate` returns truthy for **all** elements of `collection`.
11604 * The predicate is bound to `thisArg` and invoked with three arguments:
11605 * (value, index|key, collection).
11607 * If a property name is provided for `predicate` the created `_.property`
11608 * style callback returns the property value of the given element.
11610 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11611 * style callback returns `true` for elements that have a matching property
11612 * value, else `false`.
11614 * If an object is provided for `predicate` the created `_.matches` style
11615 * callback returns `true` for elements that have the properties of the given
11616 * object, else `false`.
11621 * @category Collection
11622 * @param {Array|Object|string} collection The collection to iterate over.
11623 * @param {Function|Object|string} [predicate=_.identity] The function invoked
11625 * @param {*} [thisArg] The `this` binding of `predicate`.
11626 * @returns {boolean} Returns `true` if all elements pass the predicate check,
11630 * _.every([true, 1, null, 'yes'], Boolean);
11634 * { 'user': 'barney', 'active': false },
11635 * { 'user': 'fred', 'active': false }
11638 * // using the `_.matches` callback shorthand
11639 * _.every(users, { 'user': 'barney', 'active': false });
11642 * // using the `_.matchesProperty` callback shorthand
11643 * _.every(users, 'active', false);
11646 * // using the `_.property` callback shorthand
11647 * _.every(users, 'active');
11650 function every(collection, predicate, thisArg) {
11651 var func = isArray(collection) ? arrayEvery : baseEvery;
11652 if (thisArg && isIterateeCall(collection, predicate, thisArg)) {
11655 if (typeof predicate != 'function' || thisArg !== undefined) {
11656 predicate = getCallback(predicate, thisArg, 3);
11658 return func(collection, predicate);
11662 * Iterates over elements of `collection`, returning an array of all elements
11663 * `predicate` returns truthy for. The predicate is bound to `thisArg` and
11664 * invoked with three arguments: (value, index|key, collection).
11666 * If a property name is provided for `predicate` the created `_.property`
11667 * style callback returns the property value of the given element.
11669 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11670 * style callback returns `true` for elements that have a matching property
11671 * value, else `false`.
11673 * If an object is provided for `predicate` the created `_.matches` style
11674 * callback returns `true` for elements that have the properties of the given
11675 * object, else `false`.
11680 * @category Collection
11681 * @param {Array|Object|string} collection The collection to iterate over.
11682 * @param {Function|Object|string} [predicate=_.identity] The function invoked
11684 * @param {*} [thisArg] The `this` binding of `predicate`.
11685 * @returns {Array} Returns the new filtered array.
11688 * _.filter([4, 5, 6], function(n) {
11689 * return n % 2 == 0;
11694 * { 'user': 'barney', 'age': 36, 'active': true },
11695 * { 'user': 'fred', 'age': 40, 'active': false }
11698 * // using the `_.matches` callback shorthand
11699 * _.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user');
11702 * // using the `_.matchesProperty` callback shorthand
11703 * _.pluck(_.filter(users, 'active', false), 'user');
11706 * // using the `_.property` callback shorthand
11707 * _.pluck(_.filter(users, 'active'), 'user');
11710 function filter(collection, predicate, thisArg) {
11711 var func = isArray(collection) ? arrayFilter : baseFilter;
11712 predicate = getCallback(predicate, thisArg, 3);
11713 return func(collection, predicate);
11717 * Iterates over elements of `collection`, returning the first element
11718 * `predicate` returns truthy for. The predicate is bound to `thisArg` and
11719 * invoked with three arguments: (value, index|key, collection).
11721 * If a property name is provided for `predicate` the created `_.property`
11722 * style callback returns the property value of the given element.
11724 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11725 * style callback returns `true` for elements that have a matching property
11726 * value, else `false`.
11728 * If an object is provided for `predicate` the created `_.matches` style
11729 * callback returns `true` for elements that have the properties of the given
11730 * object, else `false`.
11735 * @category Collection
11736 * @param {Array|Object|string} collection The collection to search.
11737 * @param {Function|Object|string} [predicate=_.identity] The function invoked
11739 * @param {*} [thisArg] The `this` binding of `predicate`.
11740 * @returns {*} Returns the matched element, else `undefined`.
11744 * { 'user': 'barney', 'age': 36, 'active': true },
11745 * { 'user': 'fred', 'age': 40, 'active': false },
11746 * { 'user': 'pebbles', 'age': 1, 'active': true }
11749 * _.result(_.find(users, function(chr) {
11750 * return chr.age < 40;
11754 * // using the `_.matches` callback shorthand
11755 * _.result(_.find(users, { 'age': 1, 'active': true }), 'user');
11758 * // using the `_.matchesProperty` callback shorthand
11759 * _.result(_.find(users, 'active', false), 'user');
11762 * // using the `_.property` callback shorthand
11763 * _.result(_.find(users, 'active'), 'user');
11766 var find = createFind(baseEach);
11769 * Iterates over elements of `collection` invoking `iteratee` for each element.
11770 * The `iteratee` is bound to `thisArg` and invoked with three arguments:
11771 * (value, index|key, collection). Iteratee functions may exit iteration early
11772 * by explicitly returning `false`.
11774 * **Note:** As with other "Collections" methods, objects with a "length" property
11775 * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
11776 * may be used for object iteration.
11781 * @category Collection
11782 * @param {Array|Object|string} collection The collection to iterate over.
11783 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
11784 * @param {*} [thisArg] The `this` binding of `iteratee`.
11785 * @returns {Array|Object|string} Returns `collection`.
11788 * _([1, 2]).forEach(function(n) {
11791 * // => logs each value from left to right and returns the array
11793 * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) {
11794 * console.log(n, key);
11796 * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
11798 var forEach = createForEach(arrayEach, baseEach);
11801 * Creates an object composed of keys generated from the results of running
11802 * each element of `collection` through `iteratee`. The corresponding value
11803 * of each key is an array of the elements responsible for generating the key.
11804 * The `iteratee` is bound to `thisArg` and invoked with three arguments:
11805 * (value, index|key, collection).
11807 * If a property name is provided for `iteratee` the created `_.property`
11808 * style callback returns the property value of the given element.
11810 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11811 * style callback returns `true` for elements that have a matching property
11812 * value, else `false`.
11814 * If an object is provided for `iteratee` the created `_.matches` style
11815 * callback returns `true` for elements that have the properties of the given
11816 * object, else `false`.
11820 * @category Collection
11821 * @param {Array|Object|string} collection The collection to iterate over.
11822 * @param {Function|Object|string} [iteratee=_.identity] The function invoked
11824 * @param {*} [thisArg] The `this` binding of `iteratee`.
11825 * @returns {Object} Returns the composed aggregate object.
11828 * _.groupBy([4.2, 6.1, 6.4], function(n) {
11829 * return Math.floor(n);
11831 * // => { '4': [4.2], '6': [6.1, 6.4] }
11833 * _.groupBy([4.2, 6.1, 6.4], function(n) {
11834 * return this.floor(n);
11836 * // => { '4': [4.2], '6': [6.1, 6.4] }
11838 * // using the `_.property` callback shorthand
11839 * _.groupBy(['one', 'two', 'three'], 'length');
11840 * // => { '3': ['one', 'two'], '5': ['three'] }
11842 var groupBy = createAggregator(function(result, value, key) {
11843 if (hasOwnProperty.call(result, key)) {
11844 result[key].push(value);
11846 result[key] = [value];
11851 * Checks if `value` is in `collection` using
11852 * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11853 * for equality comparisons. If `fromIndex` is negative, it is used as the offset
11854 * from the end of `collection`.
11858 * @alias contains, include
11859 * @category Collection
11860 * @param {Array|Object|string} collection The collection to search.
11861 * @param {*} target The value to search for.
11862 * @param {number} [fromIndex=0] The index to search from.
11863 * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`.
11864 * @returns {boolean} Returns `true` if a matching element is found, else `false`.
11867 * _.includes([1, 2, 3], 1);
11870 * _.includes([1, 2, 3], 1, 2);
11873 * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
11876 * _.includes('pebbles', 'eb');
11879 function includes(collection, target, fromIndex, guard) {
11880 var length = collection ? getLength(collection) : 0;
11881 if (!isLength(length)) {
11882 collection = values(collection);
11883 length = collection.length;
11888 if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) {
11891 fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
11893 return (typeof collection == 'string' || !isArray(collection) && isString(collection))
11894 ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1)
11895 : (getIndexOf(collection, target, fromIndex) > -1);
11899 * Creates an array of values by running each element in `collection` through
11900 * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three
11901 * arguments: (value, index|key, collection).
11903 * If a property name is provided for `iteratee` the created `_.property`
11904 * style callback returns the property value of the given element.
11906 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11907 * style callback returns `true` for elements that have a matching property
11908 * value, else `false`.
11910 * If an object is provided for `iteratee` the created `_.matches` style
11911 * callback returns `true` for elements that have the properties of the given
11912 * object, else `false`.
11914 * Many lodash methods are guarded to work as iteratees for methods like
11915 * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
11917 * The guarded methods are:
11918 * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`,
11919 * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`,
11920 * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`,
11921 * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`,
11922 * `sum`, `uniq`, and `words`
11927 * @category Collection
11928 * @param {Array|Object|string} collection The collection to iterate over.
11929 * @param {Function|Object|string} [iteratee=_.identity] The function invoked
11931 * @param {*} [thisArg] The `this` binding of `iteratee`.
11932 * @returns {Array} Returns the new mapped array.
11935 * function timesThree(n) {
11939 * _.map([1, 2], timesThree);
11942 * _.map({ 'a': 1, 'b': 2 }, timesThree);
11943 * // => [3, 6] (iteration order is not guaranteed)
11946 * { 'user': 'barney' },
11947 * { 'user': 'fred' }
11950 * // using the `_.property` callback shorthand
11951 * _.map(users, 'user');
11952 * // => ['barney', 'fred']
11954 function map(collection, iteratee, thisArg) {
11955 var func = isArray(collection) ? arrayMap : baseMap;
11956 iteratee = getCallback(iteratee, thisArg, 3);
11957 return func(collection, iteratee);
11961 * Gets the property value of `path` from all elements in `collection`.
11965 * @category Collection
11966 * @param {Array|Object|string} collection The collection to iterate over.
11967 * @param {Array|string} path The path of the property to pluck.
11968 * @returns {Array} Returns the property values.
11972 * { 'user': 'barney', 'age': 36 },
11973 * { 'user': 'fred', 'age': 40 }
11976 * _.pluck(users, 'user');
11977 * // => ['barney', 'fred']
11979 * var userIndex = _.indexBy(users, 'user');
11980 * _.pluck(userIndex, 'age');
11981 * // => [36, 40] (iteration order is not guaranteed)
11983 function pluck(collection, path) {
11984 return map(collection, property(path));
11988 * Reduces `collection` to a value which is the accumulated result of running
11989 * each element in `collection` through `iteratee`, where each successive
11990 * invocation is supplied the return value of the previous. If `accumulator`
11991 * is not provided the first element of `collection` is used as the initial
11992 * value. The `iteratee` is bound to `thisArg` and invoked with four arguments:
11993 * (accumulator, value, index|key, collection).
11995 * Many lodash methods are guarded to work as iteratees for methods like
11996 * `_.reduce`, `_.reduceRight`, and `_.transform`.
11998 * The guarded methods are:
11999 * `assign`, `defaults`, `includes`, `merge`, `sortByAll`, and `sortByOrder`
12003 * @alias foldl, inject
12004 * @category Collection
12005 * @param {Array|Object|string} collection The collection to iterate over.
12006 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12007 * @param {*} [accumulator] The initial value.
12008 * @param {*} [thisArg] The `this` binding of `iteratee`.
12009 * @returns {*} Returns the accumulated value.
12012 * _.reduce([1, 2], function(total, n) {
12013 * return total + n;
12017 * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) {
12018 * result[key] = n * 3;
12021 * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed)
12023 var reduce = createReduce(arrayReduce, baseEach);
12026 * The opposite of `_.filter`; this method returns the elements of `collection`
12027 * that `predicate` does **not** return truthy for.
12031 * @category Collection
12032 * @param {Array|Object|string} collection The collection to iterate over.
12033 * @param {Function|Object|string} [predicate=_.identity] The function invoked
12035 * @param {*} [thisArg] The `this` binding of `predicate`.
12036 * @returns {Array} Returns the new filtered array.
12039 * _.reject([1, 2, 3, 4], function(n) {
12040 * return n % 2 == 0;
12045 * { 'user': 'barney', 'age': 36, 'active': false },
12046 * { 'user': 'fred', 'age': 40, 'active': true }
12049 * // using the `_.matches` callback shorthand
12050 * _.pluck(_.reject(users, { 'age': 40, 'active': true }), 'user');
12053 * // using the `_.matchesProperty` callback shorthand
12054 * _.pluck(_.reject(users, 'active', false), 'user');
12057 * // using the `_.property` callback shorthand
12058 * _.pluck(_.reject(users, 'active'), 'user');
12061 function reject(collection, predicate, thisArg) {
12062 var func = isArray(collection) ? arrayFilter : baseFilter;
12063 predicate = getCallback(predicate, thisArg, 3);
12064 return func(collection, function(value, index, collection) {
12065 return !predicate(value, index, collection);
12070 * Checks if `predicate` returns truthy for **any** element of `collection`.
12071 * The function returns as soon as it finds a passing value and does not iterate
12072 * over the entire collection. The predicate is bound to `thisArg` and invoked
12073 * with three arguments: (value, index|key, collection).
12075 * If a property name is provided for `predicate` the created `_.property`
12076 * style callback returns the property value of the given element.
12078 * If a value is also provided for `thisArg` the created `_.matchesProperty`
12079 * style callback returns `true` for elements that have a matching property
12080 * value, else `false`.
12082 * If an object is provided for `predicate` the created `_.matches` style
12083 * callback returns `true` for elements that have the properties of the given
12084 * object, else `false`.
12089 * @category Collection
12090 * @param {Array|Object|string} collection The collection to iterate over.
12091 * @param {Function|Object|string} [predicate=_.identity] The function invoked
12093 * @param {*} [thisArg] The `this` binding of `predicate`.
12094 * @returns {boolean} Returns `true` if any element passes the predicate check,
12098 * _.some([null, 0, 'yes', false], Boolean);
12102 * { 'user': 'barney', 'active': true },
12103 * { 'user': 'fred', 'active': false }
12106 * // using the `_.matches` callback shorthand
12107 * _.some(users, { 'user': 'barney', 'active': false });
12110 * // using the `_.matchesProperty` callback shorthand
12111 * _.some(users, 'active', false);
12114 * // using the `_.property` callback shorthand
12115 * _.some(users, 'active');
12118 function some(collection, predicate, thisArg) {
12119 var func = isArray(collection) ? arraySome : baseSome;
12120 if (thisArg && isIterateeCall(collection, predicate, thisArg)) {
12123 if (typeof predicate != 'function' || thisArg !== undefined) {
12124 predicate = getCallback(predicate, thisArg, 3);
12126 return func(collection, predicate);
12129 /*------------------------------------------------------------------------*/
12132 * Gets the number of milliseconds that have elapsed since the Unix epoch
12133 * (1 January 1970 00:00:00 UTC).
12140 * _.defer(function(stamp) {
12141 * console.log(_.now() - stamp);
12143 * // => logs the number of milliseconds it took for the deferred function to be invoked
12145 var now = nativeNow || function() {
12146 return new Date().getTime();
12149 /*------------------------------------------------------------------------*/
12152 * Creates a function that invokes `func` with the `this` binding of `thisArg`
12153 * and prepends any additional `_.bind` arguments to those provided to the
12156 * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
12157 * may be used as a placeholder for partially applied arguments.
12159 * **Note:** Unlike native `Function#bind` this method does not set the "length"
12160 * property of bound functions.
12164 * @category Function
12165 * @param {Function} func The function to bind.
12166 * @param {*} thisArg The `this` binding of `func`.
12167 * @param {...*} [partials] The arguments to be partially applied.
12168 * @returns {Function} Returns the new bound function.
12171 * var greet = function(greeting, punctuation) {
12172 * return greeting + ' ' + this.user + punctuation;
12175 * var object = { 'user': 'fred' };
12177 * var bound = _.bind(greet, object, 'hi');
12181 * // using placeholders
12182 * var bound = _.bind(greet, object, _, '!');
12186 var bind = restParam(function(func, thisArg, partials) {
12187 var bitmask = BIND_FLAG;
12188 if (partials.length) {
12189 var holders = replaceHolders(partials, bind.placeholder);
12190 bitmask |= PARTIAL_FLAG;
12192 return createWrapper(func, bitmask, thisArg, partials, holders);
12196 * Creates a debounced function that delays invoking `func` until after `wait`
12197 * milliseconds have elapsed since the last time the debounced function was
12198 * invoked. The debounced function comes with a `cancel` method to cancel
12199 * delayed invocations. Provide an options object to indicate that `func`
12200 * should be invoked on the leading and/or trailing edge of the `wait` timeout.
12201 * Subsequent calls to the debounced function return the result of the last
12202 * `func` invocation.
12204 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
12205 * on the trailing edge of the timeout only if the the debounced function is
12206 * invoked more than once during the `wait` timeout.
12208 * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
12209 * for details over the differences between `_.debounce` and `_.throttle`.
12213 * @category Function
12214 * @param {Function} func The function to debounce.
12215 * @param {number} [wait=0] The number of milliseconds to delay.
12216 * @param {Object} [options] The options object.
12217 * @param {boolean} [options.leading=false] Specify invoking on the leading
12218 * edge of the timeout.
12219 * @param {number} [options.maxWait] The maximum time `func` is allowed to be
12220 * delayed before it is invoked.
12221 * @param {boolean} [options.trailing=true] Specify invoking on the trailing
12222 * edge of the timeout.
12223 * @returns {Function} Returns the new debounced function.
12226 * // avoid costly calculations while the window size is in flux
12227 * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
12229 * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
12230 * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
12232 * 'trailing': false
12235 * // ensure `batchLog` is invoked once after 1 second of debounced calls
12236 * var source = new EventSource('/stream');
12237 * jQuery(source).on('message', _.debounce(batchLog, 250, {
12241 * // cancel a debounced call
12242 * var todoChanges = _.debounce(batchLog, 1000);
12243 * Object.observe(models.todo, todoChanges);
12245 * Object.observe(models, function(changes) {
12246 * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
12247 * todoChanges.cancel();
12251 * // ...at some point `models.todo` is changed
12252 * models.todo.completed = true;
12254 * // ...before 1 second has passed `models.todo` is deleted
12255 * // which cancels the debounced `todoChanges` call
12256 * delete models.todo;
12258 function debounce(func, wait, options) {
12270 if (typeof func != 'function') {
12271 throw new TypeError(FUNC_ERROR_TEXT);
12273 wait = wait < 0 ? 0 : (+wait || 0);
12274 if (options === true) {
12275 var leading = true;
12277 } else if (isObject(options)) {
12278 leading = options.leading;
12279 maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);
12280 trailing = 'trailing' in options ? options.trailing : trailing;
12283 function cancel() {
12285 clearTimeout(timeoutId);
12287 if (maxTimeoutId) {
12288 clearTimeout(maxTimeoutId);
12290 maxTimeoutId = timeoutId = trailingCall = undefined;
12293 function delayed() {
12294 var remaining = wait - (now() - stamp);
12295 if (remaining <= 0 || remaining > wait) {
12296 if (maxTimeoutId) {
12297 clearTimeout(maxTimeoutId);
12299 var isCalled = trailingCall;
12300 maxTimeoutId = timeoutId = trailingCall = undefined;
12302 lastCalled = now();
12303 result = func.apply(thisArg, args);
12304 if (!timeoutId && !maxTimeoutId) {
12305 args = thisArg = null;
12309 timeoutId = setTimeout(delayed, remaining);
12313 function maxDelayed() {
12315 clearTimeout(timeoutId);
12317 maxTimeoutId = timeoutId = trailingCall = undefined;
12318 if (trailing || (maxWait !== wait)) {
12319 lastCalled = now();
12320 result = func.apply(thisArg, args);
12321 if (!timeoutId && !maxTimeoutId) {
12322 args = thisArg = null;
12327 function debounced() {
12331 trailingCall = trailing && (timeoutId || !leading);
12333 if (maxWait === false) {
12334 var leadingCall = leading && !timeoutId;
12336 if (!maxTimeoutId && !leading) {
12337 lastCalled = stamp;
12339 var remaining = maxWait - (stamp - lastCalled),
12340 isCalled = remaining <= 0 || remaining > maxWait;
12343 if (maxTimeoutId) {
12344 maxTimeoutId = clearTimeout(maxTimeoutId);
12346 lastCalled = stamp;
12347 result = func.apply(thisArg, args);
12349 else if (!maxTimeoutId) {
12350 maxTimeoutId = setTimeout(maxDelayed, remaining);
12353 if (isCalled && timeoutId) {
12354 timeoutId = clearTimeout(timeoutId);
12356 else if (!timeoutId && wait !== maxWait) {
12357 timeoutId = setTimeout(delayed, wait);
12361 result = func.apply(thisArg, args);
12363 if (isCalled && !timeoutId && !maxTimeoutId) {
12364 args = thisArg = null;
12368 debounced.cancel = cancel;
12373 * Creates a function that invokes `func` with the `this` binding of the
12374 * created function and arguments from `start` and beyond provided as an array.
12376 * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters).
12380 * @category Function
12381 * @param {Function} func The function to apply a rest parameter to.
12382 * @param {number} [start=func.length-1] The start position of the rest parameter.
12383 * @returns {Function} Returns the new function.
12386 * var say = _.restParam(function(what, names) {
12387 * return what + ' ' + _.initial(names).join(', ') +
12388 * (_.size(names) > 1 ? ', & ' : '') + _.last(names);
12391 * say('hello', 'fred', 'barney', 'pebbles');
12392 * // => 'hello fred, barney, & pebbles'
12394 function restParam(func, start) {
12395 if (typeof func != 'function') {
12396 throw new TypeError(FUNC_ERROR_TEXT);
12398 start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);
12399 return function() {
12400 var args = arguments,
12402 length = nativeMax(args.length - start, 0),
12403 rest = Array(length);
12405 while (++index < length) {
12406 rest[index] = args[start + index];
12409 case 0: return func.call(this, rest);
12410 case 1: return func.call(this, args[0], rest);
12411 case 2: return func.call(this, args[0], args[1], rest);
12413 var otherArgs = Array(start + 1);
12415 while (++index < start) {
12416 otherArgs[index] = args[index];
12418 otherArgs[start] = rest;
12419 return func.apply(this, otherArgs);
12424 * Creates a throttled function that only invokes `func` at most once per
12425 * every `wait` milliseconds. The throttled function comes with a `cancel`
12426 * method to cancel delayed invocations. Provide an options object to indicate
12427 * that `func` should be invoked on the leading and/or trailing edge of the
12428 * `wait` timeout. Subsequent calls to the throttled function return the
12429 * result of the last `func` call.
12431 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
12432 * on the trailing edge of the timeout only if the the throttled function is
12433 * invoked more than once during the `wait` timeout.
12435 * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
12436 * for details over the differences between `_.throttle` and `_.debounce`.
12440 * @category Function
12441 * @param {Function} func The function to throttle.
12442 * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
12443 * @param {Object} [options] The options object.
12444 * @param {boolean} [options.leading=true] Specify invoking on the leading
12445 * edge of the timeout.
12446 * @param {boolean} [options.trailing=true] Specify invoking on the trailing
12447 * edge of the timeout.
12448 * @returns {Function} Returns the new throttled function.
12451 * // avoid excessively updating the position while scrolling
12452 * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
12454 * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes
12455 * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
12456 * 'trailing': false
12459 * // cancel a trailing throttled call
12460 * jQuery(window).on('popstate', throttled.cancel);
12462 function throttle(func, wait, options) {
12463 var leading = true,
12466 if (typeof func != 'function') {
12467 throw new TypeError(FUNC_ERROR_TEXT);
12469 if (options === false) {
12471 } else if (isObject(options)) {
12472 leading = 'leading' in options ? !!options.leading : leading;
12473 trailing = 'trailing' in options ? !!options.trailing : trailing;
12475 debounceOptions.leading = leading;
12476 debounceOptions.maxWait = +wait;
12477 debounceOptions.trailing = trailing;
12478 return debounce(func, wait, debounceOptions);
12481 /*------------------------------------------------------------------------*/
12484 * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
12485 * otherwise they are assigned by reference. If `customizer` is provided it is
12486 * invoked to produce the cloned values. If `customizer` returns `undefined`
12487 * cloning is handled by the method instead. The `customizer` is bound to
12488 * `thisArg` and invoked with two argument; (value [, index|key, object]).
12490 * **Note:** This method is loosely based on the
12491 * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm).
12492 * The enumerable properties of `arguments` objects and objects created by
12493 * constructors other than `Object` are cloned to plain `Object` objects. An
12494 * empty object is returned for uncloneable values such as functions, DOM nodes,
12495 * Maps, Sets, and WeakMaps.
12500 * @param {*} value The value to clone.
12501 * @param {boolean} [isDeep] Specify a deep clone.
12502 * @param {Function} [customizer] The function to customize cloning values.
12503 * @param {*} [thisArg] The `this` binding of `customizer`.
12504 * @returns {*} Returns the cloned value.
12508 * { 'user': 'barney' },
12509 * { 'user': 'fred' }
12512 * var shallow = _.clone(users);
12513 * shallow[0] === users[0];
12516 * var deep = _.clone(users, true);
12517 * deep[0] === users[0];
12520 * // using a customizer callback
12521 * var el = _.clone(document.body, function(value) {
12522 * if (_.isElement(value)) {
12523 * return value.cloneNode(false);
12527 * el === document.body
12531 * el.childNodes.length;
12534 function clone(value, isDeep, customizer, thisArg) {
12535 if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) {
12538 else if (typeof isDeep == 'function') {
12539 thisArg = customizer;
12540 customizer = isDeep;
12543 return typeof customizer == 'function'
12544 ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 1))
12545 : baseClone(value, isDeep);
12549 * Creates a deep clone of `value`. If `customizer` is provided it is invoked
12550 * to produce the cloned values. If `customizer` returns `undefined` cloning
12551 * is handled by the method instead. The `customizer` is bound to `thisArg`
12552 * and invoked with two argument; (value [, index|key, object]).
12554 * **Note:** This method is loosely based on the
12555 * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm).
12556 * The enumerable properties of `arguments` objects and objects created by
12557 * constructors other than `Object` are cloned to plain `Object` objects. An
12558 * empty object is returned for uncloneable values such as functions, DOM nodes,
12559 * Maps, Sets, and WeakMaps.
12564 * @param {*} value The value to deep clone.
12565 * @param {Function} [customizer] The function to customize cloning values.
12566 * @param {*} [thisArg] The `this` binding of `customizer`.
12567 * @returns {*} Returns the deep cloned value.
12571 * { 'user': 'barney' },
12572 * { 'user': 'fred' }
12575 * var deep = _.cloneDeep(users);
12576 * deep[0] === users[0];
12579 * // using a customizer callback
12580 * var el = _.cloneDeep(document.body, function(value) {
12581 * if (_.isElement(value)) {
12582 * return value.cloneNode(true);
12586 * el === document.body
12590 * el.childNodes.length;
12593 function cloneDeep(value, customizer, thisArg) {
12594 return typeof customizer == 'function'
12595 ? baseClone(value, true, bindCallback(customizer, thisArg, 1))
12596 : baseClone(value, true);
12600 * Checks if `value` is classified as an `arguments` object.
12605 * @param {*} value The value to check.
12606 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
12609 * _.isArguments(function() { return arguments; }());
12612 * _.isArguments([1, 2, 3]);
12615 function isArguments(value) {
12616 return isObjectLike(value) && isArrayLike(value) && objToString.call(value) == argsTag;
12618 // Fallback for environments without a `toStringTag` for `arguments` objects.
12619 if (!support.argsTag) {
12620 isArguments = function(value) {
12621 return isObjectLike(value) && isArrayLike(value) &&
12622 hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee');
12627 * Checks if `value` is classified as an `Array` object.
12632 * @param {*} value The value to check.
12633 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
12636 * _.isArray([1, 2, 3]);
12639 * _.isArray(function() { return arguments; }());
12642 var isArray = nativeIsArray || function(value) {
12643 return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
12647 * Checks if `value` is empty. A value is considered empty unless it is an
12648 * `arguments` object, array, string, or jQuery-like collection with a length
12649 * greater than `0` or an object with own enumerable properties.
12654 * @param {Array|Object|string} value The value to inspect.
12655 * @returns {boolean} Returns `true` if `value` is empty, else `false`.
12667 * _.isEmpty([1, 2, 3]);
12670 * _.isEmpty({ 'a': 1 });
12673 function isEmpty(value) {
12674 if (value == null) {
12677 if (isArrayLike(value) && (isArray(value) || isString(value) || isArguments(value) ||
12678 (isObjectLike(value) && isFunction(value.splice)))) {
12679 return !value.length;
12681 return !keys(value).length;
12685 * Performs a deep comparison between two values to determine if they are
12686 * equivalent. If `customizer` is provided it is invoked to compare values.
12687 * If `customizer` returns `undefined` comparisons are handled by the method
12688 * instead. The `customizer` is bound to `thisArg` and invoked with three
12689 * arguments: (value, other [, index|key]).
12691 * **Note:** This method supports comparing arrays, booleans, `Date` objects,
12692 * numbers, `Object` objects, regexes, and strings. Objects are compared by
12693 * their own, not inherited, enumerable properties. Functions and DOM nodes
12694 * are **not** supported. Provide a customizer function to extend support
12695 * for comparing other values.
12701 * @param {*} value The value to compare.
12702 * @param {*} other The other value to compare.
12703 * @param {Function} [customizer] The function to customize value comparisons.
12704 * @param {*} [thisArg] The `this` binding of `customizer`.
12705 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
12708 * var object = { 'user': 'fred' };
12709 * var other = { 'user': 'fred' };
12714 * _.isEqual(object, other);
12717 * // using a customizer callback
12718 * var array = ['hello', 'goodbye'];
12719 * var other = ['hi', 'goodbye'];
12721 * _.isEqual(array, other, function(value, other) {
12722 * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) {
12728 function isEqual(value, other, customizer, thisArg) {
12729 customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined;
12730 var result = customizer ? customizer(value, other) : undefined;
12731 return result === undefined ? baseIsEqual(value, other, customizer) : !!result;
12735 * Checks if `value` is classified as a `Function` object.
12740 * @param {*} value The value to check.
12741 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
12747 * _.isFunction(/abc/);
12750 var isFunction = !(baseIsFunction(/x/) || (Uint8Array && !baseIsFunction(Uint8Array))) ? baseIsFunction : function(value) {
12751 // The use of `Object#toString` avoids issues with the `typeof` operator
12752 // in older versions of Chrome and Safari which return 'function' for regexes
12753 // and Safari 8 equivalents which return 'object' for typed array constructors.
12754 return objToString.call(value) == funcTag;
12758 * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
12759 * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
12764 * @param {*} value The value to check.
12765 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
12771 * _.isObject([1, 2, 3]);
12777 function isObject(value) {
12778 // Avoid a V8 JIT bug in Chrome 19-20.
12779 // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
12780 var type = typeof value;
12781 return !!value && (type == 'object' || type == 'function');
12785 * Checks if `value` is a native function.
12790 * @param {*} value The value to check.
12791 * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
12794 * _.isNative(Array.prototype.push);
12800 function isNative(value) {
12801 if (value == null) {
12804 if (objToString.call(value) == funcTag) {
12805 return reIsNative.test(fnToString.call(value));
12807 return isObjectLike(value) && (isHostObject(value) ? reIsNative : reIsHostCtor).test(value);
12811 * Checks if `value` is a plain object, that is, an object created by the
12812 * `Object` constructor or one with a `[[Prototype]]` of `null`.
12814 * **Note:** This method assumes objects created by the `Object` constructor
12815 * have no inherited enumerable properties.
12820 * @param {*} value The value to check.
12821 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
12828 * _.isPlainObject(new Foo);
12831 * _.isPlainObject([1, 2, 3]);
12834 * _.isPlainObject({ 'x': 0, 'y': 0 });
12837 * _.isPlainObject(Object.create(null));
12840 var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
12841 if (!(value && objToString.call(value) == objectTag) || (!lodash.support.argsTag && isArguments(value))) {
12844 var valueOf = getNative(value, 'valueOf'),
12845 objProto = valueOf && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
12848 ? (value == objProto || getPrototypeOf(value) == objProto)
12849 : shimIsPlainObject(value);
12853 * Checks if `value` is classified as a `String` primitive or object.
12858 * @param {*} value The value to check.
12859 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
12862 * _.isString('abc');
12868 function isString(value) {
12869 return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag);
12873 * Checks if `value` is classified as a typed array.
12878 * @param {*} value The value to check.
12879 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
12882 * _.isTypedArray(new Uint8Array);
12885 * _.isTypedArray([]);
12888 function isTypedArray(value) {
12889 return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)];
12893 * Converts `value` to a plain object flattening inherited enumerable
12894 * properties of `value` to own properties of the plain object.
12899 * @param {*} value The value to convert.
12900 * @returns {Object} Returns the converted plain object.
12907 * Foo.prototype.c = 3;
12909 * _.assign({ 'a': 1 }, new Foo);
12910 * // => { 'a': 1, 'b': 2 }
12912 * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
12913 * // => { 'a': 1, 'b': 2, 'c': 3 }
12915 function toPlainObject(value) {
12916 return baseCopy(value, keysIn(value));
12919 /*------------------------------------------------------------------------*/
12922 * Assigns own enumerable properties of source object(s) to the destination
12923 * object. Subsequent sources overwrite property assignments of previous sources.
12924 * If `customizer` is provided it is invoked to produce the assigned values.
12925 * The `customizer` is bound to `thisArg` and invoked with five arguments:
12926 * (objectValue, sourceValue, key, object, source).
12928 * **Note:** This method mutates `object` and is based on
12929 * [`Object.assign`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign).
12935 * @param {Object} object The destination object.
12936 * @param {...Object} [sources] The source objects.
12937 * @param {Function} [customizer] The function to customize assigned values.
12938 * @param {*} [thisArg] The `this` binding of `customizer`.
12939 * @returns {Object} Returns `object`.
12942 * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
12943 * // => { 'user': 'fred', 'age': 40 }
12945 * // using a customizer callback
12946 * var defaults = _.partialRight(_.assign, function(value, other) {
12947 * return _.isUndefined(value) ? other : value;
12950 * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
12951 * // => { 'user': 'barney', 'age': 36 }
12953 var assign = createAssigner(function(object, source, customizer) {
12955 ? assignWith(object, source, customizer)
12956 : baseAssign(object, source);
12960 * Iterates over own enumerable properties of an object invoking `iteratee`
12961 * for each property. The `iteratee` is bound to `thisArg` and invoked with
12962 * three arguments: (value, key, object). Iteratee functions may exit iteration
12963 * early by explicitly returning `false`.
12968 * @param {Object} object The object to iterate over.
12969 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12970 * @param {*} [thisArg] The `this` binding of `iteratee`.
12971 * @returns {Object} Returns `object`.
12979 * Foo.prototype.c = 3;
12981 * _.forOwn(new Foo, function(value, key) {
12982 * console.log(key);
12984 * // => logs 'a' and 'b' (iteration order is not guaranteed)
12986 var forOwn = createForOwn(baseForOwn);
12989 * Creates an array of the own enumerable property names of `object`.
12991 * **Note:** Non-object values are coerced to objects. See the
12992 * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys)
12993 * for more details.
12998 * @param {Object} object The object to query.
12999 * @returns {Array} Returns the array of property names.
13007 * Foo.prototype.c = 3;
13010 * // => ['a', 'b'] (iteration order is not guaranteed)
13015 var keys = !nativeKeys ? shimKeys : function(object) {
13016 var Ctor = object == null ? null : object.constructor;
13017 if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
13018 (typeof object == 'function' ? lodash.support.enumPrototypes : isArrayLike(object))) {
13019 return shimKeys(object);
13021 return isObject(object) ? nativeKeys(object) : [];
13025 * Creates an array of the own and inherited enumerable property names of `object`.
13027 * **Note:** Non-object values are coerced to objects.
13032 * @param {Object} object The object to query.
13033 * @returns {Array} Returns the array of property names.
13041 * Foo.prototype.c = 3;
13043 * _.keysIn(new Foo);
13044 * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
13046 function keysIn(object) {
13047 if (object == null) {
13050 if (!isObject(object)) {
13051 object = Object(object);
13053 var length = object.length,
13054 support = lodash.support;
13056 length = (length && isLength(length) &&
13057 (isArray(object) || isArguments(object) || isString(object)) && length) || 0;
13059 var Ctor = object.constructor,
13061 proto = (isFunction(Ctor) && Ctor.prototype) || objectProto,
13062 isProto = proto === object,
13063 result = Array(length),
13064 skipIndexes = length > 0,
13065 skipErrorProps = support.enumErrorProps && (object === errorProto || object instanceof Error),
13066 skipProto = support.enumPrototypes && isFunction(object);
13068 while (++index < length) {
13069 result[index] = (index + '');
13071 // lodash skips the `constructor` property when it infers it is iterating
13072 // over a `prototype` object because IE < 9 can't set the `[[Enumerable]]`
13073 // attribute of an existing property and the `constructor` property of a
13074 // prototype defaults to non-enumerable.
13075 for (var key in object) {
13076 if (!(skipProto && key == 'prototype') &&
13077 !(skipErrorProps && (key == 'message' || key == 'name')) &&
13078 !(skipIndexes && isIndex(key, length)) &&
13079 !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
13083 if (support.nonEnumShadows && object !== objectProto) {
13084 var tag = object === stringProto ? stringTag : (object === errorProto ? errorTag : objToString.call(object)),
13085 nonEnums = nonEnumProps[tag] || nonEnumProps[objectTag];
13087 if (tag == objectTag) {
13088 proto = objectProto;
13090 length = shadowProps.length;
13092 key = shadowProps[length];
13093 var nonEnum = nonEnums[key];
13094 if (!(isProto && nonEnum) &&
13095 (nonEnum ? hasOwnProperty.call(object, key) : object[key] !== proto[key])) {
13104 * Recursively merges own enumerable properties of the source object(s), that
13105 * don't resolve to `undefined` into the destination object. Subsequent sources
13106 * overwrite property assignments of previous sources. If `customizer` is
13107 * provided it is invoked to produce the merged values of the destination and
13108 * source properties. If `customizer` returns `undefined` merging is handled
13109 * by the method instead. The `customizer` is bound to `thisArg` and invoked
13110 * with five arguments: (objectValue, sourceValue, key, object, source).
13115 * @param {Object} object The destination object.
13116 * @param {...Object} [sources] The source objects.
13117 * @param {Function} [customizer] The function to customize assigned values.
13118 * @param {*} [thisArg] The `this` binding of `customizer`.
13119 * @returns {Object} Returns `object`.
13123 * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
13127 * 'data': [{ 'age': 36 }, { 'age': 40 }]
13130 * _.merge(users, ages);
13131 * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
13133 * // using a customizer callback
13135 * 'fruits': ['apple'],
13136 * 'vegetables': ['beet']
13140 * 'fruits': ['banana'],
13141 * 'vegetables': ['carrot']
13144 * _.merge(object, other, function(a, b) {
13145 * if (_.isArray(a)) {
13146 * return a.concat(b);
13149 * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
13151 var merge = createAssigner(baseMerge);
13154 * The opposite of `_.pick`; this method creates an object composed of the
13155 * own and inherited enumerable properties of `object` that are not omitted.
13160 * @param {Object} object The source object.
13161 * @param {Function|...(string|string[])} [predicate] The function invoked per
13162 * iteration or property names to omit, specified as individual property
13163 * names or arrays of property names.
13164 * @param {*} [thisArg] The `this` binding of `predicate`.
13165 * @returns {Object} Returns the new object.
13168 * var object = { 'user': 'fred', 'age': 40 };
13170 * _.omit(object, 'age');
13171 * // => { 'user': 'fred' }
13173 * _.omit(object, _.isNumber);
13174 * // => { 'user': 'fred' }
13176 var omit = restParam(function(object, props) {
13177 if (object == null) {
13180 if (typeof props[0] != 'function') {
13181 var props = arrayMap(baseFlatten(props), String);
13182 return pickByArray(object, baseDifference(keysIn(object), props));
13184 var predicate = bindCallback(props[0], props[1], 3);
13185 return pickByCallback(object, function(value, key, object) {
13186 return !predicate(value, key, object);
13191 * Creates a two dimensional array of the key-value pairs for `object`,
13192 * e.g. `[[key1, value1], [key2, value2]]`.
13197 * @param {Object} object The object to query.
13198 * @returns {Array} Returns the new array of key-value pairs.
13201 * _.pairs({ 'barney': 36, 'fred': 40 });
13202 * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed)
13204 function pairs(object) {
13205 object = toObject(object);
13208 props = keys(object),
13209 length = props.length,
13210 result = Array(length);
13212 while (++index < length) {
13213 var key = props[index];
13214 result[index] = [key, object[key]];
13220 * Creates an object composed of the picked `object` properties. Property
13221 * names may be specified as individual arguments or as arrays of property
13222 * names. If `predicate` is provided it is invoked for each property of `object`
13223 * picking the properties `predicate` returns truthy for. The predicate is
13224 * bound to `thisArg` and invoked with three arguments: (value, key, object).
13229 * @param {Object} object The source object.
13230 * @param {Function|...(string|string[])} [predicate] The function invoked per
13231 * iteration or property names to pick, specified as individual property
13232 * names or arrays of property names.
13233 * @param {*} [thisArg] The `this` binding of `predicate`.
13234 * @returns {Object} Returns the new object.
13237 * var object = { 'user': 'fred', 'age': 40 };
13239 * _.pick(object, 'user');
13240 * // => { 'user': 'fred' }
13242 * _.pick(object, _.isString);
13243 * // => { 'user': 'fred' }
13245 var pick = restParam(function(object, props) {
13246 if (object == null) {
13249 return typeof props[0] == 'function'
13250 ? pickByCallback(object, bindCallback(props[0], props[1], 3))
13251 : pickByArray(object, baseFlatten(props));
13255 * Creates an array of the own enumerable property values of `object`.
13257 * **Note:** Non-object values are coerced to objects.
13262 * @param {Object} object The object to query.
13263 * @returns {Array} Returns the array of property values.
13271 * Foo.prototype.c = 3;
13273 * _.values(new Foo);
13274 * // => [1, 2] (iteration order is not guaranteed)
13279 function values(object) {
13280 return baseValues(object, keys(object));
13283 /*------------------------------------------------------------------------*/
13286 * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?",
13287 * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`.
13292 * @param {string} [string=''] The string to escape.
13293 * @returns {string} Returns the escaped string.
13296 * _.escapeRegExp('[lodash](https://lodash.com/)');
13297 * // => '\[lodash\]\(https:\/\/lodash\.com\/\)'
13299 function escapeRegExp(string) {
13300 string = baseToString(string);
13301 return (string && reHasRegExpChars.test(string))
13302 ? string.replace(reRegExpChars, '\\$&')
13306 /*------------------------------------------------------------------------*/
13309 * Creates a function that invokes `func` with the `this` binding of `thisArg`
13310 * and arguments of the created function. If `func` is a property name the
13311 * created callback returns the property value for a given element. If `func`
13312 * is an object the created callback returns `true` for elements that contain
13313 * the equivalent object properties, otherwise it returns `false`.
13318 * @category Utility
13319 * @param {*} [func=_.identity] The value to convert to a callback.
13320 * @param {*} [thisArg] The `this` binding of `func`.
13321 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
13322 * @returns {Function} Returns the callback.
13326 * { 'user': 'barney', 'age': 36 },
13327 * { 'user': 'fred', 'age': 40 }
13330 * // wrap to create custom callback shorthands
13331 * _.callback = _.wrap(_.callback, function(callback, func, thisArg) {
13332 * var match = /^(.+?)__([gl]t)(.+)$/.exec(func);
13334 * return callback(func, thisArg);
13336 * return function(object) {
13337 * return match[2] == 'gt'
13338 * ? object[match[1]] > match[3]
13339 * : object[match[1]] < match[3];
13343 * _.filter(users, 'age__gt36');
13344 * // => [{ 'user': 'fred', 'age': 40 }]
13346 function callback(func, thisArg, guard) {
13347 if (guard && isIterateeCall(func, thisArg, guard)) {
13350 return isObjectLike(func)
13352 : baseCallback(func, thisArg);
13356 * Creates a function that returns `value`.
13360 * @category Utility
13361 * @param {*} value The value to return from the new function.
13362 * @returns {Function} Returns the new function.
13365 * var object = { 'user': 'fred' };
13366 * var getter = _.constant(object);
13368 * getter() === object;
13371 function constant(value) {
13372 return function() {
13378 * This method returns the first argument provided to it.
13382 * @category Utility
13383 * @param {*} value Any value.
13384 * @returns {*} Returns `value`.
13387 * var object = { 'user': 'fred' };
13389 * _.identity(object) === object;
13392 function identity(value) {
13397 * Creates a function that performs a deep comparison between a given object
13398 * and `source`, returning `true` if the given object has equivalent property
13399 * values, else `false`.
13401 * **Note:** This method supports comparing arrays, booleans, `Date` objects,
13402 * numbers, `Object` objects, regexes, and strings. Objects are compared by
13403 * their own, not inherited, enumerable properties. For comparing a single
13404 * own or inherited property value see `_.matchesProperty`.
13408 * @category Utility
13409 * @param {Object} source The object of property values to match.
13410 * @returns {Function} Returns the new function.
13414 * { 'user': 'barney', 'age': 36, 'active': true },
13415 * { 'user': 'fred', 'age': 40, 'active': false }
13418 * _.filter(users, _.matches({ 'age': 40, 'active': false }));
13419 * // => [{ 'user': 'fred', 'age': 40, 'active': false }]
13421 function matches(source) {
13422 return baseMatches(baseClone(source, true));
13426 * Adds all own enumerable function properties of a source object to the
13427 * destination object. If `object` is a function then methods are added to
13428 * its prototype as well.
13430 * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
13431 * avoid conflicts caused by modifying the original.
13435 * @category Utility
13436 * @param {Function|Object} [object=lodash] The destination object.
13437 * @param {Object} source The object of functions to add.
13438 * @param {Object} [options] The options object.
13439 * @param {boolean} [options.chain=true] Specify whether the functions added
13441 * @returns {Function|Object} Returns `object`.
13444 * function vowels(string) {
13445 * return _.filter(string, function(v) {
13446 * return /[aeiou]/i.test(v);
13450 * _.mixin({ 'vowels': vowels });
13451 * _.vowels('fred');
13454 * _('fred').vowels().value();
13457 * _.mixin({ 'vowels': vowels }, { 'chain': false });
13458 * _('fred').vowels();
13461 function mixin(object, source, options) {
13462 if (options == null) {
13463 var isObj = isObject(source),
13464 props = isObj ? keys(source) : null,
13465 methodNames = (props && props.length) ? baseFunctions(source, props) : null;
13467 if (!(methodNames ? methodNames.length : isObj)) {
13468 methodNames = false;
13474 if (!methodNames) {
13475 methodNames = baseFunctions(source, keys(source));
13479 isFunc = isFunction(object),
13480 length = methodNames.length;
13482 if (options === false) {
13484 } else if (isObject(options) && 'chain' in options) {
13485 chain = options.chain;
13487 while (++index < length) {
13488 var methodName = methodNames[index],
13489 func = source[methodName];
13491 object[methodName] = func;
13493 object.prototype[methodName] = (function(func) {
13494 return function() {
13495 var chainAll = this.__chain__;
13496 if (chain || chainAll) {
13497 var result = object(this.__wrapped__),
13498 actions = result.__actions__ = arrayCopy(this.__actions__);
13500 actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
13501 result.__chain__ = chainAll;
13504 var args = [this.value()];
13505 push.apply(args, arguments);
13506 return func.apply(object, args);
13515 * A no-operation function that returns `undefined` regardless of the
13516 * arguments it receives.
13520 * @category Utility
13523 * var object = { 'user': 'fred' };
13525 * _.noop(object) === undefined;
13529 // No operation performed.
13533 * Creates a function that returns the property value at `path` on a
13538 * @category Utility
13539 * @param {Array|string} path The path of the property to get.
13540 * @returns {Function} Returns the new function.
13544 * { 'a': { 'b': { 'c': 2 } } },
13545 * { 'a': { 'b': { 'c': 1 } } }
13548 * _.map(objects, _.property('a.b.c'));
13551 * _.pluck(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c');
13554 function property(path) {
13555 return isKey(path) ? baseProperty(path) : basePropertyDeep(path);
13558 /*------------------------------------------------------------------------*/
13560 // Ensure wrappers are instances of `baseLodash`.
13561 lodash.prototype = baseLodash.prototype;
13563 LodashWrapper.prototype = baseCreate(baseLodash.prototype);
13564 LodashWrapper.prototype.constructor = LodashWrapper;
13566 LazyWrapper.prototype = baseCreate(baseLodash.prototype);
13567 LazyWrapper.prototype.constructor = LazyWrapper;
13569 // Add functions to the `Set` cache.
13570 SetCache.prototype.push = cachePush;
13572 // Add functions that return wrapped values when chaining.
13573 lodash.assign = assign;
13574 lodash.bind = bind;
13575 lodash.callback = callback;
13576 lodash.chain = chain;
13577 lodash.chunk = chunk;
13578 lodash.compact = compact;
13579 lodash.constant = constant;
13580 lodash.debounce = debounce;
13581 lodash.difference = difference;
13582 lodash.filter = filter;
13583 lodash.flatten = flatten;
13584 lodash.forEach = forEach;
13585 lodash.forOwn = forOwn;
13586 lodash.groupBy = groupBy;
13587 lodash.intersection = intersection;
13588 lodash.keys = keys;
13589 lodash.keysIn = keysIn;
13591 lodash.matches = matches;
13592 lodash.merge = merge;
13593 lodash.mixin = mixin;
13594 lodash.omit = omit;
13595 lodash.pairs = pairs;
13596 lodash.pick = pick;
13597 lodash.pluck = pluck;
13598 lodash.property = property;
13599 lodash.reject = reject;
13600 lodash.restParam = restParam;
13602 lodash.throttle = throttle;
13603 lodash.thru = thru;
13604 lodash.toPlainObject = toPlainObject;
13605 lodash.union = union;
13606 lodash.uniq = uniq;
13607 lodash.values = values;
13608 lodash.without = without;
13611 lodash.collect = map;
13612 lodash.each = forEach;
13613 lodash.extend = assign;
13614 lodash.iteratee = callback;
13615 lodash.select = filter;
13616 lodash.unique = uniq;
13618 // Add functions to `lodash.prototype`.
13619 mixin(lodash, lodash);
13621 /*------------------------------------------------------------------------*/
13623 // Add functions that return unwrapped values when chaining.
13624 lodash.clone = clone;
13625 lodash.cloneDeep = cloneDeep;
13626 lodash.escapeRegExp = escapeRegExp;
13627 lodash.every = every;
13628 lodash.find = find;
13629 lodash.first = first;
13630 lodash.identity = identity;
13631 lodash.includes = includes;
13632 lodash.indexOf = indexOf;
13633 lodash.isArguments = isArguments;
13634 lodash.isArray = isArray;
13635 lodash.isEmpty = isEmpty;
13636 lodash.isEqual = isEqual;
13637 lodash.isFunction = isFunction;
13638 lodash.isNative = isNative;
13639 lodash.isObject = isObject;
13640 lodash.isPlainObject = isPlainObject;
13641 lodash.isString = isString;
13642 lodash.isTypedArray = isTypedArray;
13643 lodash.last = last;
13644 lodash.noop = noop;
13646 lodash.reduce = reduce;
13647 lodash.some = some;
13650 lodash.all = every;
13652 lodash.contains = includes;
13653 lodash.eq = isEqual;
13654 lodash.detect = find;
13655 lodash.foldl = reduce;
13656 lodash.head = first;
13657 lodash.include = includes;
13658 lodash.inject = reduce;
13660 mixin(lodash, (function() {
13662 baseForOwn(lodash, function(func, methodName) {
13663 if (!lodash.prototype[methodName]) {
13664 source[methodName] = func;
13670 /*------------------------------------------------------------------------*/
13672 lodash.prototype.sample = function(n) {
13673 if (!this.__chain__ && n == null) {
13674 return sample(this.value());
13676 return this.thru(function(value) {
13677 return sample(value, n);
13681 /*------------------------------------------------------------------------*/
13684 * The semantic version number.
13690 lodash.VERSION = VERSION;
13692 // Assign default placeholders.
13693 bind.placeholder = lodash;
13695 // Add `LazyWrapper` methods that accept an `iteratee` value.
13696 arrayEach(['dropWhile', 'filter', 'map', 'takeWhile'], function(methodName, type) {
13697 var isFilter = type != LAZY_MAP_FLAG,
13698 isDropWhile = type == LAZY_DROP_WHILE_FLAG;
13700 LazyWrapper.prototype[methodName] = function(iteratee, thisArg) {
13701 var filtered = this.__filtered__,
13702 result = (filtered && isDropWhile) ? new LazyWrapper(this) : this.clone(),
13703 iteratees = result.__iteratees__ || (result.__iteratees__ = []);
13709 'iteratee': getCallback(iteratee, thisArg, 1),
13714 result.__filtered__ = filtered || isFilter;
13719 // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
13720 arrayEach(['drop', 'take'], function(methodName, index) {
13721 var whileName = methodName + 'While';
13723 LazyWrapper.prototype[methodName] = function(n) {
13724 var filtered = this.__filtered__,
13725 result = (filtered && !index) ? this.dropWhile() : this.clone();
13727 n = n == null ? 1 : nativeMax(floor(n) || 0, 0);
13730 result.__takeCount__ = nativeMin(result.__takeCount__, n);
13732 last(result.__iteratees__).limit = n;
13735 var views = result.__views__ || (result.__views__ = []);
13736 views.push({ 'size': n, 'type': methodName + (result.__dir__ < 0 ? 'Right' : '') });
13741 LazyWrapper.prototype[methodName + 'Right'] = function(n) {
13742 return this.reverse()[methodName](n).reverse();
13745 LazyWrapper.prototype[methodName + 'RightWhile'] = function(predicate, thisArg) {
13746 return this.reverse()[whileName](predicate, thisArg).reverse();
13750 // Add `LazyWrapper` methods for `_.first` and `_.last`.
13751 arrayEach(['first', 'last'], function(methodName, index) {
13752 var takeName = 'take' + (index ? 'Right' : '');
13754 LazyWrapper.prototype[methodName] = function() {
13755 return this[takeName](1).value()[0];
13759 // Add `LazyWrapper` methods for `_.initial` and `_.rest`.
13760 arrayEach(['initial', 'rest'], function(methodName, index) {
13761 var dropName = 'drop' + (index ? '' : 'Right');
13763 LazyWrapper.prototype[methodName] = function() {
13764 return this[dropName](1);
13768 // Add `LazyWrapper` methods for `_.pluck` and `_.where`.
13769 arrayEach(['pluck', 'where'], function(methodName, index) {
13770 var operationName = index ? 'filter' : 'map',
13771 createCallback = index ? baseMatches : property;
13773 LazyWrapper.prototype[methodName] = function(value) {
13774 return this[operationName](createCallback(value));
13778 LazyWrapper.prototype.compact = function() {
13779 return this.filter(identity);
13782 LazyWrapper.prototype.reject = function(predicate, thisArg) {
13783 predicate = getCallback(predicate, thisArg, 1);
13784 return this.filter(function(value) {
13785 return !predicate(value);
13789 LazyWrapper.prototype.slice = function(start, end) {
13790 start = start == null ? 0 : (+start || 0);
13794 result = this.takeRight(-start);
13795 } else if (start) {
13796 result = this.drop(start);
13798 if (end !== undefined) {
13800 result = end < 0 ? result.dropRight(-end) : result.take(end - start);
13805 LazyWrapper.prototype.toArray = function() {
13806 return this.drop(0);
13809 // Add `LazyWrapper` methods to `lodash.prototype`.
13810 baseForOwn(LazyWrapper.prototype, function(func, methodName) {
13811 var lodashFunc = lodash[methodName];
13815 var checkIteratee = /^(?:filter|map|reject)|While$/.test(methodName),
13816 retUnwrapped = /^(?:first|last)$/.test(methodName);
13818 lodash.prototype[methodName] = function() {
13819 var args = arguments,
13820 chainAll = this.__chain__,
13821 value = this.__wrapped__,
13822 isHybrid = !!this.__actions__.length,
13823 isLazy = value instanceof LazyWrapper,
13824 iteratee = args[0],
13825 useLazy = isLazy || isArray(value);
13827 if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
13828 // avoid lazy use if the iteratee has a "length" value other than `1`
13829 isLazy = useLazy = false;
13831 var onlyLazy = isLazy && !isHybrid;
13832 if (retUnwrapped && !chainAll) {
13835 : lodashFunc.call(lodash, this.value());
13837 var interceptor = function(value) {
13838 var otherArgs = [value];
13839 push.apply(otherArgs, args);
13840 return lodashFunc.apply(lodash, otherArgs);
13843 var wrapper = onlyLazy ? value : new LazyWrapper(this),
13844 result = func.apply(wrapper, args);
13846 if (!retUnwrapped && (isHybrid || result.__actions__)) {
13847 var actions = result.__actions__ || (result.__actions__ = []);
13848 actions.push({ 'func': thru, 'args': [interceptor], 'thisArg': lodash });
13850 return new LodashWrapper(result, chainAll);
13852 return this.thru(interceptor);
13856 // Add `Array` and `String` methods to `lodash.prototype`.
13857 arrayEach(['concat', 'join', 'pop', 'push', 'replace', 'shift', 'sort', 'splice', 'split', 'unshift'], function(methodName) {
13858 var protoFunc = (/^(?:replace|split)$/.test(methodName) ? stringProto : arrayProto)[methodName],
13859 chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
13860 fixObjects = !support.spliceObjects && /^(?:pop|shift|splice)$/.test(methodName),
13861 retUnwrapped = /^(?:join|pop|replace|shift)$/.test(methodName);
13863 // Avoid array-like object bugs with `Array#shift` and `Array#splice` in
13864 // IE < 9, Firefox < 10, and RingoJS.
13865 var func = !fixObjects ? protoFunc : function() {
13866 var result = protoFunc.apply(this, arguments);
13867 if (this.length === 0) {
13873 lodash.prototype[methodName] = function() {
13874 var args = arguments;
13875 if (retUnwrapped && !this.__chain__) {
13876 return func.apply(this.value(), args);
13878 return this[chainName](function(value) {
13879 return func.apply(value, args);
13884 // Map minified function names to their real names.
13885 baseForOwn(LazyWrapper.prototype, function(func, methodName) {
13886 var lodashFunc = lodash[methodName];
13888 var key = lodashFunc.name,
13889 names = realNames[key] || (realNames[key] = []);
13891 names.push({ 'name': methodName, 'func': lodashFunc });
13895 realNames[createHybridWrapper(null, BIND_KEY_FLAG).name] = [{ 'name': 'wrapper', 'func': null }];
13897 // Add functions to the lazy wrapper.
13898 LazyWrapper.prototype.clone = lazyClone;
13899 LazyWrapper.prototype.reverse = lazyReverse;
13900 LazyWrapper.prototype.value = lazyValue;
13902 // Add chaining functions to the `lodash` wrapper.
13903 lodash.prototype.chain = wrapperChain;
13904 lodash.prototype.commit = wrapperCommit;
13905 lodash.prototype.plant = wrapperPlant;
13906 lodash.prototype.reverse = wrapperReverse;
13907 lodash.prototype.toString = wrapperToString;
13908 lodash.prototype.run = lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
13910 // Add function aliases to the `lodash` wrapper.
13911 lodash.prototype.collect = lodash.prototype.map;
13912 lodash.prototype.head = lodash.prototype.first;
13913 lodash.prototype.select = lodash.prototype.filter;
13914 lodash.prototype.tail = lodash.prototype.rest;
13916 /*--------------------------------------------------------------------------*/
13918 if (freeExports && freeModule) {
13919 // Export for Node.js or RingoJS.
13920 if (moduleExports) {
13921 (freeModule.exports = lodash)._ = lodash;
13925 // Export for a browser or Rhino.
13929 (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;
13930 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){
13933 var ohauth = require('ohauth'),
13934 xtend = require('xtend'),
13935 store = require('store');
13939 // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
13940 // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
13941 // does not support custom headers, which this uses everywhere.
13942 module.exports = function(o) {
13946 // authenticated users will also have a request token secret, but it's
13947 // not used in transactions with the server
13948 oauth.authenticated = function() {
13949 return !!(token('oauth_token') && token('oauth_token_secret'));
13952 oauth.logout = function() {
13953 token('oauth_token', '');
13954 token('oauth_token_secret', '');
13955 token('oauth_request_token_secret', '');
13959 // TODO: detect lack of click event
13960 oauth.authenticate = function(callback) {
13961 if (oauth.authenticated()) return callback();
13965 // ## Getting a request token
13966 var params = timenonce(getAuth(o)),
13967 url = o.url + '/oauth/request_token',
13970 params.oauth_signature = ohauth.signature(
13971 o.oauth_secret, '',
13972 ohauth.baseString('POST', url, params));
13974 if (!o.singlepage) {
13975 // Create a 600x550 popup window in the center of the screen
13976 var w = 600, h = 550,
13978 ['width', w], ['height', h],
13979 ['left', screen.width / 2 - w / 2],
13980 ['top', screen.height / 2 - h / 2]].map(function(x) {
13981 return x.join('=');
13983 popup = window.open('about:blank', 'oauth_window', settings);
13986 timer = setInterval(function() {
13987 if (popup.closed) {
13989 clearInterval(timer);
13990 callback('not authenticated', null);
13995 // Request a request token. When this is complete, the popup
13996 // window is redirected to OSM's authorization page.
13997 ohauth.xhr('POST', url, params, null, {}, reqTokenDone);
14000 function reqTokenDone(err, xhr) {
14003 if (timer) clearInterval(timer);
14004 return callback(err);
14006 var resp = ohauth.stringQs(xhr.response);
14007 token('oauth_request_token_secret', resp.oauth_token_secret);
14008 var authorize_url = o.url + '/oauth/authorize?' + ohauth.qsString({
14009 oauth_token: resp.oauth_token,
14010 oauth_callback: location.href.replace('index.html', '')
14011 .replace(/#.*/, '') + o.landing
14014 if (o.singlepage) {
14015 location.href = authorize_url;
14017 popup.location = authorize_url;
14021 // Called by a function in a landing page, in the popup window. The
14022 // window closes itself.
14023 window.authComplete = function(token) {
14024 if (timer) clearInterval(timer);
14025 var oauth_token = ohauth.stringQs(token.split('?')[1]);
14026 get_access_token(oauth_token.oauth_token);
14027 delete window.authComplete;
14030 // ## Getting an request token
14032 // At this point we have an `oauth_token`, brought in from a function
14033 // call on a landing page popup.
14034 function get_access_token(oauth_token) {
14035 var url = o.url + '/oauth/access_token',
14036 params = timenonce(getAuth(o)),
14037 request_token_secret = token('oauth_request_token_secret');
14038 params.oauth_token = oauth_token;
14039 params.oauth_signature = ohauth.signature(
14041 request_token_secret,
14042 ohauth.baseString('POST', url, params));
14044 // ## Getting an access token
14046 // The final token required for authentication. At this point
14047 // we have a `request token secret`
14048 ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
14052 function accessTokenDone(err, xhr) {
14054 if (timer) clearInterval(timer);
14055 if (err) return callback(err);
14056 var access_token = ohauth.stringQs(xhr.response);
14057 token('oauth_token', access_token.oauth_token);
14058 token('oauth_token_secret', access_token.oauth_token_secret);
14059 callback(null, oauth);
14063 oauth.bootstrapToken = function(oauth_token, callback) {
14064 // ## Getting an request token
14065 // At this point we have an `oauth_token`, brought in from a function
14066 // call on a landing page popup.
14067 function get_access_token(oauth_token) {
14068 var url = o.url + '/oauth/access_token',
14069 params = timenonce(getAuth(o)),
14070 request_token_secret = token('oauth_request_token_secret');
14071 params.oauth_token = oauth_token;
14072 params.oauth_signature = ohauth.signature(
14074 request_token_secret,
14075 ohauth.baseString('POST', url, params));
14077 // ## Getting an access token
14078 // The final token required for authentication. At this point
14079 // we have a `request token secret`
14080 ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
14084 function accessTokenDone(err, xhr) {
14086 if (err) return callback(err);
14087 var access_token = ohauth.stringQs(xhr.response);
14088 token('oauth_token', access_token.oauth_token);
14089 token('oauth_token_secret', access_token.oauth_token_secret);
14090 callback(null, oauth);
14093 get_access_token(oauth_token);
14098 // A single XMLHttpRequest wrapper that does authenticated calls if the
14099 // user has logged in.
14100 oauth.xhr = function(options, callback) {
14101 if (!oauth.authenticated()) {
14102 if (o.auto) return oauth.authenticate(run);
14103 else return callback('not authenticated', null);
14104 } else return run();
14107 var params = timenonce(getAuth(o)),
14108 url = o.url + options.path,
14109 oauth_token_secret = token('oauth_token_secret');
14111 // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
14112 if ((!options.options || !options.options.header ||
14113 options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') &&
14115 params = xtend(params, ohauth.stringQs(options.content));
14118 params.oauth_token = token('oauth_token');
14119 params.oauth_signature = ohauth.signature(
14121 oauth_token_secret,
14122 ohauth.baseString(options.method, url, params));
14124 ohauth.xhr(options.method,
14125 url, params, options.content, options.options, done);
14128 function done(err, xhr) {
14129 if (err) return callback(err);
14130 else if (xhr.responseXML) return callback(err, xhr.responseXML);
14131 else return callback(err, xhr.response);
14135 // pre-authorize this object, if we can just get a token and token_secret
14137 oauth.preauth = function(c) {
14139 if (c.oauth_token) token('oauth_token', c.oauth_token);
14140 if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
14144 oauth.options = function(_) {
14145 if (!arguments.length) return o;
14149 o.url = o.url || 'http://www.openstreetmap.org';
14150 o.landing = o.landing || 'land.html';
14152 o.singlepage = o.singlepage || false;
14154 // Optional loading and loading-done functions for nice UI feedback.
14155 // by default, no-ops
14156 o.loading = o.loading || function() {};
14157 o.done = o.done || function() {};
14159 return oauth.preauth(o);
14162 // 'stamp' an authentication object from `getAuth()`
14163 // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
14165 function timenonce(o) {
14166 o.oauth_timestamp = ohauth.timestamp();
14167 o.oauth_nonce = ohauth.nonce();
14171 // get/set tokens. These are prefixed with the base URL so that `osm-auth`
14172 // can be used with multiple APIs and the keys in `localStorage`
14176 if (store.enabled) {
14177 token = function (x, y) {
14178 if (arguments.length === 1) return store.get(o.url + x);
14179 else if (arguments.length === 2) return store.set(o.url + x, y);
14183 token = function (x, y) {
14184 if (arguments.length === 1) return storage[o.url + x];
14185 else if (arguments.length === 2) return storage[o.url + x] = y;
14189 // Get an authentication object. If you just add and remove properties
14190 // from a single object, you'll need to use `delete` to make sure that
14191 // it doesn't contain undesired properties for authentication
14192 function getAuth(o) {
14194 oauth_consumer_key: o.oauth_consumer_key,
14195 oauth_signature_method: "HMAC-SHA1"
14199 // potentially pre-authorize
14205 },{"ohauth":2,"store":3,"xtend":4}],3:[function(require,module,exports){
14206 (function(global){;(function(win){
14208 doc = win.document,
14209 localStorageName = 'localStorage',
14212 store.disabled = false
14213 store.set = function(key, value) {}
14214 store.get = function(key) {}
14215 store.remove = function(key) {}
14216 store.clear = function() {}
14217 store.transact = function(key, defaultVal, transactionFn) {
14218 var val = store.get(key)
14219 if (transactionFn == null) {
14220 transactionFn = defaultVal
14223 if (typeof val == 'undefined') { val = defaultVal || {} }
14225 store.set(key, val)
14227 store.getAll = function() {}
14228 store.forEach = function() {}
14230 store.serialize = function(value) {
14231 return JSON.stringify(value)
14233 store.deserialize = function(value) {
14234 if (typeof value != 'string') { return undefined }
14235 try { return JSON.parse(value) }
14236 catch(e) { return value || undefined }
14239 // Functions to encapsulate questionable FireFox 3.6.13 behavior
14240 // when about.config::dom.storage.enabled === false
14241 // See https://github.com/marcuswestin/store.js/issues#issue/13
14242 function isLocalStorageNameSupported() {
14243 try { return (localStorageName in win && win[localStorageName]) }
14244 catch(err) { return false }
14247 if (isLocalStorageNameSupported()) {
14248 storage = win[localStorageName]
14249 store.set = function(key, val) {
14250 if (val === undefined) { return store.remove(key) }
14251 storage.setItem(key, store.serialize(val))
14254 store.get = function(key) { return store.deserialize(storage.getItem(key)) }
14255 store.remove = function(key) { storage.removeItem(key) }
14256 store.clear = function() { storage.clear() }
14257 store.getAll = function() {
14259 store.forEach(function(key, val) {
14264 store.forEach = function(callback) {
14265 for (var i=0; i<storage.length; i++) {
14266 var key = storage.key(i)
14267 callback(key, store.get(key))
14270 } else if (doc.documentElement.addBehavior) {
14273 // Since #userData storage applies only to specific paths, we need to
14274 // somehow link our data to a specific path. We choose /favicon.ico
14275 // as a pretty safe option, since all browsers already make a request to
14276 // this URL anyway and being a 404 will not hurt us here. We wrap an
14277 // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
14278 // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
14279 // since the iframe access rules appear to allow direct access and
14280 // manipulation of the document element, even for a 404 page. This
14281 // document can be used instead of the current document (which would
14282 // have been limited to the current path) to perform #userData storage.
14284 storageContainer = new ActiveXObject('htmlfile')
14285 storageContainer.open()
14286 storageContainer.write('<s' + 'cript>document.w=window</s' + 'cript><iframe src="/favicon.ico"></iframe>')
14287 storageContainer.close()
14288 storageOwner = storageContainer.w.frames[0].document
14289 storage = storageOwner.createElement('div')
14291 // somehow ActiveXObject instantiation failed (perhaps some special
14292 // security settings or otherwse), fall back to per-path storage
14293 storage = doc.createElement('div')
14294 storageOwner = doc.body
14296 function withIEStorage(storeFunction) {
14297 return function() {
14298 var args = Array.prototype.slice.call(arguments, 0)
14299 args.unshift(storage)
14300 // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
14301 // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
14302 storageOwner.appendChild(storage)
14303 storage.addBehavior('#default#userData')
14304 storage.load(localStorageName)
14305 var result = storeFunction.apply(store, args)
14306 storageOwner.removeChild(storage)
14311 // In IE7, keys may not contain special chars. See all of https://github.com/marcuswestin/store.js/issues/40
14312 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g")
14313 function ieKeyFix(key) {
14314 return key.replace(forbiddenCharsRegex, '___')
14316 store.set = withIEStorage(function(storage, key, val) {
14317 key = ieKeyFix(key)
14318 if (val === undefined) { return store.remove(key) }
14319 storage.setAttribute(key, store.serialize(val))
14320 storage.save(localStorageName)
14323 store.get = withIEStorage(function(storage, key) {
14324 key = ieKeyFix(key)
14325 return store.deserialize(storage.getAttribute(key))
14327 store.remove = withIEStorage(function(storage, key) {
14328 key = ieKeyFix(key)
14329 storage.removeAttribute(key)
14330 storage.save(localStorageName)
14332 store.clear = withIEStorage(function(storage) {
14333 var attributes = storage.XMLDocument.documentElement.attributes
14334 storage.load(localStorageName)
14335 for (var i=0, attr; attr=attributes[i]; i++) {
14336 storage.removeAttribute(attr.name)
14338 storage.save(localStorageName)
14340 store.getAll = function(storage) {
14342 store.forEach(function(key, val) {
14347 store.forEach = withIEStorage(function(storage, callback) {
14348 var attributes = storage.XMLDocument.documentElement.attributes
14349 for (var i=0, attr; attr=attributes[i]; ++i) {
14350 callback(attr.name, store.deserialize(storage.getAttribute(attr.name)))
14356 var testKey = '__storejs__'
14357 store.set(testKey, testKey)
14358 if (store.get(testKey) != testKey) { store.disabled = true }
14359 store.remove(testKey)
14361 store.disabled = true
14363 store.enabled = !store.disabled
14365 if (typeof module != 'undefined' && module.exports) { module.exports = store }
14366 else if (typeof define === 'function' && define.amd) { define(store) }
14367 else { win.store = store }
14369 })(this.window || global);
14372 },{}],5:[function(require,module,exports){
14373 module.exports = hasKeys
14375 function hasKeys(source) {
14376 return source !== null &&
14377 (typeof source === "object" ||
14378 typeof source === "function")
14381 },{}],4:[function(require,module,exports){
14382 var Keys = require("object-keys")
14383 var hasKeys = require("./has-keys")
14385 module.exports = extend
14387 function extend() {
14390 for (var i = 0; i < arguments.length; i++) {
14391 var source = arguments[i]
14393 if (!hasKeys(source)) {
14397 var keys = Keys(source)
14399 for (var j = 0; j < keys.length; j++) {
14401 target[name] = source[name]
14408 },{"./has-keys":5,"object-keys":6}],7:[function(require,module,exports){
14409 (function(global){/**
14410 * jsHashes - A fast and independent hashing library pure JavaScript implemented (ES3 compliant) for both server and client side
14413 * @author Tomas Aparicio <tomas@rijndael-project.com>
14414 * @license New BSD (see LICENSE file)
14417 * Algorithms specification:
14419 * MD5 <http://www.ietf.org/rfc/rfc1321.txt>
14420 * RIPEMD-160 <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
14421 * SHA1 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
14422 * SHA256 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
14423 * SHA512 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
14424 * HMAC <http://www.ietf.org/rfc/rfc2104.txt>
14430 // private helper methods
14431 function utf8Encode(str) {
14432 var x, y, output = '', i = -1, l;
14434 if (str && str.length) {
14436 while ((i+=1) < l) {
14437 /* Decode utf-16 surrogate pairs */
14438 x = str.charCodeAt(i);
14439 y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
14440 if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
14441 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
14444 /* Encode output as utf-8 */
14446 output += String.fromCharCode(x);
14447 } else if (x <= 0x7FF) {
14448 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
14449 0x80 | ( x & 0x3F));
14450 } else if (x <= 0xFFFF) {
14451 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
14452 0x80 | ((x >>> 6 ) & 0x3F),
14453 0x80 | ( x & 0x3F));
14454 } else if (x <= 0x1FFFFF) {
14455 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
14456 0x80 | ((x >>> 12) & 0x3F),
14457 0x80 | ((x >>> 6 ) & 0x3F),
14458 0x80 | ( x & 0x3F));
14465 function utf8Decode(str) {
14466 var i, ac, c1, c2, c3, arr = [], l;
14467 i = ac = c1 = c2 = c3 = 0;
14469 if (str && str.length) {
14474 c1 = str.charCodeAt(i);
14477 arr[ac] = String.fromCharCode(c1);
14479 } else if (c1 > 191 && c1 < 224) {
14480 c2 = str.charCodeAt(i + 1);
14481 arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
14484 c2 = str.charCodeAt(i + 1);
14485 c3 = str.charCodeAt(i + 2);
14486 arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
14491 return arr.join('');
14495 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
14496 * to work around bugs in some JS interpreters.
14498 function safe_add(x, y) {
14499 var lsw = (x & 0xFFFF) + (y & 0xFFFF),
14500 msw = (x >> 16) + (y >> 16) + (lsw >> 16);
14501 return (msw << 16) | (lsw & 0xFFFF);
14505 * Bitwise rotate a 32-bit number to the left.
14507 function bit_rol(num, cnt) {
14508 return (num << cnt) | (num >>> (32 - cnt));
14512 * Convert a raw string to a hex string
14514 function rstr2hex(input, hexcase) {
14515 var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
14516 output = '', x, i = 0, l = input.length;
14517 for (; i < l; i+=1) {
14518 x = input.charCodeAt(i);
14519 output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F);
14525 * Encode a string as utf-16
14527 function str2rstr_utf16le(input) {
14528 var i, l = input.length, output = '';
14529 for (i = 0; i < l; i+=1) {
14530 output += String.fromCharCode( input.charCodeAt(i) & 0xFF, (input.charCodeAt(i) >>> 8) & 0xFF);
14535 function str2rstr_utf16be(input) {
14536 var i, l = input.length, output = '';
14537 for (i = 0; i < l; i+=1) {
14538 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, input.charCodeAt(i) & 0xFF);
14544 * Convert an array of big-endian words to a string
14546 function binb2rstr(input) {
14547 var i, l = input.length * 32, output = '';
14548 for (i = 0; i < l; i += 8) {
14549 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
14555 * Convert an array of little-endian words to a string
14557 function binl2rstr(input) {
14558 var i, l = input.length * 32, output = '';
14559 for (i = 0;i < l; i += 8) {
14560 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
14566 * Convert a raw string to an array of little-endian words
14567 * Characters >255 have their high-byte silently ignored.
14569 function rstr2binl(input) {
14570 var i, l = input.length * 8, output = Array(input.length >> 2), lo = output.length;
14571 for (i = 0; i < lo; i+=1) {
14574 for (i = 0; i < l; i += 8) {
14575 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
14581 * Convert a raw string to an array of big-endian words
14582 * Characters >255 have their high-byte silently ignored.
14584 function rstr2binb(input) {
14585 var i, l = input.length * 8, output = Array(input.length >> 2), lo = output.length;
14586 for (i = 0; i < lo; i+=1) {
14589 for (i = 0; i < l; i += 8) {
14590 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
14596 * Convert a raw string to an arbitrary string encoding
14598 function rstr2any(input, encoding) {
14599 var divisor = encoding.length,
14600 remainders = Array(),
14601 i, q, x, ld, quotient, dividend, output, full_length;
14603 /* Convert to an array of 16-bit big-endian values, forming the dividend */
14604 dividend = Array(Math.ceil(input.length / 2));
14605 ld = dividend.length;
14606 for (i = 0; i < ld; i+=1) {
14607 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
14611 * Repeatedly perform a long division. The binary array forms the dividend,
14612 * the length of the encoding is the divisor. Once computed, the quotient
14613 * forms the dividend for the next step. We stop when the dividend is zerHashes.
14614 * All remainders are stored for later use.
14616 while(dividend.length > 0) {
14617 quotient = Array();
14619 for (i = 0; i < dividend.length; i+=1) {
14620 x = (x << 16) + dividend[i];
14621 q = Math.floor(x / divisor);
14623 if (quotient.length > 0 || q > 0) {
14624 quotient[quotient.length] = q;
14627 remainders[remainders.length] = x;
14628 dividend = quotient;
14631 /* Convert the remainders to the output string */
14633 for (i = remainders.length - 1; i >= 0; i--) {
14634 output += encoding.charAt(remainders[i]);
14637 /* Append leading zero equivalents */
14638 full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
14639 for (i = output.length; i < full_length; i+=1) {
14640 output = encoding[0] + output;
14646 * Convert a raw string to a base-64 string
14648 function rstr2b64(input, b64pad) {
14649 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
14651 len = input.length, i, j, triplet;
14652 b64pad= b64pad || '=';
14653 for (i = 0; i < len; i += 3) {
14654 triplet = (input.charCodeAt(i) << 16)
14655 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
14656 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
14657 for (j = 0; j < 4; j+=1) {
14658 if (i * 8 + j * 6 > input.length * 8) {
14661 output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
14670 * @property {String} version
14679 Base64 : function () {
14680 // private properties
14681 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
14682 pad = '=', // default pad according with the RFC standard
14683 url = false, // URL encoding support @todo
14684 utf8 = true; // by default enable UTF-8 support encoding
14686 // public method for encoding
14687 this.encode = function (input) {
14690 len = input.length;
14693 input = (utf8) ? utf8Encode(input) : input;
14695 for (i = 0; i < len; i += 3) {
14696 triplet = (input.charCodeAt(i) << 16)
14697 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
14698 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
14699 for (j = 0; j < 4; j+=1) {
14700 if (i * 8 + j * 6 > len * 8) {
14703 output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
14710 // public method for decoding
14711 this.decode = function (input) {
14712 // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
14713 var i, o1, o2, o3, h1, h2, h3, h4, bits, ac,
14716 if (!input) { return input; }
14719 input = input.replace(new RegExp('\\'+pad,'gi'),''); // use '='
14722 do { // unpack four hexets into three octets using index points in b64
14723 h1 = tab.indexOf(input.charAt(i+=1));
14724 h2 = tab.indexOf(input.charAt(i+=1));
14725 h3 = tab.indexOf(input.charAt(i+=1));
14726 h4 = tab.indexOf(input.charAt(i+=1));
14728 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
14730 o1 = bits >> 16 & 0xff;
14731 o2 = bits >> 8 & 0xff;
14736 arr[ac] = String.fromCharCode(o1);
14737 } else if (h4 === 64) {
14738 arr[ac] = String.fromCharCode(o1, o2);
14740 arr[ac] = String.fromCharCode(o1, o2, o3);
14742 } while (i < input.length);
14744 dec = arr.join('');
14745 dec = (utf8) ? utf8Decode(dec) : dec;
14750 // set custom pad string
14751 this.setPad = function (str) {
14755 // set custom tab string characters
14756 this.setTab = function (str) {
14760 this.setUTF8 = function (bool) {
14761 if (typeof bool === 'boolean') {
14769 * CRC-32 calculation
14773 * @param {String} str Input String
14776 CRC32 : function (str) {
14777 var crc = 0, x = 0, y = 0, table, i, iTop;
14778 str = utf8Encode(str);
14781 '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ',
14782 '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ',
14783 '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ',
14784 '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ',
14785 'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ',
14786 '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ',
14787 'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ',
14788 '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ',
14789 'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ',
14790 '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ',
14791 'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ',
14792 '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ',
14793 'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ',
14794 '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ',
14795 '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ',
14796 '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ',
14797 '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ',
14798 'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ',
14799 '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ',
14800 'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ',
14801 '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ',
14802 'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ',
14803 '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ',
14804 'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ',
14805 '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ',
14806 'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'
14810 for (i = 0, iTop = str.length; i < iTop; i+=1 ) {
14811 y = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
14812 x = '0x' + table.substr( y * 9, 8 );
14813 crc = ( crc >>> 8 ) ^ x;
14815 // always return a positive number (that's what >>> 0 does)
14816 return (crc ^ (-1)) >>> 0;
14822 * @param {Object} [config]
14824 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
14825 * Digest Algorithm, as defined in RFC 1321.
14826 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
14827 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
14828 * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
14830 MD5 : function (options) {
14832 * Private config properties. You may need to tweak these to be compatible with
14833 * the server-side, but the defaults work in most cases.
14834 * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
14836 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
14837 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
14838 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
14840 // privileged (public) methods
14841 this.hex = function (s) {
14842 return rstr2hex(rstr(s, utf8), hexcase);
14844 this.b64 = function (s) {
14845 return rstr2b64(rstr(s), b64pad);
14847 this.any = function(s, e) {
14848 return rstr2any(rstr(s, utf8), e);
14850 this.hex_hmac = function (k, d) {
14851 return rstr2hex(rstr_hmac(k, d), hexcase);
14853 this.b64_hmac = function (k, d) {
14854 return rstr2b64(rstr_hmac(k,d), b64pad);
14856 this.any_hmac = function (k, d, e) {
14857 return rstr2any(rstr_hmac(k, d), e);
14860 * Perform a simple self-test to see if the VM is working
14861 * @return {String} Hexadecimal hash sample
14863 this.vm_test = function () {
14864 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
14867 * Enable/disable uppercase hexadecimal returned string
14869 * @return {Object} this
14871 this.setUpperCase = function (a) {
14872 if (typeof a === 'boolean' ) {
14878 * Defines a base64 pad string
14879 * @param {String} Pad
14880 * @return {Object} this
14882 this.setPad = function (a) {
14883 b64pad = a || b64pad;
14887 * Defines a base64 pad string
14889 * @return {Object} [this]
14891 this.setUTF8 = function (a) {
14892 if (typeof a === 'boolean') {
14901 * Calculate the MD5 of a raw string
14904 s = (utf8) ? utf8Encode(s): s;
14905 return binl2rstr(binl(rstr2binl(s), s.length * 8));
14909 * Calculate the HMAC-MD5, of a key and some data (raw strings)
14911 function rstr_hmac(key, data) {
14912 var bkey, ipad, opad, hash, i;
14914 key = (utf8) ? utf8Encode(key) : key;
14915 data = (utf8) ? utf8Encode(data) : data;
14916 bkey = rstr2binl(key);
14917 if (bkey.length > 16) {
14918 bkey = binl(bkey, key.length * 8);
14921 ipad = Array(16), opad = Array(16);
14922 for (i = 0; i < 16; i+=1) {
14923 ipad[i] = bkey[i] ^ 0x36363636;
14924 opad[i] = bkey[i] ^ 0x5C5C5C5C;
14926 hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
14927 return binl2rstr(binl(opad.concat(hash), 512 + 128));
14931 * Calculate the MD5 of an array of little-endian words, and a bit length.
14933 function binl(x, len) {
14934 var i, olda, oldb, oldc, oldd,
14940 /* append padding */
14941 x[len >> 5] |= 0x80 << ((len) % 32);
14942 x[(((len + 64) >>> 9) << 4) + 14] = len;
14944 for (i = 0; i < x.length; i += 16) {
14950 a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
14951 d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
14952 c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
14953 b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
14954 a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
14955 d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
14956 c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
14957 b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
14958 a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
14959 d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
14960 c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
14961 b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
14962 a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
14963 d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
14964 c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
14965 b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
14967 a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
14968 d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
14969 c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
14970 b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
14971 a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
14972 d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
14973 c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
14974 b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
14975 a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
14976 d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
14977 c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
14978 b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
14979 a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
14980 d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
14981 c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
14982 b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
14984 a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
14985 d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
14986 c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
14987 b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
14988 a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
14989 d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
14990 c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
14991 b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
14992 a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
14993 d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
14994 c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
14995 b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
14996 a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
14997 d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
14998 c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
14999 b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
15001 a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
15002 d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
15003 c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
15004 b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
15005 a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
15006 d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
15007 c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
15008 b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
15009 a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
15010 d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
15011 c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
15012 b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
15013 a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
15014 d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
15015 c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
15016 b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
15018 a = safe_add(a, olda);
15019 b = safe_add(b, oldb);
15020 c = safe_add(c, oldc);
15021 d = safe_add(d, oldd);
15023 return Array(a, b, c, d);
15027 * These functions implement the four basic operations the algorithm uses.
15029 function md5_cmn(q, a, b, x, s, t) {
15030 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
15032 function md5_ff(a, b, c, d, x, s, t) {
15033 return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
15035 function md5_gg(a, b, c, d, x, s, t) {
15036 return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
15038 function md5_hh(a, b, c, d, x, s, t) {
15039 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
15041 function md5_ii(a, b, c, d, x, s, t) {
15042 return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
15047 * @class Hashes.SHA1
15048 * @param {Object} [config]
15051 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
15052 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
15053 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
15054 * See http://pajhome.org.uk/crypt/md5 for details.
15056 SHA1 : function (options) {
15058 * Private config properties. You may need to tweak these to be compatible with
15059 * the server-side, but the defaults work in most cases.
15060 * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
15062 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
15063 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
15064 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
15067 this.hex = function (s) {
15068 return rstr2hex(rstr(s, utf8), hexcase);
15070 this.b64 = function (s) {
15071 return rstr2b64(rstr(s, utf8), b64pad);
15073 this.any = function (s, e) {
15074 return rstr2any(rstr(s, utf8), e);
15076 this.hex_hmac = function (k, d) {
15077 return rstr2hex(rstr_hmac(k, d));
15079 this.b64_hmac = function (k, d) {
15080 return rstr2b64(rstr_hmac(k, d), b64pad);
15082 this.any_hmac = function (k, d, e) {
15083 return rstr2any(rstr_hmac(k, d), e);
15086 * Perform a simple self-test to see if the VM is working
15087 * @return {String} Hexadecimal hash sample
15090 this.vm_test = function () {
15091 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
15094 * @description Enable/disable uppercase hexadecimal returned string
15096 * @return {Object} this
15099 this.setUpperCase = function (a) {
15100 if (typeof a === 'boolean') {
15106 * @description Defines a base64 pad string
15107 * @param {string} Pad
15108 * @return {Object} this
15111 this.setPad = function (a) {
15112 b64pad = a || b64pad;
15116 * @description Defines a base64 pad string
15118 * @return {Object} this
15121 this.setUTF8 = function (a) {
15122 if (typeof a === 'boolean') {
15131 * Calculate the SHA-512 of a raw string
15134 s = (utf8) ? utf8Encode(s) : s;
15135 return binb2rstr(binb(rstr2binb(s), s.length * 8));
15139 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
15141 function rstr_hmac(key, data) {
15142 var bkey, ipad, opad, i, hash;
15143 key = (utf8) ? utf8Encode(key) : key;
15144 data = (utf8) ? utf8Encode(data) : data;
15145 bkey = rstr2binb(key);
15147 if (bkey.length > 16) {
15148 bkey = binb(bkey, key.length * 8);
15150 ipad = Array(16), opad = Array(16);
15151 for (i = 0; i < 16; i+=1) {
15152 ipad[i] = bkey[i] ^ 0x36363636;
15153 opad[i] = bkey[i] ^ 0x5C5C5C5C;
15155 hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
15156 return binb2rstr(binb(opad.concat(hash), 512 + 160));
15160 * Calculate the SHA-1 of an array of big-endian words, and a bit length
15162 function binb(x, len) {
15163 var i, j, t, olda, oldb, oldc, oldd, olde,
15171 /* append padding */
15172 x[len >> 5] |= 0x80 << (24 - len % 32);
15173 x[((len + 64 >> 9) << 4) + 15] = len;
15175 for (i = 0; i < x.length; i += 16) {
15182 for (j = 0; j < 80; j+=1) {
15186 w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
15188 t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
15189 safe_add(safe_add(e, w[j]), sha1_kt(j)));
15192 c = bit_rol(b, 30);
15197 a = safe_add(a, olda);
15198 b = safe_add(b, oldb);
15199 c = safe_add(c, oldc);
15200 d = safe_add(d, oldd);
15201 e = safe_add(e, olde);
15203 return Array(a, b, c, d, e);
15207 * Perform the appropriate triplet combination function for the current
15210 function sha1_ft(t, b, c, d) {
15211 if (t < 20) { return (b & c) | ((~b) & d); }
15212 if (t < 40) { return b ^ c ^ d; }
15213 if (t < 60) { return (b & c) | (b & d) | (c & d); }
15218 * Determine the appropriate additive constant for the current iteration
15220 function sha1_kt(t) {
15221 return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
15222 (t < 60) ? -1894007588 : -899497514;
15226 * @class Hashes.SHA256
15229 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
15230 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
15231 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
15232 * See http://pajhome.org.uk/crypt/md5 for details.
15233 * Also http://anmar.eu.org/projects/jssha2/
15235 SHA256 : function (options) {
15237 * Private properties configuration variables. You may need to tweak these to be compatible with
15238 * the server-side, but the defaults work in most cases.
15239 * @see this.setUpperCase() method
15240 * @see this.setPad() method
15242 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase */
15243 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
15244 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
15247 /* privileged (public) methods */
15248 this.hex = function (s) {
15249 return rstr2hex(rstr(s, utf8));
15251 this.b64 = function (s) {
15252 return rstr2b64(rstr(s, utf8), b64pad);
15254 this.any = function (s, e) {
15255 return rstr2any(rstr(s, utf8), e);
15257 this.hex_hmac = function (k, d) {
15258 return rstr2hex(rstr_hmac(k, d));
15260 this.b64_hmac = function (k, d) {
15261 return rstr2b64(rstr_hmac(k, d), b64pad);
15263 this.any_hmac = function (k, d, e) {
15264 return rstr2any(rstr_hmac(k, d), e);
15267 * Perform a simple self-test to see if the VM is working
15268 * @return {String} Hexadecimal hash sample
15271 this.vm_test = function () {
15272 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
15275 * Enable/disable uppercase hexadecimal returned string
15277 * @return {Object} this
15280 this.setUpperCase = function (a) {
15281 if (typeof a === 'boolean') {
15287 * @description Defines a base64 pad string
15288 * @param {string} Pad
15289 * @return {Object} this
15292 this.setPad = function (a) {
15293 b64pad = a || b64pad;
15297 * Defines a base64 pad string
15299 * @return {Object} this
15302 this.setUTF8 = function (a) {
15303 if (typeof a === 'boolean') {
15312 * Calculate the SHA-512 of a raw string
15314 function rstr(s, utf8) {
15315 s = (utf8) ? utf8Encode(s) : s;
15316 return binb2rstr(binb(rstr2binb(s), s.length * 8));
15320 * Calculate the HMAC-sha256 of a key and some data (raw strings)
15322 function rstr_hmac(key, data) {
15323 key = (utf8) ? utf8Encode(key) : key;
15324 data = (utf8) ? utf8Encode(data) : data;
15326 bkey = rstr2binb(key),
15330 if (bkey.length > 16) { bkey = binb(bkey, key.length * 8); }
15332 for (; i < 16; i+=1) {
15333 ipad[i] = bkey[i] ^ 0x36363636;
15334 opad[i] = bkey[i] ^ 0x5C5C5C5C;
15337 hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
15338 return binb2rstr(binb(opad.concat(hash), 512 + 256));
15342 * Main sha256 function, with its support functions
15344 function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
15345 function sha256_R (X, n) {return ( X >>> n );}
15346 function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
15347 function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
15348 function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
15349 function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
15350 function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
15351 function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
15352 function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
15353 function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
15354 function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
15355 function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
15358 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
15359 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
15360 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
15361 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
15362 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
15363 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
15364 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
15365 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
15366 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
15367 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
15368 -1866530822, -1538233109, -1090935817, -965641998
15371 function binb(m, l) {
15372 var HASH = [1779033703, -1150833019, 1013904242, -1521486534,
15373 1359893119, -1694144372, 528734635, 1541459225];
15374 var W = new Array(64);
15375 var a, b, c, d, e, f, g, h;
15378 /* append padding */
15379 m[l >> 5] |= 0x80 << (24 - l % 32);
15380 m[((l + 64 >> 9) << 4) + 15] = l;
15382 for (i = 0; i < m.length; i += 16)
15393 for (j = 0; j < 64; j+=1)
15398 W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
15399 sha256_Gamma0256(W[j - 15])), W[j - 16]);
15402 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
15403 sha256_K[j]), W[j]);
15404 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
15408 e = safe_add(d, T1);
15412 a = safe_add(T1, T2);
15415 HASH[0] = safe_add(a, HASH[0]);
15416 HASH[1] = safe_add(b, HASH[1]);
15417 HASH[2] = safe_add(c, HASH[2]);
15418 HASH[3] = safe_add(d, HASH[3]);
15419 HASH[4] = safe_add(e, HASH[4]);
15420 HASH[5] = safe_add(f, HASH[5]);
15421 HASH[6] = safe_add(g, HASH[6]);
15422 HASH[7] = safe_add(h, HASH[7]);
15430 * @class Hashes.SHA512
15433 * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
15434 * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
15435 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
15436 * See http://pajhome.org.uk/crypt/md5 for details.
15438 SHA512 : function (options) {
15440 * Private properties configuration variables. You may need to tweak these to be compatible with
15441 * the server-side, but the defaults work in most cases.
15442 * @see this.setUpperCase() method
15443 * @see this.setPad() method
15445 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false , /* hexadecimal output case format. false - lowercase; true - uppercase */
15446 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
15447 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
15450 /* privileged (public) methods */
15451 this.hex = function (s) {
15452 return rstr2hex(rstr(s));
15454 this.b64 = function (s) {
15455 return rstr2b64(rstr(s), b64pad);
15457 this.any = function (s, e) {
15458 return rstr2any(rstr(s), e);
15460 this.hex_hmac = function (k, d) {
15461 return rstr2hex(rstr_hmac(k, d));
15463 this.b64_hmac = function (k, d) {
15464 return rstr2b64(rstr_hmac(k, d), b64pad);
15466 this.any_hmac = function (k, d, e) {
15467 return rstr2any(rstr_hmac(k, d), e);
15470 * Perform a simple self-test to see if the VM is working
15471 * @return {String} Hexadecimal hash sample
15474 this.vm_test = function () {
15475 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
15478 * @description Enable/disable uppercase hexadecimal returned string
15480 * @return {Object} this
15483 this.setUpperCase = function (a) {
15484 if (typeof a === 'boolean') {
15490 * @description Defines a base64 pad string
15491 * @param {string} Pad
15492 * @return {Object} this
15495 this.setPad = function (a) {
15496 b64pad = a || b64pad;
15500 * @description Defines a base64 pad string
15502 * @return {Object} this
15505 this.setUTF8 = function (a) {
15506 if (typeof a === 'boolean') {
15512 /* private methods */
15515 * Calculate the SHA-512 of a raw string
15518 s = (utf8) ? utf8Encode(s) : s;
15519 return binb2rstr(binb(rstr2binb(s), s.length * 8));
15522 * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
15524 function rstr_hmac(key, data) {
15525 key = (utf8) ? utf8Encode(key) : key;
15526 data = (utf8) ? utf8Encode(data) : data;
15529 bkey = rstr2binb(key),
15530 ipad = Array(32), opad = Array(32);
15532 if (bkey.length > 32) { bkey = binb(bkey, key.length * 8); }
15534 for (; i < 32; i+=1) {
15535 ipad[i] = bkey[i] ^ 0x36363636;
15536 opad[i] = bkey[i] ^ 0x5C5C5C5C;
15539 hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
15540 return binb2rstr(binb(opad.concat(hash), 1024 + 512));
15544 * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
15546 function binb(x, len) {
15549 hash = new Array(16),
15550 //Initial hash values
15552 new int64(0x6a09e667, -205731576),
15553 new int64(-1150833019, -2067093701),
15554 new int64(0x3c6ef372, -23791573),
15555 new int64(-1521486534, 0x5f1d36f1),
15556 new int64(0x510e527f, -1377402159),
15557 new int64(-1694144372, 0x2b3e6c1f),
15558 new int64(0x1f83d9ab, -79577749),
15559 new int64(0x5be0cd19, 0x137e2179)
15561 T1 = new int64(0, 0),
15562 T2 = new int64(0, 0),
15563 a = new int64(0,0),
15564 b = new int64(0,0),
15565 c = new int64(0,0),
15566 d = new int64(0,0),
15567 e = new int64(0,0),
15568 f = new int64(0,0),
15569 g = new int64(0,0),
15570 h = new int64(0,0),
15571 //Temporary variables not specified by the document
15572 s0 = new int64(0, 0),
15573 s1 = new int64(0, 0),
15574 Ch = new int64(0, 0),
15575 Maj = new int64(0, 0),
15576 r1 = new int64(0, 0),
15577 r2 = new int64(0, 0),
15578 r3 = new int64(0, 0);
15580 if (sha512_k === undefined) {
15583 new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
15584 new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
15585 new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
15586 new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
15587 new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
15588 new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
15589 new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
15590 new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
15591 new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
15592 new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
15593 new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
15594 new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
15595 new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
15596 new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
15597 new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
15598 new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
15599 new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
15600 new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
15601 new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
15602 new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
15603 new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
15604 new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
15605 new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
15606 new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
15607 new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
15608 new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
15609 new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
15610 new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
15611 new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
15612 new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
15613 new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
15614 new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
15615 new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
15616 new int64(-354779690, -840897762), new int64(-176337025, -294727304),
15617 new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
15618 new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
15619 new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
15620 new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
15621 new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
15622 new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)
15626 for (i=0; i<80; i+=1) {
15627 W[i] = new int64(0, 0);
15630 // append padding to the source string. The format is described in the FIPS.
15631 x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
15632 x[((len + 128 >> 10)<< 5) + 31] = len;
15634 for (i = 0; i<l; i+=32) { //32 dwords is the block size
15635 int64copy(a, H[0]);
15636 int64copy(b, H[1]);
15637 int64copy(c, H[2]);
15638 int64copy(d, H[3]);
15639 int64copy(e, H[4]);
15640 int64copy(f, H[5]);
15641 int64copy(g, H[6]);
15642 int64copy(h, H[7]);
15644 for (j=0; j<16; j+=1) {
15645 W[j].h = x[i + 2*j];
15646 W[j].l = x[i + 2*j + 1];
15649 for (j=16; j<80; j+=1) {
15651 int64rrot(r1, W[j-2], 19);
15652 int64revrrot(r2, W[j-2], 29);
15653 int64shr(r3, W[j-2], 6);
15654 s1.l = r1.l ^ r2.l ^ r3.l;
15655 s1.h = r1.h ^ r2.h ^ r3.h;
15657 int64rrot(r1, W[j-15], 1);
15658 int64rrot(r2, W[j-15], 8);
15659 int64shr(r3, W[j-15], 7);
15660 s0.l = r1.l ^ r2.l ^ r3.l;
15661 s0.h = r1.h ^ r2.h ^ r3.h;
15663 int64add4(W[j], s1, W[j-7], s0, W[j-16]);
15666 for (j = 0; j < 80; j+=1) {
15668 Ch.l = (e.l & f.l) ^ (~e.l & g.l);
15669 Ch.h = (e.h & f.h) ^ (~e.h & g.h);
15672 int64rrot(r1, e, 14);
15673 int64rrot(r2, e, 18);
15674 int64revrrot(r3, e, 9);
15675 s1.l = r1.l ^ r2.l ^ r3.l;
15676 s1.h = r1.h ^ r2.h ^ r3.h;
15679 int64rrot(r1, a, 28);
15680 int64revrrot(r2, a, 2);
15681 int64revrrot(r3, a, 7);
15682 s0.l = r1.l ^ r2.l ^ r3.l;
15683 s0.h = r1.h ^ r2.h ^ r3.h;
15686 Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
15687 Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
15689 int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
15690 int64add(T2, s0, Maj);
15695 int64add(e, d, T1);
15699 int64add(a, T1, T2);
15701 int64add(H[0], H[0], a);
15702 int64add(H[1], H[1], b);
15703 int64add(H[2], H[2], c);
15704 int64add(H[3], H[3], d);
15705 int64add(H[4], H[4], e);
15706 int64add(H[5], H[5], f);
15707 int64add(H[6], H[6], g);
15708 int64add(H[7], H[7], h);
15711 //represent the hash as an array of 32-bit dwords
15712 for (i=0; i<8; i+=1) {
15713 hash[2*i] = H[i].h;
15714 hash[2*i + 1] = H[i].l;
15719 //A constructor for 64-bit numbers
15720 function int64(h, l) {
15723 //this.toString = int64toString;
15726 //Copies src into dst, assuming both are 64-bit numbers
15727 function int64copy(dst, src) {
15732 //Right-rotates a 64-bit number by shift
15733 //Won't handle cases of shift>=32
15734 //The function revrrot() is for that
15735 function int64rrot(dst, x, shift) {
15736 dst.l = (x.l >>> shift) | (x.h << (32-shift));
15737 dst.h = (x.h >>> shift) | (x.l << (32-shift));
15740 //Reverses the dwords of the source and then rotates right by shift.
15741 //This is equivalent to rotation by 32+shift
15742 function int64revrrot(dst, x, shift) {
15743 dst.l = (x.h >>> shift) | (x.l << (32-shift));
15744 dst.h = (x.l >>> shift) | (x.h << (32-shift));
15747 //Bitwise-shifts right a 64-bit number by shift
15748 //Won't handle shift>=32, but it's never needed in SHA512
15749 function int64shr(dst, x, shift) {
15750 dst.l = (x.l >>> shift) | (x.h << (32-shift));
15751 dst.h = (x.h >>> shift);
15754 //Adds two 64-bit numbers
15755 //Like the original implementation, does not rely on 32-bit operations
15756 function int64add(dst, x, y) {
15757 var w0 = (x.l & 0xffff) + (y.l & 0xffff);
15758 var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
15759 var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
15760 var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
15761 dst.l = (w0 & 0xffff) | (w1 << 16);
15762 dst.h = (w2 & 0xffff) | (w3 << 16);
15765 //Same, except with 4 addends. Works faster than adding them one by one.
15766 function int64add4(dst, a, b, c, d) {
15767 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
15768 var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
15769 var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
15770 var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
15771 dst.l = (w0 & 0xffff) | (w1 << 16);
15772 dst.h = (w2 & 0xffff) | (w3 << 16);
15775 //Same, except with 5 addends
15776 function int64add5(dst, a, b, c, d, e) {
15777 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
15778 w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
15779 w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
15780 w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
15781 dst.l = (w0 & 0xffff) | (w1 << 16);
15782 dst.h = (w2 & 0xffff) | (w3 << 16);
15786 * @class Hashes.RMD160
15788 * @param {Object} [config]
15790 * A JavaScript implementation of the RIPEMD-160 Algorithm
15791 * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
15792 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
15793 * See http://pajhome.org.uk/crypt/md5 for details.
15794 * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
15796 RMD160 : function (options) {
15798 * Private properties configuration variables. You may need to tweak these to be compatible with
15799 * the server-side, but the defaults work in most cases.
15800 * @see this.setUpperCase() method
15801 * @see this.setPad() method
15803 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, /* hexadecimal output case format. false - lowercase; true - uppercase */
15804 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
15805 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
15807 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
15808 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
15809 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
15810 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
15811 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
15814 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
15815 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
15816 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
15817 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
15818 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
15821 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
15822 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
15823 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
15824 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
15825 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
15828 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
15829 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
15830 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
15831 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
15832 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
15835 /* privileged (public) methods */
15836 this.hex = function (s) {
15837 return rstr2hex(rstr(s, utf8));
15839 this.b64 = function (s) {
15840 return rstr2b64(rstr(s, utf8), b64pad);
15842 this.any = function (s, e) {
15843 return rstr2any(rstr(s, utf8), e);
15845 this.hex_hmac = function (k, d) {
15846 return rstr2hex(rstr_hmac(k, d));
15848 this.b64_hmac = function (k, d) {
15849 return rstr2b64(rstr_hmac(k, d), b64pad);
15851 this.any_hmac = function (k, d, e) {
15852 return rstr2any(rstr_hmac(k, d), e);
15855 * Perform a simple self-test to see if the VM is working
15856 * @return {String} Hexadecimal hash sample
15859 this.vm_test = function () {
15860 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
15863 * @description Enable/disable uppercase hexadecimal returned string
15865 * @return {Object} this
15868 this.setUpperCase = function (a) {
15869 if (typeof a === 'boolean' ) { hexcase = a; }
15873 * @description Defines a base64 pad string
15874 * @param {string} Pad
15875 * @return {Object} this
15878 this.setPad = function (a) {
15879 if (typeof a !== 'undefined' ) { b64pad = a; }
15883 * @description Defines a base64 pad string
15885 * @return {Object} this
15888 this.setUTF8 = function (a) {
15889 if (typeof a === 'boolean') { utf8 = a; }
15893 /* private methods */
15896 * Calculate the rmd160 of a raw string
15899 s = (utf8) ? utf8Encode(s) : s;
15900 return binl2rstr(binl(rstr2binl(s), s.length * 8));
15904 * Calculate the HMAC-rmd160 of a key and some data (raw strings)
15906 function rstr_hmac(key, data) {
15907 key = (utf8) ? utf8Encode(key) : key;
15908 data = (utf8) ? utf8Encode(data) : data;
15910 bkey = rstr2binl(key),
15911 ipad = Array(16), opad = Array(16);
15913 if (bkey.length > 16) {
15914 bkey = binl(bkey, key.length * 8);
15917 for (i = 0; i < 16; i+=1) {
15918 ipad[i] = bkey[i] ^ 0x36363636;
15919 opad[i] = bkey[i] ^ 0x5C5C5C5C;
15921 hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
15922 return binl2rstr(binl(opad.concat(hash), 512 + 160));
15926 * Convert an array of little-endian words to a string
15928 function binl2rstr(input) {
15929 var i, output = '', l = input.length * 32;
15930 for (i = 0; i < l; i += 8) {
15931 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
15937 * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
15939 function binl(x, len) {
15946 A1, B1, C1, D1, E1,
15947 A2, B2, C2, D2, E2;
15949 /* append padding */
15950 x[len >> 5] |= 0x80 << (len % 32);
15951 x[(((len + 64) >>> 9) << 4) + 14] = len;
15954 for (i = 0; i < l; i+=16) {
15955 A1 = A2 = h0; B1 = B2 = h1; C1 = C2 = h2; D1 = D2 = h3; E1 = E2 = h4;
15956 for (j = 0; j <= 79; j+=1) {
15957 T = safe_add(A1, rmd160_f(j, B1, C1, D1));
15958 T = safe_add(T, x[i + rmd160_r1[j]]);
15959 T = safe_add(T, rmd160_K1(j));
15960 T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
15961 A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
15962 T = safe_add(A2, rmd160_f(79-j, B2, C2, D2));
15963 T = safe_add(T, x[i + rmd160_r2[j]]);
15964 T = safe_add(T, rmd160_K2(j));
15965 T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
15966 A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
15969 T = safe_add(h1, safe_add(C1, D2));
15970 h1 = safe_add(h2, safe_add(D1, E2));
15971 h2 = safe_add(h3, safe_add(E1, A2));
15972 h3 = safe_add(h4, safe_add(A1, B2));
15973 h4 = safe_add(h0, safe_add(B1, C2));
15976 return [h0, h1, h2, h3, h4];
15979 // specific algorithm methods
15980 function rmd160_f(j, x, y, z) {
15981 return ( 0 <= j && j <= 15) ? (x ^ y ^ z) :
15982 (16 <= j && j <= 31) ? (x & y) | (~x & z) :
15983 (32 <= j && j <= 47) ? (x | ~y) ^ z :
15984 (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
15985 (64 <= j && j <= 79) ? x ^ (y | ~z) :
15986 'rmd160_f: j out of range';
15989 function rmd160_K1(j) {
15990 return ( 0 <= j && j <= 15) ? 0x00000000 :
15991 (16 <= j && j <= 31) ? 0x5a827999 :
15992 (32 <= j && j <= 47) ? 0x6ed9eba1 :
15993 (48 <= j && j <= 63) ? 0x8f1bbcdc :
15994 (64 <= j && j <= 79) ? 0xa953fd4e :
15995 'rmd160_K1: j out of range';
15998 function rmd160_K2(j){
15999 return ( 0 <= j && j <= 15) ? 0x50a28be6 :
16000 (16 <= j && j <= 31) ? 0x5c4dd124 :
16001 (32 <= j && j <= 47) ? 0x6d703ef3 :
16002 (48 <= j && j <= 63) ? 0x7a6d76e9 :
16003 (64 <= j && j <= 79) ? 0x00000000 :
16004 'rmd160_K2: j out of range';
16010 (function( window, undefined ) {
16011 var freeExports = false;
16012 if (typeof exports === 'object' ) {
16013 freeExports = exports;
16014 if (exports && typeof global === 'object' && global && global === global.global ) { window = global; }
16017 if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
16018 // define as an anonymous module, so, through path mapping, it can be aliased
16019 define(function () { return Hashes; });
16021 else if ( freeExports ) {
16022 // in Node.js or RingoJS v0.8.0+
16023 if ( typeof module === 'object' && module && module.exports === freeExports ) {
16024 module.exports = Hashes;
16026 // in Narwhal or RingoJS v0.7.0-
16028 freeExports.Hashes = Hashes;
16032 // in a browser or Rhino
16033 window.Hashes = Hashes;
16039 },{}],2:[function(require,module,exports){
16042 var hashes = require('jshashes'),
16043 xtend = require('xtend'),
16044 sha1 = new hashes.SHA1();
16048 ohauth.qsString = function(obj) {
16049 return Object.keys(obj).sort().map(function(key) {
16050 return ohauth.percentEncode(key) + '=' +
16051 ohauth.percentEncode(obj[key]);
16055 ohauth.stringQs = function(str) {
16056 return str.split('&').reduce(function(obj, pair){
16057 var parts = pair.split('=');
16058 obj[decodeURIComponent(parts[0])] = (null === parts[1]) ?
16059 '' : decodeURIComponent(parts[1]);
16064 ohauth.rawxhr = function(method, url, data, headers, callback) {
16065 var xhr = new XMLHttpRequest(),
16066 twoHundred = /^20\d$/;
16067 xhr.onreadystatechange = function() {
16068 if (4 == xhr.readyState && 0 !== xhr.status) {
16069 if (twoHundred.test(xhr.status)) callback(null, xhr);
16070 else return callback(xhr, null);
16073 xhr.onerror = function(e) { return callback(e, null); };
16074 xhr.open(method, url, true);
16075 for (var h in headers) xhr.setRequestHeader(h, headers[h]);
16079 ohauth.xhr = function(method, url, auth, data, options, callback) {
16080 var headers = (options && options.header) || {
16081 'Content-Type': 'application/x-www-form-urlencoded'
16083 headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
16084 ohauth.rawxhr(method, url, data, headers, callback);
16087 ohauth.nonce = function() {
16088 for (var o = ''; o.length < 6;) {
16089 o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
16094 ohauth.authHeader = function(obj) {
16095 return Object.keys(obj).sort().map(function(key) {
16096 return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
16100 ohauth.timestamp = function() { return ~~((+new Date()) / 1000); };
16102 ohauth.percentEncode = function(s) {
16103 return encodeURIComponent(s)
16104 .replace(/\!/g, '%21').replace(/\'/g, '%27')
16105 .replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
16108 ohauth.baseString = function(method, url, params) {
16109 if (params.oauth_signature) delete params.oauth_signature;
16112 ohauth.percentEncode(url),
16113 ohauth.percentEncode(ohauth.qsString(params))].join('&');
16116 ohauth.signature = function(oauth_secret, token_secret, baseString) {
16117 return sha1.b64_hmac(
16118 ohauth.percentEncode(oauth_secret) + '&' +
16119 ohauth.percentEncode(token_secret),
16124 * Takes an options object for configuration (consumer_key,
16125 * consumer_secret, version, signature_method, token) and returns a
16126 * function that generates the Authorization header for given data.
16128 * The returned function takes these parameters:
16129 * - method: GET/POST/...
16130 * - uri: full URI with protocol, port, path and query string
16131 * - extra_params: any extra parameters (that are passed in the POST data),
16132 * can be an object or a from-urlencoded string.
16134 * Returned function returns full OAuth header with "OAuth" string in it.
16137 ohauth.headerGenerator = function(options) {
16138 options = options || {};
16139 var consumer_key = options.consumer_key || '',
16140 consumer_secret = options.consumer_secret || '',
16141 signature_method = options.signature_method || 'HMAC-SHA1',
16142 version = options.version || '1.0',
16143 token = options.token || '';
16145 return function(method, uri, extra_params) {
16146 method = method.toUpperCase();
16147 if (typeof extra_params === 'string' && extra_params.length > 0) {
16148 extra_params = ohauth.stringQs(extra_params);
16151 var uri_parts = uri.split('?', 2),
16152 base_uri = uri_parts[0];
16154 var query_params = uri_parts.length === 2 ?
16155 ohauth.stringQs(uri_parts[1]) : {};
16157 var oauth_params = {
16158 oauth_consumer_key: consumer_key,
16159 oauth_signature_method: signature_method,
16160 oauth_version: version,
16161 oauth_timestamp: ohauth.timestamp(),
16162 oauth_nonce: ohauth.nonce()
16165 if (token) oauth_params.oauth_token = token;
16167 var all_params = xtend({}, oauth_params, query_params, extra_params),
16168 base_str = ohauth.baseString(method, base_uri, all_params);
16170 oauth_params.oauth_signature = ohauth.signature(consumer_secret, token, base_str);
16172 return 'OAuth ' + ohauth.authHeader(oauth_params);
16176 module.exports = ohauth;
16178 },{"jshashes":7,"xtend":4}],6:[function(require,module,exports){
16179 module.exports = Object.keys || require('./shim');
16182 },{"./shim":8}],8:[function(require,module,exports){
16186 // modified from https://github.com/kriskowal/es5-shim
16187 var has = Object.prototype.hasOwnProperty,
16188 is = require('is'),
16189 forEach = require('foreach'),
16190 hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
16197 "propertyIsEnumerable",
16202 keysShim = function keys(object) {
16203 if (!is.object(object) && !is.array(object)) {
16204 throw new TypeError("Object.keys called on a non-object");
16207 var name, theKeys = [];
16208 for (name in object) {
16209 if (has.call(object, name)) {
16210 theKeys.push(name);
16214 if (hasDontEnumBug) {
16215 forEach(dontEnums, function (dontEnum) {
16216 if (has.call(object, dontEnum)) {
16217 theKeys.push(dontEnum);
16224 module.exports = keysShim;
16228 },{"is":9,"foreach":10}],9:[function(require,module,exports){
16232 * the definitive JavaScript type testing library
16234 * @copyright 2013 Enrico Marino
16238 var objProto = Object.prototype;
16239 var owns = objProto.hasOwnProperty;
16240 var toString = objProto.toString;
16241 var isActualNaN = function (value) {
16242 return value !== value;
16244 var NON_HOST_TYPES = {
16255 var is = module.exports = {};
16263 * Test if `value` is a type of `type`.
16265 * @param {Mixed} value value to test
16266 * @param {String} type type
16267 * @return {Boolean} true if `value` is a type of `type`, false otherwise
16272 is.type = function (value, type) {
16273 return typeof value === type;
16278 * Test if `value` is defined.
16280 * @param {Mixed} value value to test
16281 * @return {Boolean} true if 'value' is defined, false otherwise
16285 is.defined = function (value) {
16286 return value !== undefined;
16291 * Test if `value` is empty.
16293 * @param {Mixed} value value to test
16294 * @return {Boolean} true if `value` is empty, false otherwise
16298 is.empty = function (value) {
16299 var type = toString.call(value);
16302 if ('[object Array]' === type || '[object Arguments]' === type) {
16303 return value.length === 0;
16306 if ('[object Object]' === type) {
16307 for (key in value) if (owns.call(value, key)) return false;
16311 if ('[object String]' === type) {
16312 return '' === value;
16320 * Test if `value` is equal to `other`.
16322 * @param {Mixed} value value to test
16323 * @param {Mixed} other value to compare with
16324 * @return {Boolean} true if `value` is equal to `other`, false otherwise
16327 is.equal = function (value, other) {
16328 var type = toString.call(value)
16331 if (type !== toString.call(other)) {
16335 if ('[object Object]' === type) {
16336 for (key in value) {
16337 if (!is.equal(value[key], other[key])) {
16344 if ('[object Array]' === type) {
16345 key = value.length;
16346 if (key !== other.length) {
16350 if (!is.equal(value[key], other[key])) {
16357 if ('[object Function]' === type) {
16358 return value.prototype === other.prototype;
16361 if ('[object Date]' === type) {
16362 return value.getTime() === other.getTime();
16365 return value === other;
16370 * Test if `value` is hosted by `host`.
16372 * @param {Mixed} value to test
16373 * @param {Mixed} host host to test with
16374 * @return {Boolean} true if `value` is hosted by `host`, false otherwise
16378 is.hosted = function (value, host) {
16379 var type = typeof host[value];
16380 return type === 'object' ? !!host[value] : !NON_HOST_TYPES[type];
16385 * Test if `value` is an instance of `constructor`.
16387 * @param {Mixed} value value to test
16388 * @return {Boolean} true if `value` is an instance of `constructor`
16392 is.instance = is['instanceof'] = function (value, constructor) {
16393 return value instanceof constructor;
16398 * Test if `value` is null.
16400 * @param {Mixed} value value to test
16401 * @return {Boolean} true if `value` is null, false otherwise
16405 is['null'] = function (value) {
16406 return value === null;
16411 * Test if `value` is undefined.
16413 * @param {Mixed} value value to test
16414 * @return {Boolean} true if `value` is undefined, false otherwise
16418 is.undefined = function (value) {
16419 return value === undefined;
16428 * Test if `value` is an arguments object.
16430 * @param {Mixed} value value to test
16431 * @return {Boolean} true if `value` is an arguments object, false otherwise
16435 is.arguments = function (value) {
16436 var isStandardArguments = '[object Arguments]' === toString.call(value);
16437 var isOldArguments = !is.array(value) && is.arraylike(value) && is.object(value) && is.fn(value.callee);
16438 return isStandardArguments || isOldArguments;
16447 * Test if 'value' is an array.
16449 * @param {Mixed} value value to test
16450 * @return {Boolean} true if `value` is an array, false otherwise
16454 is.array = function (value) {
16455 return '[object Array]' === toString.call(value);
16459 * is.arguments.empty
16460 * Test if `value` is an empty arguments object.
16462 * @param {Mixed} value value to test
16463 * @return {Boolean} true if `value` is an empty arguments object, false otherwise
16466 is.arguments.empty = function (value) {
16467 return is.arguments(value) && value.length === 0;
16472 * Test if `value` is an empty array.
16474 * @param {Mixed} value value to test
16475 * @return {Boolean} true if `value` is an empty array, false otherwise
16478 is.array.empty = function (value) {
16479 return is.array(value) && value.length === 0;
16484 * Test if `value` is an arraylike object.
16486 * @param {Mixed} value value to test
16487 * @return {Boolean} true if `value` is an arguments object, false otherwise
16491 is.arraylike = function (value) {
16492 return !!value && !is.boolean(value)
16493 && owns.call(value, 'length')
16494 && isFinite(value.length)
16495 && is.number(value.length)
16496 && value.length >= 0;
16505 * Test if `value` is a boolean.
16507 * @param {Mixed} value value to test
16508 * @return {Boolean} true if `value` is a boolean, false otherwise
16512 is.boolean = function (value) {
16513 return '[object Boolean]' === toString.call(value);
16518 * Test if `value` is false.
16520 * @param {Mixed} value value to test
16521 * @return {Boolean} true if `value` is false, false otherwise
16525 is['false'] = function (value) {
16526 return is.boolean(value) && (value === false || value.valueOf() === false);
16531 * Test if `value` is true.
16533 * @param {Mixed} value value to test
16534 * @return {Boolean} true if `value` is true, false otherwise
16538 is['true'] = function (value) {
16539 return is.boolean(value) && (value === true || value.valueOf() === true);
16548 * Test if `value` is a date.
16550 * @param {Mixed} value value to test
16551 * @return {Boolean} true if `value` is a date, false otherwise
16555 is.date = function (value) {
16556 return '[object Date]' === toString.call(value);
16565 * Test if `value` is an html element.
16567 * @param {Mixed} value value to test
16568 * @return {Boolean} true if `value` is an HTML Element, false otherwise
16572 is.element = function (value) {
16573 return value !== undefined
16574 && typeof HTMLElement !== 'undefined'
16575 && value instanceof HTMLElement
16576 && value.nodeType === 1;
16585 * Test if `value` is an error object.
16587 * @param {Mixed} value value to test
16588 * @return {Boolean} true if `value` is an error object, false otherwise
16592 is.error = function (value) {
16593 return '[object Error]' === toString.call(value);
16601 * is.fn / is.function (deprecated)
16602 * Test if `value` is a function.
16604 * @param {Mixed} value value to test
16605 * @return {Boolean} true if `value` is a function, false otherwise
16609 is.fn = is['function'] = function (value) {
16610 var isAlert = typeof window !== 'undefined' && value === window.alert;
16611 return isAlert || '[object Function]' === toString.call(value);
16620 * Test if `value` is a number.
16622 * @param {Mixed} value value to test
16623 * @return {Boolean} true if `value` is a number, false otherwise
16627 is.number = function (value) {
16628 return '[object Number]' === toString.call(value);
16633 * Test if `value` is positive or negative infinity.
16635 * @param {Mixed} value value to test
16636 * @return {Boolean} true if `value` is positive or negative Infinity, false otherwise
16639 is.infinite = function (value) {
16640 return value === Infinity || value === -Infinity;
16645 * Test if `value` is a decimal number.
16647 * @param {Mixed} value value to test
16648 * @return {Boolean} true if `value` is a decimal number, false otherwise
16652 is.decimal = function (value) {
16653 return is.number(value) && !isActualNaN(value) && value % 1 !== 0;
16658 * Test if `value` is divisible by `n`.
16660 * @param {Number} value value to test
16661 * @param {Number} n dividend
16662 * @return {Boolean} true if `value` is divisible by `n`, false otherwise
16666 is.divisibleBy = function (value, n) {
16667 var isDividendInfinite = is.infinite(value);
16668 var isDivisorInfinite = is.infinite(n);
16669 var isNonZeroNumber = is.number(value) && !isActualNaN(value) && is.number(n) && !isActualNaN(n) && n !== 0;
16670 return isDividendInfinite || isDivisorInfinite || (isNonZeroNumber && value % n === 0);
16675 * Test if `value` is an integer.
16677 * @param value to test
16678 * @return {Boolean} true if `value` is an integer, false otherwise
16682 is.int = function (value) {
16683 return is.number(value) && !isActualNaN(value) && value % 1 === 0;
16688 * Test if `value` is greater than 'others' values.
16690 * @param {Number} value value to test
16691 * @param {Array} others values to compare with
16692 * @return {Boolean} true if `value` is greater than `others` values
16696 is.maximum = function (value, others) {
16697 if (isActualNaN(value)) {
16698 throw new TypeError('NaN is not a valid value');
16699 } else if (!is.arraylike(others)) {
16700 throw new TypeError('second argument must be array-like');
16702 var len = others.length;
16704 while (--len >= 0) {
16705 if (value < others[len]) {
16715 * Test if `value` is less than `others` values.
16717 * @param {Number} value value to test
16718 * @param {Array} others values to compare with
16719 * @return {Boolean} true if `value` is less than `others` values
16723 is.minimum = function (value, others) {
16724 if (isActualNaN(value)) {
16725 throw new TypeError('NaN is not a valid value');
16726 } else if (!is.arraylike(others)) {
16727 throw new TypeError('second argument must be array-like');
16729 var len = others.length;
16731 while (--len >= 0) {
16732 if (value > others[len]) {
16742 * Test if `value` is not a number.
16744 * @param {Mixed} value value to test
16745 * @return {Boolean} true if `value` is not a number, false otherwise
16749 is.nan = function (value) {
16750 return !is.number(value) || value !== value;
16755 * Test if `value` is an even number.
16757 * @param {Number} value value to test
16758 * @return {Boolean} true if `value` is an even number, false otherwise
16762 is.even = function (value) {
16763 return is.infinite(value) || (is.number(value) && value === value && value % 2 === 0);
16768 * Test if `value` is an odd number.
16770 * @param {Number} value value to test
16771 * @return {Boolean} true if `value` is an odd number, false otherwise
16775 is.odd = function (value) {
16776 return is.infinite(value) || (is.number(value) && value === value && value % 2 !== 0);
16781 * Test if `value` is greater than or equal to `other`.
16783 * @param {Number} value value to test
16784 * @param {Number} other value to compare with
16785 * @return {Boolean}
16789 is.ge = function (value, other) {
16790 if (isActualNaN(value) || isActualNaN(other)) {
16791 throw new TypeError('NaN is not a valid value');
16793 return !is.infinite(value) && !is.infinite(other) && value >= other;
16798 * Test if `value` is greater than `other`.
16800 * @param {Number} value value to test
16801 * @param {Number} other value to compare with
16802 * @return {Boolean}
16806 is.gt = function (value, other) {
16807 if (isActualNaN(value) || isActualNaN(other)) {
16808 throw new TypeError('NaN is not a valid value');
16810 return !is.infinite(value) && !is.infinite(other) && value > other;
16815 * Test if `value` is less than or equal to `other`.
16817 * @param {Number} value value to test
16818 * @param {Number} other value to compare with
16819 * @return {Boolean} if 'value' is less than or equal to 'other'
16823 is.le = function (value, other) {
16824 if (isActualNaN(value) || isActualNaN(other)) {
16825 throw new TypeError('NaN is not a valid value');
16827 return !is.infinite(value) && !is.infinite(other) && value <= other;
16832 * Test if `value` is less than `other`.
16834 * @param {Number} value value to test
16835 * @param {Number} other value to compare with
16836 * @return {Boolean} if `value` is less than `other`
16840 is.lt = function (value, other) {
16841 if (isActualNaN(value) || isActualNaN(other)) {
16842 throw new TypeError('NaN is not a valid value');
16844 return !is.infinite(value) && !is.infinite(other) && value < other;
16849 * Test if `value` is within `start` and `finish`.
16851 * @param {Number} value value to test
16852 * @param {Number} start lower bound
16853 * @param {Number} finish upper bound
16854 * @return {Boolean} true if 'value' is is within 'start' and 'finish'
16857 is.within = function (value, start, finish) {
16858 if (isActualNaN(value) || isActualNaN(start) || isActualNaN(finish)) {
16859 throw new TypeError('NaN is not a valid value');
16860 } else if (!is.number(value) || !is.number(start) || !is.number(finish)) {
16861 throw new TypeError('all arguments must be numbers');
16863 var isAnyInfinite = is.infinite(value) || is.infinite(start) || is.infinite(finish);
16864 return isAnyInfinite || (value >= start && value <= finish);
16873 * Test if `value` is an object.
16875 * @param {Mixed} value value to test
16876 * @return {Boolean} true if `value` is an object, false otherwise
16880 is.object = function (value) {
16881 return value && '[object Object]' === toString.call(value);
16886 * Test if `value` is a hash - a plain object literal.
16888 * @param {Mixed} value value to test
16889 * @return {Boolean} true if `value` is a hash, false otherwise
16893 is.hash = function (value) {
16894 return is.object(value) && value.constructor === Object && !value.nodeType && !value.setInterval;
16903 * Test if `value` is a regular expression.
16905 * @param {Mixed} value value to test
16906 * @return {Boolean} true if `value` is a regexp, false otherwise
16910 is.regexp = function (value) {
16911 return '[object RegExp]' === toString.call(value);
16920 * Test if `value` is a string.
16922 * @param {Mixed} value value to test
16923 * @return {Boolean} true if 'value' is a string, false otherwise
16927 is.string = function (value) {
16928 return '[object String]' === toString.call(value);
16932 },{}],10:[function(require,module,exports){
16934 var hasOwn = Object.prototype.hasOwnProperty;
16935 var toString = Object.prototype.toString;
16937 module.exports = function forEach (obj, fn, ctx) {
16938 if (toString.call(fn) !== '[object Function]') {
16939 throw new TypeError('iterator must be a function');
16941 var l = obj.length;
16943 for (var i = 0; i < l; i++) {
16944 fn.call(ctx, obj[i], i, obj);
16947 for (var k in obj) {
16948 if (hasOwn.call(obj, k)) {
16949 fn.call(ctx, obj[k], k, obj);
16960 (c) 2015, Vladimir Agafonkin
16961 RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles.
16962 https://github.com/mourner/rbush
16968 function rbush(maxEntries, format) {
16970 // jshint newcap: false, validthis: true
16971 if (!(this instanceof rbush)) return new rbush(maxEntries, format);
16973 // max entries in a node is 9 by default; min node fill is 40% for best performance
16974 this._maxEntries = Math.max(4, maxEntries || 9);
16975 this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
16978 this._initFormat(format);
16984 rbush.prototype = {
16987 return this._all(this.data, []);
16990 search: function (bbox) {
16992 var node = this.data,
16994 toBBox = this.toBBox;
16996 if (!intersects(bbox, node.bbox)) return result;
16998 var nodesToSearch = [],
16999 i, len, child, childBBox;
17002 for (i = 0, len = node.children.length; i < len; i++) {
17004 child = node.children[i];
17005 childBBox = node.leaf ? toBBox(child) : child.bbox;
17007 if (intersects(bbox, childBBox)) {
17008 if (node.leaf) result.push(child);
17009 else if (contains(bbox, childBBox)) this._all(child, result);
17010 else nodesToSearch.push(child);
17013 node = nodesToSearch.pop();
17019 collides: function (bbox) {
17021 var node = this.data,
17022 toBBox = this.toBBox;
17024 if (!intersects(bbox, node.bbox)) return false;
17026 var nodesToSearch = [],
17027 i, len, child, childBBox;
17030 for (i = 0, len = node.children.length; i < len; i++) {
17032 child = node.children[i];
17033 childBBox = node.leaf ? toBBox(child) : child.bbox;
17035 if (intersects(bbox, childBBox)) {
17036 if (node.leaf || contains(bbox, childBBox)) return true;
17037 nodesToSearch.push(child);
17040 node = nodesToSearch.pop();
17046 load: function (data) {
17047 if (!(data && data.length)) return this;
17049 if (data.length < this._minEntries) {
17050 for (var i = 0, len = data.length; i < len; i++) {
17051 this.insert(data[i]);
17056 // recursively build the tree with the given data from stratch using OMT algorithm
17057 var node = this._build(data.slice(), 0, data.length - 1, 0);
17059 if (!this.data.children.length) {
17060 // save as is if tree is empty
17063 } else if (this.data.height === node.height) {
17064 // split root if trees have the same height
17065 this._splitRoot(this.data, node);
17068 if (this.data.height < node.height) {
17069 // swap trees if inserted one is bigger
17070 var tmpNode = this.data;
17075 // insert the small tree into the large tree at appropriate level
17076 this._insert(node, this.data.height - node.height - 1, true);
17082 insert: function (item) {
17083 if (item) this._insert(item, this.data.height - 1);
17087 clear: function () {
17097 remove: function (item) {
17098 if (!item) return this;
17100 var node = this.data,
17101 bbox = this.toBBox(item),
17104 i, parent, index, goingUp;
17106 // depth-first iterative tree traversal
17107 while (node || path.length) {
17109 if (!node) { // go up
17111 parent = path[path.length - 1];
17116 if (node.leaf) { // check current node
17117 index = node.children.indexOf(item);
17119 if (index !== -1) {
17120 // item found, remove the item and condense tree upwards
17121 node.children.splice(index, 1);
17123 this._condense(path);
17128 if (!goingUp && !node.leaf && contains(node.bbox, bbox)) { // go down
17133 node = node.children[0];
17135 } else if (parent) { // go right
17137 node = parent.children[i];
17140 } else node = null; // nothing found
17146 toBBox: function (item) { return item; },
17148 compareMinX: function (a, b) { return a[0] - b[0]; },
17149 compareMinY: function (a, b) { return a[1] - b[1]; },
17151 toJSON: function () { return this.data; },
17153 fromJSON: function (data) {
17158 _all: function (node, result) {
17159 var nodesToSearch = [];
17161 if (node.leaf) result.push.apply(result, node.children);
17162 else nodesToSearch.push.apply(nodesToSearch, node.children);
17164 node = nodesToSearch.pop();
17169 _build: function (items, left, right, height) {
17171 var N = right - left + 1,
17172 M = this._maxEntries,
17176 // reached leaf level; return leaf
17178 children: items.slice(left, right + 1),
17183 calcBBox(node, this.toBBox);
17188 // target height of the bulk-loaded tree
17189 height = Math.ceil(Math.log(N) / Math.log(M));
17191 // target number of root entries to maximize storage utilization
17192 M = Math.ceil(N / Math.pow(M, height - 1));
17202 // split the items into M mostly square tiles
17204 var N2 = Math.ceil(N / M),
17205 N1 = N2 * Math.ceil(Math.sqrt(M)),
17206 i, j, right2, right3;
17208 multiSelect(items, left, right, N1, this.compareMinX);
17210 for (i = left; i <= right; i += N1) {
17212 right2 = Math.min(i + N1 - 1, right);
17214 multiSelect(items, i, right2, N2, this.compareMinY);
17216 for (j = i; j <= right2; j += N2) {
17218 right3 = Math.min(j + N2 - 1, right2);
17220 // pack each entry recursively
17221 node.children.push(this._build(items, j, right3, height - 1));
17225 calcBBox(node, this.toBBox);
17230 _chooseSubtree: function (bbox, node, level, path) {
17232 var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
17237 if (node.leaf || path.length - 1 === level) break;
17239 minArea = minEnlargement = Infinity;
17241 for (i = 0, len = node.children.length; i < len; i++) {
17242 child = node.children[i];
17243 area = bboxArea(child.bbox);
17244 enlargement = enlargedArea(bbox, child.bbox) - area;
17246 // choose entry with the least area enlargement
17247 if (enlargement < minEnlargement) {
17248 minEnlargement = enlargement;
17249 minArea = area < minArea ? area : minArea;
17250 targetNode = child;
17252 } else if (enlargement === minEnlargement) {
17253 // otherwise choose one with the smallest area
17254 if (area < minArea) {
17256 targetNode = child;
17267 _insert: function (item, level, isNode) {
17269 var toBBox = this.toBBox,
17270 bbox = isNode ? item.bbox : toBBox(item),
17273 // find the best node for accommodating the item, saving all nodes along the path too
17274 var node = this._chooseSubtree(bbox, this.data, level, insertPath);
17276 // put the item into the node
17277 node.children.push(item);
17278 extend(node.bbox, bbox);
17280 // split on node overflow; propagate upwards if necessary
17281 while (level >= 0) {
17282 if (insertPath[level].children.length > this._maxEntries) {
17283 this._split(insertPath, level);
17288 // adjust bboxes along the insertion path
17289 this._adjustParentBBoxes(bbox, insertPath, level);
17292 // split overflowed node into two
17293 _split: function (insertPath, level) {
17295 var node = insertPath[level],
17296 M = node.children.length,
17297 m = this._minEntries;
17299 this._chooseSplitAxis(node, m, M);
17301 var splitIndex = this._chooseSplitIndex(node, m, M);
17304 children: node.children.splice(splitIndex, node.children.length - splitIndex),
17305 height: node.height,
17310 if (node.leaf) newNode.leaf = true;
17312 calcBBox(node, this.toBBox);
17313 calcBBox(newNode, this.toBBox);
17315 if (level) insertPath[level - 1].children.push(newNode);
17316 else this._splitRoot(node, newNode);
17319 _splitRoot: function (node, newNode) {
17322 children: [node, newNode],
17323 height: node.height + 1,
17327 calcBBox(this.data, this.toBBox);
17330 _chooseSplitIndex: function (node, m, M) {
17332 var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
17334 minOverlap = minArea = Infinity;
17336 for (i = m; i <= M - m; i++) {
17337 bbox1 = distBBox(node, 0, i, this.toBBox);
17338 bbox2 = distBBox(node, i, M, this.toBBox);
17340 overlap = intersectionArea(bbox1, bbox2);
17341 area = bboxArea(bbox1) + bboxArea(bbox2);
17343 // choose distribution with minimum overlap
17344 if (overlap < minOverlap) {
17345 minOverlap = overlap;
17348 minArea = area < minArea ? area : minArea;
17350 } else if (overlap === minOverlap) {
17351 // otherwise choose distribution with minimum area
17352 if (area < minArea) {
17362 // sorts node children by the best axis for split
17363 _chooseSplitAxis: function (node, m, M) {
17365 var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
17366 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
17367 xMargin = this._allDistMargin(node, m, M, compareMinX),
17368 yMargin = this._allDistMargin(node, m, M, compareMinY);
17370 // if total distributions margin value is minimal for x, sort by minX,
17371 // otherwise it's already sorted by minY
17372 if (xMargin < yMargin) node.children.sort(compareMinX);
17375 // total margin of all possible split distributions where each node is at least m full
17376 _allDistMargin: function (node, m, M, compare) {
17378 node.children.sort(compare);
17380 var toBBox = this.toBBox,
17381 leftBBox = distBBox(node, 0, m, toBBox),
17382 rightBBox = distBBox(node, M - m, M, toBBox),
17383 margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
17386 for (i = m; i < M - m; i++) {
17387 child = node.children[i];
17388 extend(leftBBox, node.leaf ? toBBox(child) : child.bbox);
17389 margin += bboxMargin(leftBBox);
17392 for (i = M - m - 1; i >= m; i--) {
17393 child = node.children[i];
17394 extend(rightBBox, node.leaf ? toBBox(child) : child.bbox);
17395 margin += bboxMargin(rightBBox);
17401 _adjustParentBBoxes: function (bbox, path, level) {
17402 // adjust bboxes along the given tree path
17403 for (var i = level; i >= 0; i--) {
17404 extend(path[i].bbox, bbox);
17408 _condense: function (path) {
17409 // go through the path, removing empty nodes and updating bboxes
17410 for (var i = path.length - 1, siblings; i >= 0; i--) {
17411 if (path[i].children.length === 0) {
17413 siblings = path[i - 1].children;
17414 siblings.splice(siblings.indexOf(path[i]), 1);
17416 } else this.clear();
17418 } else calcBBox(path[i], this.toBBox);
17422 _initFormat: function (format) {
17423 // data format (minX, minY, maxX, maxY accessors)
17425 // uses eval-type function compilation instead of just accepting a toBBox function
17426 // because the algorithms are very sensitive to sorting functions performance,
17427 // so they should be dead simple and without inner calls
17429 // jshint evil: true
17431 var compareArr = ['return a', ' - b', ';'];
17433 this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
17434 this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
17436 this.toBBox = new Function('a', 'return [a' + format.join(', a') + '];');
17441 // calculate node's bbox from bboxes of its children
17442 function calcBBox(node, toBBox) {
17443 node.bbox = distBBox(node, 0, node.children.length, toBBox);
17446 // min bounding rectangle of node children from k to p-1
17447 function distBBox(node, k, p, toBBox) {
17448 var bbox = empty();
17450 for (var i = k, child; i < p; i++) {
17451 child = node.children[i];
17452 extend(bbox, node.leaf ? toBBox(child) : child.bbox);
17458 function empty() { return [Infinity, Infinity, -Infinity, -Infinity]; }
17460 function extend(a, b) {
17461 a[0] = Math.min(a[0], b[0]);
17462 a[1] = Math.min(a[1], b[1]);
17463 a[2] = Math.max(a[2], b[2]);
17464 a[3] = Math.max(a[3], b[3]);
17468 function compareNodeMinX(a, b) { return a.bbox[0] - b.bbox[0]; }
17469 function compareNodeMinY(a, b) { return a.bbox[1] - b.bbox[1]; }
17471 function bboxArea(a) { return (a[2] - a[0]) * (a[3] - a[1]); }
17472 function bboxMargin(a) { return (a[2] - a[0]) + (a[3] - a[1]); }
17474 function enlargedArea(a, b) {
17475 return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) *
17476 (Math.max(b[3], a[3]) - Math.min(b[1], a[1]));
17479 function intersectionArea(a, b) {
17480 var minX = Math.max(a[0], b[0]),
17481 minY = Math.max(a[1], b[1]),
17482 maxX = Math.min(a[2], b[2]),
17483 maxY = Math.min(a[3], b[3]);
17485 return Math.max(0, maxX - minX) *
17486 Math.max(0, maxY - minY);
17489 function contains(a, b) {
17490 return a[0] <= b[0] &&
17496 function intersects(a, b) {
17497 return b[0] <= a[2] &&
17503 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
17504 // combines selection algorithm with binary divide & conquer approach
17506 function multiSelect(arr, left, right, n, compare) {
17507 var stack = [left, right],
17510 while (stack.length) {
17511 right = stack.pop();
17512 left = stack.pop();
17514 if (right - left <= n) continue;
17516 mid = left + Math.ceil((right - left) / n / 2) * n;
17517 select(arr, left, right, mid, compare);
17519 stack.push(left, mid, mid, right);
17523 // Floyd-Rivest selection algorithm:
17524 // sort an array between left and right (inclusive) so that the smallest k elements come first (unordered)
17525 function select(arr, left, right, k, compare) {
17526 var n, i, z, s, sd, newLeft, newRight, t, j;
17528 while (right > left) {
17529 if (right - left > 600) {
17530 n = right - left + 1;
17533 s = 0.5 * Math.exp(2 * z / 3);
17534 sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (i - n / 2 < 0 ? -1 : 1);
17535 newLeft = Math.max(left, Math.floor(k - i * s / n + sd));
17536 newRight = Math.min(right, Math.floor(k + (n - i) * s / n + sd));
17537 select(arr, newLeft, newRight, k, compare);
17544 swap(arr, left, k);
17545 if (compare(arr[right], t) > 0) swap(arr, left, right);
17551 while (compare(arr[i], t) < 0) i++;
17552 while (compare(arr[j], t) > 0) j--;
17555 if (compare(arr[left], t) === 0) swap(arr, left, j);
17558 swap(arr, j, right);
17561 if (j <= k) left = j + 1;
17562 if (k <= j) right = j - 1;
17566 function swap(arr, i, j) {
17573 // export as AMD/CommonJS module or global variable
17574 if (typeof define === 'function' && define.amd) define('rbush', function () { return rbush; });
17575 else if (typeof module !== 'undefined') module.exports = rbush;
17576 else if (typeof self !== 'undefined') self.rbush = rbush;
17577 else window.rbush = rbush;
17580 (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;
17581 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){
17582 module.exports = element;
17583 module.exports.pair = pair;
17584 module.exports.format = format;
17585 module.exports.formatPair = formatPair;
17587 function element(x, dims) {
17588 return search(x, dims).val;
17591 function formatPair(x) {
17592 return format(x.lat, 'lat') + ' ' + format(x.lon, 'lon');
17595 // Is 0 North or South?
17596 function format(x, dim) {
17601 dir = dirs[x >= 0 ? 0 : 1],
17603 whole = Math.floor(abs),
17604 fraction = abs - whole,
17605 fractionMinutes = fraction * 60,
17606 minutes = Math.floor(fractionMinutes),
17607 seconds = Math.floor((fractionMinutes - minutes) * 60);
17609 return whole + '° ' +
17610 (minutes ? minutes + "' " : '') +
17611 (seconds ? seconds + '" ' : '') + dir;
17614 function search(x, dims, r) {
17615 if (!dims) dims = 'NSEW';
17616 if (typeof x !== 'string') return { val: null, regex: r };
17617 r = r || /[\s\,]*([\-|\—|\―]?[0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/gi;
17619 if (!m) return { val: null, regex: r };
17620 else if (m[4] && dims.indexOf(m[4]) === -1) return { val: null, regex: r };
17622 val: (((m[1]) ? parseFloat(m[1]) : 0) +
17623 ((m[2] ? parseFloat(m[2]) / 60 : 0)) +
17624 ((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
17625 ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1),
17632 function pair(x, dims) {
17634 var one = search(x, dims);
17635 if (one.val === null) return null;
17636 var two = search(x, dims, one.regex);
17637 if (two.val === null) return null;
17638 // null if one/two are not contiguous.
17639 if (one.raw + two.raw !== x) return null;
17640 if (one.dim) return swapdim(one.val, two.val, one.dim);
17641 else return [one.val, two.val];
17644 function swapdim(a, b, dim) {
17645 if (dim == 'N' || dim == 'S') return [a, b];
17646 if (dim == 'W' || dim == 'E') return [b, a];
17652 ;toGeoJSON = (function() {
17655 var removeSpace = (/\s*/g),
17656 trimSpace = (/^\s*|\s*$/g),
17657 splitSpace = (/\s+/);
17658 // generate a short, numeric hash of a string
17659 function okhash(x) {
17660 if (!x || !x.length) return 0;
17661 for (var i = 0, h = 0; i < x.length; i++) {
17662 h = ((h << 5) - h) + x.charCodeAt(i) | 0;
17665 // all Y children of X
17666 function get(x, y) { return x.getElementsByTagName(y); }
17667 function attr(x, y) { return x.getAttribute(y); }
17668 function attrf(x, y) { return parseFloat(attr(x, y)); }
17669 // one Y child of X, if any, otherwise null
17670 function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
17671 // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
17672 function norm(el) { if (el.normalize) { el.normalize(); } return el; }
17673 // cast array x into numbers
17674 function numarray(x) {
17675 for (var j = 0, o = []; j < x.length; j++) o[j] = parseFloat(x[j]);
17678 function clean(x) {
17680 for (var i in x) if (x[i]) o[i] = x[i];
17683 // get the content of a text node, if any
17684 function nodeVal(x) { if (x) {norm(x);} return x && x.firstChild && x.firstChild.nodeValue; }
17685 // get one coordinate from a coordinate array, if any
17686 function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
17687 // get all coordinates from a coordinate array as [[],[]]
17688 function coord(v) {
17689 var coords = v.replace(trimSpace, '').split(splitSpace),
17691 for (var i = 0; i < coords.length; i++) {
17692 o.push(coord1(coords[i]));
17696 function coordPair(x) { return [attrf(x, 'lon'), attrf(x, 'lat')]; }
17698 // create a new feature collection parent object
17701 type: 'FeatureCollection',
17706 var styleSupport = false;
17707 if (typeof XMLSerializer !== 'undefined') {
17708 var serializer = new XMLSerializer();
17709 styleSupport = true;
17711 function xml2str(str) { return serializer.serializeToString(str); }
17714 kml: function(doc, o) {
17718 // styleindex keeps track of hashed styles in order to match features
17720 // atomic geospatial types supported by KML - MultiGeometry is
17721 // handled separately
17722 geotypes = ['Polygon', 'LineString', 'Point', 'Track'],
17723 // all root placemarks in the file
17724 placemarks = get(doc, 'Placemark'),
17725 styles = get(doc, 'Style');
17727 if (styleSupport) for (var k = 0; k < styles.length; k++) {
17728 styleIndex['#' + attr(styles[k], 'id')] = okhash(xml2str(styles[k])).toString(16);
17730 for (var j = 0; j < placemarks.length; j++) {
17731 gj.features = gj.features.concat(getPlacemark(placemarks[j]));
17733 function gxCoord(v) { return numarray(v.split(' ')); }
17734 function gxCoords(root) {
17735 var elems = get(root, 'coord', 'gx'), coords = [];
17736 for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
17739 function getGeometry(root) {
17740 var geomNode, geomNodes, i, j, k, geoms = [];
17741 if (get1(root, 'MultiGeometry')) return getGeometry(get1(root, 'MultiGeometry'));
17742 if (get1(root, 'MultiTrack')) return getGeometry(get1(root, 'MultiTrack'));
17743 for (i = 0; i < geotypes.length; i++) {
17744 geomNodes = get(root, geotypes[i]);
17746 for (j = 0; j < geomNodes.length; j++) {
17747 geomNode = geomNodes[j];
17748 if (geotypes[i] == 'Point') {
17751 coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
17753 } else if (geotypes[i] == 'LineString') {
17755 type: 'LineString',
17756 coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
17758 } else if (geotypes[i] == 'Polygon') {
17759 var rings = get(geomNode, 'LinearRing'),
17761 for (k = 0; k < rings.length; k++) {
17762 coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
17766 coordinates: coords
17768 } else if (geotypes[i] == 'Track') {
17770 type: 'LineString',
17771 coordinates: gxCoords(geomNode)
17779 function getPlacemark(root) {
17780 var geoms = getGeometry(root), i, properties = {},
17781 name = nodeVal(get1(root, 'name')),
17782 styleUrl = nodeVal(get1(root, 'styleUrl')),
17783 description = nodeVal(get1(root, 'description')),
17784 extendedData = get1(root, 'ExtendedData');
17786 if (!geoms.length) return [];
17787 if (name) properties.name = name;
17788 if (styleUrl && styleIndex[styleUrl]) {
17789 properties.styleUrl = styleUrl;
17790 properties.styleHash = styleIndex[styleUrl];
17792 if (description) properties.description = description;
17793 if (extendedData) {
17794 var datas = get(extendedData, 'Data'),
17795 simpleDatas = get(extendedData, 'SimpleData');
17797 for (i = 0; i < datas.length; i++) {
17798 properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
17800 for (i = 0; i < simpleDatas.length; i++) {
17801 properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
17806 geometry: (geoms.length === 1) ? geoms[0] : {
17807 type: 'GeometryCollection',
17810 properties: properties
17815 gpx: function(doc, o) {
17817 tracks = get(doc, 'trk'),
17818 routes = get(doc, 'rte'),
17819 waypoints = get(doc, 'wpt'),
17820 // a feature collection
17822 for (i = 0; i < tracks.length; i++) {
17823 gj.features.push(getLinestring(tracks[i], 'trkpt'));
17825 for (i = 0; i < routes.length; i++) {
17826 gj.features.push(getLinestring(routes[i], 'rtept'));
17828 for (i = 0; i < waypoints.length; i++) {
17829 gj.features.push(getPoint(waypoints[i]));
17831 function getLinestring(node, pointname) {
17832 var j, pts = get(node, pointname), line = [];
17833 for (j = 0; j < pts.length; j++) {
17834 line.push(coordPair(pts[j]));
17838 properties: getProperties(node),
17840 type: 'LineString',
17845 function getPoint(node) {
17846 var prop = getProperties(node);
17847 prop.ele = nodeVal(get1(node, 'ele'));
17848 prop.sym = nodeVal(get1(node, 'sym'));
17854 coordinates: coordPair(node)
17858 function getProperties(node) {
17859 var meta = ['name', 'desc', 'author', 'copyright', 'link',
17860 'time', 'keywords'],
17863 for (k = 0; k < meta.length; k++) {
17864 prop[meta[k]] = nodeVal(get1(node, meta[k]));
17866 return clean(prop);
17874 if (typeof module !== 'undefined') module.exports = toGeoJSON;
17876 * marked - a markdown parser
17877 * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
17878 * https://github.com/chjj/marked
17884 * Block-Level Grammar
17889 code: /^( {4}[^\n]+\n*)+/,
17891 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17892 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17894 lheading: /^([^\n]+)\n *(=|-){3,} *\n*/,
17895 blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
17896 list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17897 html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
17898 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17900 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17904 block.bullet = /(?:[*+-]|\d+\.)/;
17905 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17906 block.item = replace(block.item, 'gm')
17907 (/bull/g, block.bullet)
17910 block.list = replace(block.list)
17911 (/bull/g, block.bullet)
17912 ('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
17915 block._tag = '(?!(?:'
17916 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17917 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17918 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
17920 block.html = replace(block.html)
17921 ('comment', /<!--[\s\S]*?-->/)
17922 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17923 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17924 (/tag/g, block._tag)
17927 block.paragraph = replace(block.paragraph)
17929 ('heading', block.heading)
17930 ('lheading', block.lheading)
17931 ('blockquote', block.blockquote)
17932 ('tag', '<' + block._tag)
17937 * Normal Block Grammar
17940 block.normal = merge({}, block);
17943 * GFM Block Grammar
17946 block.gfm = merge({}, block.normal, {
17947 fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
17951 block.gfm.paragraph = replace(block.paragraph)
17952 ('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|')
17956 * GFM + Tables Block Grammar
17959 block.tables = merge({}, block.gfm, {
17960 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17961 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17968 function Lexer(options) {
17970 this.tokens.links = {};
17971 this.options = options || marked.defaults;
17972 this.rules = block.normal;
17974 if (this.options.gfm) {
17975 if (this.options.tables) {
17976 this.rules = block.tables;
17978 this.rules = block.gfm;
17984 * Expose Block Rules
17987 Lexer.rules = block;
17990 * Static Lex Method
17993 Lexer.lex = function(src, options) {
17994 var lexer = new Lexer(options);
17995 return lexer.lex(src);
18002 Lexer.prototype.lex = function(src) {
18004 .replace(/\r\n|\r/g, '\n')
18005 .replace(/\t/g, ' ')
18006 .replace(/\u00a0/g, ' ')
18007 .replace(/\u2424/g, '\n');
18009 return this.token(src, true);
18016 Lexer.prototype.token = function(src, top) {
18017 var src = src.replace(/^ +$/gm, '')
18030 if (cap = this.rules.newline.exec(src)) {
18031 src = src.substring(cap[0].length);
18032 if (cap[0].length > 1) {
18040 if (cap = this.rules.code.exec(src)) {
18041 src = src.substring(cap[0].length);
18042 cap = cap[0].replace(/^ {4}/gm, '');
18045 text: !this.options.pedantic
18046 ? cap.replace(/\n+$/, '')
18053 if (cap = this.rules.fences.exec(src)) {
18054 src = src.substring(cap[0].length);
18064 if (cap = this.rules.heading.exec(src)) {
18065 src = src.substring(cap[0].length);
18068 depth: cap[1].length,
18074 // table no leading pipe (gfm)
18075 if (top && (cap = this.rules.nptable.exec(src))) {
18076 src = src.substring(cap[0].length);
18080 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18081 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18082 cells: cap[3].replace(/\n$/, '').split('\n')
18085 for (i = 0; i < item.align.length; i++) {
18086 if (/^ *-+: *$/.test(item.align[i])) {
18087 item.align[i] = 'right';
18088 } else if (/^ *:-+: *$/.test(item.align[i])) {
18089 item.align[i] = 'center';
18090 } else if (/^ *:-+ *$/.test(item.align[i])) {
18091 item.align[i] = 'left';
18093 item.align[i] = null;
18097 for (i = 0; i < item.cells.length; i++) {
18098 item.cells[i] = item.cells[i].split(/ *\| */);
18101 this.tokens.push(item);
18107 if (cap = this.rules.lheading.exec(src)) {
18108 src = src.substring(cap[0].length);
18111 depth: cap[2] === '=' ? 1 : 2,
18118 if (cap = this.rules.hr.exec(src)) {
18119 src = src.substring(cap[0].length);
18127 if (cap = this.rules.blockquote.exec(src)) {
18128 src = src.substring(cap[0].length);
18131 type: 'blockquote_start'
18134 cap = cap[0].replace(/^ *> ?/gm, '');
18136 // Pass `top` to keep the current
18137 // "toplevel" state. This is exactly
18138 // how markdown.pl works.
18139 this.token(cap, top);
18142 type: 'blockquote_end'
18149 if (cap = this.rules.list.exec(src)) {
18150 src = src.substring(cap[0].length);
18154 type: 'list_start',
18155 ordered: bull.length > 1
18158 // Get each top-level item.
18159 cap = cap[0].match(this.rules.item);
18165 for (; i < l; i++) {
18168 // Remove the list item's bullet
18169 // so it is seen as the next token.
18170 space = item.length;
18171 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18173 // Outdent whatever the
18174 // list item contains. Hacky.
18175 if (~item.indexOf('\n ')) {
18176 space -= item.length;
18177 item = !this.options.pedantic
18178 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18179 : item.replace(/^ {1,4}/gm, '');
18182 // Determine whether the next list item belongs here.
18183 // Backpedal if it does not belong in this list.
18184 if (this.options.smartLists && i !== l - 1) {
18185 b = block.bullet.exec(cap[i+1])[0];
18186 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18187 src = cap.slice(i + 1).join('\n') + src;
18192 // Determine whether item is loose or not.
18193 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18194 // for discount behavior.
18195 loose = next || /\n\n(?!\s*$)/.test(item);
18197 next = item[item.length-1] === '\n';
18198 if (!loose) loose = next;
18203 ? 'loose_item_start'
18204 : 'list_item_start'
18208 this.token(item, false);
18211 type: 'list_item_end'
18223 if (cap = this.rules.html.exec(src)) {
18224 src = src.substring(cap[0].length);
18226 type: this.options.sanitize
18229 pre: cap[1] === 'pre' || cap[1] === 'script',
18236 if (top && (cap = this.rules.def.exec(src))) {
18237 src = src.substring(cap[0].length);
18238 this.tokens.links[cap[1].toLowerCase()] = {
18246 if (top && (cap = this.rules.table.exec(src))) {
18247 src = src.substring(cap[0].length);
18251 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18252 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18253 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18256 for (i = 0; i < item.align.length; i++) {
18257 if (/^ *-+: *$/.test(item.align[i])) {
18258 item.align[i] = 'right';
18259 } else if (/^ *:-+: *$/.test(item.align[i])) {
18260 item.align[i] = 'center';
18261 } else if (/^ *:-+ *$/.test(item.align[i])) {
18262 item.align[i] = 'left';
18264 item.align[i] = null;
18268 for (i = 0; i < item.cells.length; i++) {
18269 item.cells[i] = item.cells[i]
18270 .replace(/^ *\| *| *\| *$/g, '')
18274 this.tokens.push(item);
18279 // top-level paragraph
18280 if (top && (cap = this.rules.paragraph.exec(src))) {
18281 src = src.substring(cap[0].length);
18284 text: cap[1][cap[1].length-1] === '\n'
18285 ? cap[1].slice(0, -1)
18292 if (cap = this.rules.text.exec(src)) {
18293 // Top-level should never reach here.
18294 src = src.substring(cap[0].length);
18304 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18308 return this.tokens;
18312 * Inline-Level Grammar
18316 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18317 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18319 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18320 link: /^!?\[(inside)\]\(href\)/,
18321 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18322 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18323 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18324 em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18325 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18326 br: /^ {2,}\n(?!\s*$)/,
18328 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18331 inline._inside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
18332 inline._href = /\s*<?([^\s]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18334 inline.link = replace(inline.link)
18335 ('inside', inline._inside)
18336 ('href', inline._href)
18339 inline.reflink = replace(inline.reflink)
18340 ('inside', inline._inside)
18344 * Normal Inline Grammar
18347 inline.normal = merge({}, inline);
18350 * Pedantic Inline Grammar
18353 inline.pedantic = merge({}, inline.normal, {
18354 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18355 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18359 * GFM Inline Grammar
18362 inline.gfm = merge({}, inline.normal, {
18363 escape: replace(inline.escape)('])', '~|])')(),
18364 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18365 del: /^~~(?=\S)([\s\S]*?\S)~~/,
18366 text: replace(inline.text)
18368 ('|', '|https?://|')
18373 * GFM + Line Breaks Inline Grammar
18376 inline.breaks = merge({}, inline.gfm, {
18377 br: replace(inline.br)('{2,}', '*')(),
18378 text: replace(inline.gfm.text)('{2,}', '*')()
18382 * Inline Lexer & Compiler
18385 function InlineLexer(links, options) {
18386 this.options = options || marked.defaults;
18387 this.links = links;
18388 this.rules = inline.normal;
18392 Error('Tokens array requires a `links` property.');
18395 if (this.options.gfm) {
18396 if (this.options.breaks) {
18397 this.rules = inline.breaks;
18399 this.rules = inline.gfm;
18401 } else if (this.options.pedantic) {
18402 this.rules = inline.pedantic;
18407 * Expose Inline Rules
18410 InlineLexer.rules = inline;
18413 * Static Lexing/Compiling Method
18416 InlineLexer.output = function(src, links, options) {
18417 var inline = new InlineLexer(links, options);
18418 return inline.output(src);
18425 InlineLexer.prototype.output = function(src) {
18434 if (cap = this.rules.escape.exec(src)) {
18435 src = src.substring(cap[0].length);
18441 if (cap = this.rules.autolink.exec(src)) {
18442 src = src.substring(cap[0].length);
18443 if (cap[2] === '@') {
18444 text = cap[1][6] === ':'
18445 ? this.mangle(cap[1].substring(7))
18446 : this.mangle(cap[1]);
18447 href = this.mangle('mailto:') + text;
18449 text = escape(cap[1]);
18461 if (cap = this.rules.url.exec(src)) {
18462 src = src.substring(cap[0].length);
18463 text = escape(cap[1]);
18474 if (cap = this.rules.tag.exec(src)) {
18475 src = src.substring(cap[0].length);
18476 out += this.options.sanitize
18483 if (cap = this.rules.link.exec(src)) {
18484 src = src.substring(cap[0].length);
18485 out += this.outputLink(cap, {
18493 if ((cap = this.rules.reflink.exec(src))
18494 || (cap = this.rules.nolink.exec(src))) {
18495 src = src.substring(cap[0].length);
18496 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18497 link = this.links[link.toLowerCase()];
18498 if (!link || !link.href) {
18500 src = cap[0].substring(1) + src;
18503 out += this.outputLink(cap, link);
18508 if (cap = this.rules.strong.exec(src)) {
18509 src = src.substring(cap[0].length);
18511 + this.output(cap[2] || cap[1])
18517 if (cap = this.rules.em.exec(src)) {
18518 src = src.substring(cap[0].length);
18520 + this.output(cap[2] || cap[1])
18526 if (cap = this.rules.code.exec(src)) {
18527 src = src.substring(cap[0].length);
18529 + escape(cap[2], true)
18535 if (cap = this.rules.br.exec(src)) {
18536 src = src.substring(cap[0].length);
18542 if (cap = this.rules.del.exec(src)) {
18543 src = src.substring(cap[0].length);
18545 + this.output(cap[1])
18551 if (cap = this.rules.text.exec(src)) {
18552 src = src.substring(cap[0].length);
18553 out += escape(cap[0]);
18559 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18570 InlineLexer.prototype.outputLink = function(cap, link) {
18571 if (cap[0][0] !== '!') {
18573 + escape(link.href)
18577 + escape(link.title)
18581 + this.output(cap[1])
18584 return '<img src="'
18585 + escape(link.href)
18591 + escape(link.title)
18599 * Smartypants Transformations
18602 InlineLexer.prototype.smartypants = function(text) {
18603 if (!this.options.smartypants) return text;
18605 .replace(/--/g, '—')
18606 .replace(/'([^']*)'/g, '‘$1’')
18607 .replace(/"([^"]*)"/g, '“$1”')
18608 .replace(/\.{3}/g, '…');
18615 InlineLexer.prototype.mangle = function(text) {
18621 for (; i < l; i++) {
18622 ch = text.charCodeAt(i);
18623 if (Math.random() > 0.5) {
18624 ch = 'x' + ch.toString(16);
18626 out += '&#' + ch + ';';
18633 * Parsing & Compiling
18636 function Parser(options) {
18639 this.options = options || marked.defaults;
18643 * Static Parse Method
18646 Parser.parse = function(src, options) {
18647 var parser = new Parser(options);
18648 return parser.parse(src);
18655 Parser.prototype.parse = function(src) {
18656 this.inline = new InlineLexer(src.links, this.options);
18657 this.tokens = src.reverse();
18660 while (this.next()) {
18671 Parser.prototype.next = function() {
18672 return this.token = this.tokens.pop();
18676 * Preview Next Token
18679 Parser.prototype.peek = function() {
18680 return this.tokens[this.tokens.length-1] || 0;
18684 * Parse Text Tokens
18687 Parser.prototype.parseText = function() {
18688 var body = this.token.text;
18690 while (this.peek().type === 'text') {
18691 body += '\n' + this.next().text;
18694 return this.inline.output(body);
18698 * Parse Current Token
18701 Parser.prototype.tok = function() {
18702 switch (this.token.type) {
18713 + this.inline.output(this.token.text)
18719 if (this.options.highlight) {
18720 var code = this.options.highlight(this.token.text, this.token.lang);
18721 if (code != null && code !== this.token.text) {
18722 this.token.escaped = true;
18723 this.token.text = code;
18727 if (!this.token.escaped) {
18728 this.token.text = escape(this.token.text, true);
18731 return '<pre><code'
18734 + this.options.langPrefix
18740 + '</code></pre>\n';
18751 body += '<thead>\n<tr>\n';
18752 for (i = 0; i < this.token.header.length; i++) {
18753 heading = this.inline.output(this.token.header[i]);
18754 body += this.token.align[i]
18755 ? '<th align="' + this.token.align[i] + '">' + heading + '</th>\n'
18756 : '<th>' + heading + '</th>\n';
18758 body += '</tr>\n</thead>\n';
18761 body += '<tbody>\n'
18762 for (i = 0; i < this.token.cells.length; i++) {
18763 row = this.token.cells[i];
18765 for (j = 0; j < row.length; j++) {
18766 cell = this.inline.output(row[j]);
18767 body += this.token.align[j]
18768 ? '<td align="' + this.token.align[j] + '">' + cell + '</td>\n'
18769 : '<td>' + cell + '</td>\n';
18773 body += '</tbody>\n';
18779 case 'blockquote_start': {
18782 while (this.next().type !== 'blockquote_end') {
18783 body += this.tok();
18786 return '<blockquote>\n'
18788 + '</blockquote>\n';
18790 case 'list_start': {
18791 var type = this.token.ordered ? 'ol' : 'ul'
18794 while (this.next().type !== 'list_end') {
18795 body += this.tok();
18806 case 'list_item_start': {
18809 while (this.next().type !== 'list_item_end') {
18810 body += this.token.type === 'text'
18819 case 'loose_item_start': {
18822 while (this.next().type !== 'list_item_end') {
18823 body += this.tok();
18831 return !this.token.pre && !this.options.pedantic
18832 ? this.inline.output(this.token.text)
18835 case 'paragraph': {
18837 + this.inline.output(this.token.text)
18852 function escape(html, encode) {
18854 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
18855 .replace(/</g, '<')
18856 .replace(/>/g, '>')
18857 .replace(/"/g, '"')
18858 .replace(/'/g, ''');
18861 function replace(regex, opt) {
18862 regex = regex.source;
18864 return function self(name, val) {
18865 if (!name) return new RegExp(regex, opt);
18866 val = val.source || val;
18867 val = val.replace(/(^|[^\[])\^/g, '$1');
18868 regex = regex.replace(name, val);
18876 function merge(obj) {
18881 for (; i < arguments.length; i++) {
18882 target = arguments[i];
18883 for (key in target) {
18884 if (Object.prototype.hasOwnProperty.call(target, key)) {
18885 obj[key] = target[key];
18897 function marked(src, opt, callback) {
18898 if (callback || typeof opt === 'function') {
18904 if (opt) opt = merge({}, marked.defaults, opt);
18906 var tokens = Lexer.lex(tokens, opt)
18907 , highlight = opt.highlight
18909 , l = tokens.length
18912 if (!highlight || highlight.length < 3) {
18913 return callback(null, Parser.parse(tokens, opt));
18916 var done = function() {
18917 delete opt.highlight;
18918 var out = Parser.parse(tokens, opt);
18919 opt.highlight = highlight;
18920 return callback(null, out);
18923 for (; i < l; i++) {
18925 if (token.type !== 'code') return;
18927 return highlight(token.text, token.lang, function(err, code) {
18928 if (code == null || code === token.text) {
18929 return --pending || done();
18932 token.escaped = true;
18933 --pending || done();
18941 if (opt) opt = merge({}, marked.defaults, opt);
18942 return Parser.parse(Lexer.lex(src, opt), opt);
18944 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18945 if ((opt || marked.defaults).silent) {
18946 return '<p>An error occured:</p><pre>'
18947 + escape(e.message + '', true)
18959 marked.setOptions = function(opt) {
18960 merge(marked.defaults, opt);
18964 marked.defaults = {
18973 langPrefix: 'lang-'
18980 marked.Parser = Parser;
18981 marked.parser = Parser.parse;
18983 marked.Lexer = Lexer;
18984 marked.lexer = Lexer.lex;
18986 marked.InlineLexer = InlineLexer;
18987 marked.inlineLexer = InlineLexer.output;
18989 marked.parse = marked;
18991 if (typeof exports === 'object') {
18992 module.exports = marked;
18993 } else if (typeof define === 'function' && define.amd) {
18994 define(function() { return marked; });
18996 this.marked = marked;
18999 }).call(function() {
19000 return this || (typeof window !== 'undefined' ? window : global);
19004 window.iD = function () {
19005 window.locale.en = iD.data.en;
19006 window.locale.current('en');
19008 var dispatch = d3.dispatch('enter', 'exit'),
19011 // https://github.com/openstreetmap/iD/issues/772
19012 // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
19014 try { storage = localStorage; } catch (e) {} // eslint-disable-line no-empty
19015 storage = storage || (function() {
19018 getItem: function(k) { return s[k]; },
19019 setItem: function(k, v) { s[k] = v; },
19020 removeItem: function(k) { delete s[k]; }
19024 context.storage = function(k, v) {
19026 if (arguments.length === 1) return storage.getItem(k);
19027 else if (v === null) storage.removeItem(k);
19028 else storage.setItem(k, v);
19030 // localstorage quota exceeded
19031 /* eslint-disable no-console */
19032 if (typeof console !== 'undefined') console.error('localStorage quota exceeded');
19033 /* eslint-enable no-console */
19037 var locale, localePath;
19038 context.locale = function(loc, path) {
19042 // Also set iD.detect().locale (unless we detected 'en-us' and openstreetmap wants 'en')..
19043 if (!(loc.toLowerCase() === 'en' && iD.detect().locale.toLowerCase() === 'en-us')) {
19044 iD.detect().locale = loc;
19050 context.loadLocale = function(cb) {
19051 if (locale && locale !== 'en' && iD.data.locales.indexOf(locale) !== -1) {
19052 localePath = localePath || context.assetPath() + 'locales/' + locale + '.json';
19053 d3.json(localePath, function(err, result) {
19054 window.locale[locale] = result;
19055 window.locale.current(locale);
19064 /* Straight accessors. Avoid using these if you can. */
19065 var ui, connection, history;
19066 context.ui = function() { return ui; };
19067 context.connection = function() { return connection; };
19068 context.history = function() { return history; };
19072 function entitiesLoaded(err, result) {
19073 if (!err) history.merge(result.data, result.extent);
19076 context.preauth = function(options) {
19077 connection.switch(options);
19081 context.loadTiles = function(projection, dimensions, callback) {
19082 function done(err, result) {
19083 entitiesLoaded(err, result);
19084 if (callback) callback(err, result);
19086 connection.loadTiles(projection, dimensions, done);
19089 context.loadEntity = function(id, callback) {
19090 function done(err, result) {
19091 entitiesLoaded(err, result);
19092 if (callback) callback(err, result);
19094 connection.loadEntity(id, done);
19097 context.zoomToEntity = function(id, zoomTo) {
19098 if (zoomTo !== false) {
19099 this.loadEntity(id, function(err, result) {
19101 var entity = _.find(result.data, function(e) { return e.id === id; });
19102 if (entity) { map.zoomTo(entity); }
19106 map.on('drawn.zoomToEntity', function() {
19107 if (!context.hasEntity(id)) return;
19108 map.on('drawn.zoomToEntity', null);
19109 context.on('enter.zoomToEntity', null);
19110 context.enter(iD.modes.Select(context, [id]));
19113 context.on('enter.zoomToEntity', function() {
19114 if (mode.id !== 'browse') {
19115 map.on('drawn.zoomToEntity', null);
19116 context.on('enter.zoomToEntity', null);
19121 var minEditableZoom = 16;
19122 context.minEditableZoom = function(_) {
19123 if (!arguments.length) return minEditableZoom;
19124 minEditableZoom = _;
19125 connection.tileZoom(_);
19131 var inIntro = false;
19132 context.inIntro = function(_) {
19133 if (!arguments.length) return inIntro;
19138 context.save = function() {
19139 if (inIntro || (mode && mode.id === 'save')) return;
19141 if (history.hasChanges()) return t('save.unsaved_changes');
19144 context.flush = function() {
19145 context.debouncedSave.cancel();
19146 connection.flush();
19149 _.each(iD.services, function(service) {
19150 var reset = service().reset;
19151 if (reset) reset(context);
19158 context.hasEntity = function(id) {
19159 return history.graph().hasEntity(id);
19161 context.entity = function(id) {
19162 return history.graph().entity(id);
19164 context.childNodes = function(way) {
19165 return history.graph().childNodes(way);
19167 context.geometry = function(id) {
19168 return context.entity(id).geometry(history.graph());
19174 context.mode = function() {
19177 context.enter = function(newMode) {
19180 dispatch.exit(mode);
19185 dispatch.enter(mode);
19188 context.selectedIDs = function() {
19189 if (mode && mode.selectedIDs) {
19190 return mode.selectedIDs();
19198 context.install = function(behavior) {
19199 context.surface().call(behavior);
19201 context.uninstall = function(behavior) {
19202 context.surface().call(behavior.off);
19207 var copyIDs = [], copyGraph;
19208 context.copyGraph = function() { return copyGraph; };
19209 context.copyIDs = function(_) {
19210 if (!arguments.length) return copyIDs;
19212 copyGraph = history.graph();
19219 context.background = function() { return background; };
19224 context.features = function() { return features; };
19225 context.hasHiddenConnections = function(id) {
19226 var graph = history.graph(),
19227 entity = graph.entity(id);
19228 return features.hasHiddenConnections(entity, graph);
19234 context.map = function() { return map; };
19235 context.layers = function() { return map.layers; };
19236 context.surface = function() { return map.surface; };
19237 context.editable = function() { return map.editable(); };
19239 context.surfaceRect = function() {
19240 // Work around a bug in Firefox.
19241 // http://stackoverflow.com/questions/18153989/
19242 // https://bugzilla.mozilla.org/show_bug.cgi?id=530985
19243 return context.surface().node().parentNode.getBoundingClientRect();
19249 context.presets = function(_) {
19250 if (!arguments.length) return presets;
19252 iD.areaKeys = presets.areaKeys();
19258 context.imagery = function(_) {
19259 background.load(_);
19265 var container, embed;
19266 context.container = function(_) {
19267 if (!arguments.length) return container;
19269 container.classed('id-container', true);
19272 context.embed = function(_) {
19273 if (!arguments.length) return embed;
19281 context.taginfo = function(_) {
19282 if (!arguments.length) return taginfo;
19289 var assetPath = '';
19290 context.assetPath = function(_) {
19291 if (!arguments.length) return assetPath;
19297 context.assetMap = function(_) {
19298 if (!arguments.length) return assetMap;
19303 context.imagePath = function(_) {
19304 var asset = 'img/' + _;
19305 return assetMap[asset] || assetPath + asset;
19311 context.projection = iD.geo.RawMercator();
19313 locale = iD.detect().locale;
19314 if (locale && iD.data.locales.indexOf(locale) === -1) {
19315 locale = locale.split('-')[0];
19318 history = iD.History(context);
19319 context.graph = history.graph;
19320 context.changes = history.changes;
19321 context.intersects = history.intersects;
19323 // Debounce save, since it's a synchronous localStorage write,
19324 // and history changes can happen frequently (e.g. when dragging).
19325 context.debouncedSave = _.debounce(context.save, 350);
19326 function withDebouncedSave(fn) {
19327 return function() {
19328 var result = fn.apply(history, arguments);
19329 context.debouncedSave();
19334 context.perform = withDebouncedSave(history.perform);
19335 context.replace = withDebouncedSave(history.replace);
19336 context.pop = withDebouncedSave(history.pop);
19337 context.overwrite = withDebouncedSave(history.overwrite);
19338 context.undo = withDebouncedSave(history.undo);
19339 context.redo = withDebouncedSave(history.redo);
19341 ui = iD.ui(context);
19343 connection = iD.Connection();
19345 background = iD.Background(context);
19347 features = iD.Features(context);
19349 map = iD.Map(context);
19350 context.mouse = map.mouse;
19351 context.extent = map.extent;
19352 context.pan = map.pan;
19353 context.zoomIn = map.zoomIn;
19354 context.zoomOut = map.zoomOut;
19355 context.zoomInFurther = map.zoomInFurther;
19356 context.zoomOutFurther = map.zoomOutFurther;
19357 context.redrawEnable = map.redrawEnable;
19359 presets = iD.presets();
19361 return d3.rebind(context, dispatch, 'on');
19365 iD.version = '1.9.0';
19370 var ua = navigator.userAgent,
19373 m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
19375 detected.browser = m[1];
19376 detected.version = m[2];
19378 if (!detected.browser) {
19379 m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
19381 detected.browser = 'msie';
19382 detected.version = m[1];
19385 if (!detected.browser) {
19386 m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
19388 detected.browser = 'Opera';
19389 detected.version = m[2];
19392 if (!detected.browser) {
19393 m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
19395 detected.browser = m[1];
19396 detected.version = m[2];
19397 m = ua.match(/version\/([\.\d]+)/i);
19398 if (m !== null) detected.version = m[1];
19401 if (!detected.browser) {
19402 detected.browser = navigator.appName;
19403 detected.version = navigator.appVersion;
19406 // keep major.minor version only..
19407 detected.version = detected.version.split(/\W/).slice(0,2).join('.');
19409 if (detected.browser.toLowerCase() === 'msie') {
19410 detected.ie = true;
19411 detected.browser = 'Internet Explorer';
19412 detected.support = parseFloat(detected.version) >= 11;
19414 detected.ie = false;
19415 detected.support = true;
19418 // Added due to incomplete svg style support. See #715
19419 detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 );
19421 detected.locale = (navigator.languages && navigator.languages.length)
19422 ? navigator.languages[0] : (navigator.language || navigator.userLanguage || 'en-US');
19424 detected.filedrop = (window.FileReader && 'ondrop' in window);
19427 return navigator.userAgent.indexOf(x) !== -1;
19431 detected.os = 'win';
19432 detected.platform = 'Windows';
19434 else if (nav('Mac')) {
19435 detected.os = 'mac';
19436 detected.platform = 'Macintosh';
19438 else if (nav('X11') || nav('Linux')) {
19439 detected.os = 'linux';
19440 detected.platform = 'Linux';
19443 detected.os = 'win';
19444 detected.platform = 'Unknown';
19447 iD.detect = function() { return detected; };
19450 iD.services.mapillary = function() {
19451 var mapillary = {},
19452 dispatch = d3.dispatch('loadedImages', 'loadedSigns'),
19453 apibase = 'https://a.mapillary.com/v2/',
19454 urlImage = 'https://www.mapillary.com/map/im/',
19455 urlThumb = 'https://d1cuyjsrcm0gby.cloudfront.net/',
19456 clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi',
19461 function loadSignStyles(context) {
19462 d3.select('head').selectAll('#traffico')
19466 .attr('id', 'traffico')
19467 .attr('rel', 'stylesheet')
19468 .attr('href', context.assetPath() + 'traffico/stylesheets/traffico.css');
19471 function loadSignDefs(context) {
19472 if (!iD.services.mapillary.sign_defs) {
19473 iD.services.mapillary.sign_defs = {};
19474 _.each(['au', 'br', 'ca', 'de', 'us'], function(region) {
19475 d3.json(context.assetPath() + 'traffico/string-maps/' + region + '-map.json', function(err, data) {
19477 if (region === 'de') region = 'eu';
19478 iD.services.mapillary.sign_defs[region] = data;
19484 function abortRequest(i) {
19488 function getTiles(projection, dimensions) {
19489 var s = projection.scale() * 2 * Math.PI,
19490 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
19491 ts = 256 * Math.pow(2, z - tileZoom),
19493 s / 2 - projection.translate()[0],
19494 s / 2 - projection.translate()[1]];
19496 return d3.geo.tile()
19497 .scaleExtent([tileZoom, tileZoom])
19500 .translate(projection.translate())()
19501 .map(function(tile) {
19502 var x = tile[0] * ts - origin[0],
19503 y = tile[1] * ts - origin[1];
19506 id: tile.toString(),
19507 extent: iD.geo.Extent(
19508 projection.invert([x, y + ts]),
19509 projection.invert([x + ts, y]))
19515 function loadTiles(which, url, projection, dimensions) {
19516 var tiles = getTiles(projection, dimensions);
19518 _.filter(which.inflight, function(v, k) {
19519 var wanted = _.find(tiles, function(tile) { return k === (tile.id + ',0'); });
19520 if (!wanted) delete which.inflight[k];
19522 }).map(abortRequest);
19524 tiles.forEach(function(tile) {
19525 loadTilePage(which, url, tile, 0);
19529 function loadTilePage(which, url, tile, page) {
19530 var cache = iD.services.mapillary.cache[which],
19531 id = tile.id + ',' + String(page),
19532 rect = tile.extent.rectangle();
19534 if (cache.loaded[id] || cache.inflight[id]) return;
19536 cache.inflight[id] = d3.json(url +
19541 client_id: clientId,
19546 }), function(err, data) {
19547 cache.loaded[id] = true;
19548 delete cache.inflight[id];
19549 if (err || !data.features || !data.features.length) return;
19554 for (var i = 0; i < data.features.length; i++) {
19555 feature = data.features[i];
19556 loc = feature.geometry.coordinates;
19557 d = { key: feature.properties.key, loc: loc };
19558 if (which === 'images') d.ca = feature.properties.ca;
19559 if (which === 'signs') d.signs = feature.properties.rects;
19561 features.push([loc[0], loc[1], loc[0], loc[1], d]);
19564 cache.rtree.load(features);
19566 if (which === 'images') dispatch.loadedImages();
19567 if (which === 'signs') dispatch.loadedSigns();
19569 if (data.features.length === maxResults) {
19570 loadTilePage(which, url, tile, ++page);
19576 mapillary.loadImages = function(projection, dimensions) {
19577 var url = apibase + 'search/im/geojson?';
19578 loadTiles('images', url, projection, dimensions);
19581 mapillary.loadSigns = function(context, projection, dimensions) {
19582 var url = apibase + 'search/im/geojson/or?';
19583 loadSignStyles(context);
19584 loadSignDefs(context);
19585 loadTiles('signs', url, projection, dimensions);
19589 // partition viewport into `psize` x `psize` regions
19590 function partitionViewport(psize, projection, dimensions) {
19591 psize = psize || 16;
19592 var cols = d3.range(0, dimensions[0], psize),
19593 rows = d3.range(0, dimensions[1], psize),
19596 rows.forEach(function(y) {
19597 cols.forEach(function(x) {
19598 var min = [x, y + psize],
19599 max = [x + psize, y];
19601 iD.geo.Extent(projection.invert(min), projection.invert(max)));
19608 // no more than `limit` results per partition.
19609 function searchLimited(psize, limit, projection, dimensions, rtree) {
19610 limit = limit || 3;
19612 var partitions = partitionViewport(psize, projection, dimensions);
19613 return _.flatten(_.compact(_.map(partitions, function(extent) {
19614 return rtree.search(extent.rectangle())
19616 .map(function(d) { return d[4]; });
19620 mapillary.images = function(projection, dimensions) {
19621 var psize = 16, limit = 3;
19622 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.images.rtree);
19625 mapillary.signs = function(projection, dimensions) {
19626 var psize = 32, limit = 3;
19627 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.signs.rtree);
19630 mapillary.signsSupported = function() {
19631 var detected = iD.detect();
19632 return (!(detected.ie || detected.browser.toLowerCase() === 'safari'));
19635 mapillary.signHTML = function(d) {
19636 if (!iD.services.mapillary.sign_defs) return;
19638 var detectionPackage = d.signs[0].package,
19639 type = d.signs[0].type,
19640 country = detectionPackage.split('_')[1];
19641 return iD.services.mapillary.sign_defs[country][type];
19644 mapillary.showThumbnail = function(imageKey, position) {
19645 if (!imageKey) return;
19647 var positionClass = {
19648 'ar': (position !== 'left'),
19649 'al': (position === 'left')
19652 var thumbnail = d3.select('#content').selectAll('.mapillary-image')
19656 var enter = thumbnail.enter().append('div')
19657 .attr('class', 'mapillary-image ar');
19659 enter.append('button')
19660 .on('click', function () {
19661 mapillary.hideThumbnail();
19664 .call(iD.svg.Icon('#icon-close'));
19666 enter.append('img');
19669 .attr('class', 'link ar')
19670 .attr('target', '_blank')
19671 .call(iD.svg.Icon('#icon-out-link', 'inline'))
19673 .text(t('mapillary.view_on_mapillary'));
19676 thumbnail.selectAll('img')
19677 .attr('src', urlThumb + imageKey + '/thumb-320.jpg');
19679 var link = thumbnail.selectAll('a')
19680 .attr('href', urlImage + imageKey);
19683 thumbnail.classed(positionClass);
19684 link.classed(positionClass);
19690 .style('opacity', 1);
19693 mapillary.hideThumbnail = function() {
19694 if (iD.services.mapillary) {
19695 iD.services.mapillary.thumb = null;
19697 d3.select('#content').selectAll('.mapillary-image')
19700 .style('opacity', 0)
19704 mapillary.selectedThumbnail = function(d) {
19705 if (!iD.services.mapillary) return null;
19706 if (!arguments.length) return iD.services.mapillary.thumb;
19707 iD.services.mapillary.thumb = d;
19710 mapillary.reset = function() {
19711 var cache = iD.services.mapillary.cache;
19714 _.forEach(cache.images.inflight, abortRequest);
19715 _.forEach(cache.signs.inflight, abortRequest);
19718 iD.services.mapillary.cache = {
19719 images: { inflight: {}, loaded: {}, rtree: rbush() },
19720 signs: { inflight: {}, loaded: {}, rtree: rbush() }
19723 iD.services.mapillary.thumb = null;
19729 if (!iD.services.mapillary.cache) {
19733 return d3.rebind(mapillary, dispatch, 'on');
19735 iD.services.nominatim = function() {
19736 var nominatim = {},
19737 endpoint = 'https://nominatim.openstreetmap.org/reverse?';
19740 nominatim.countryCode = function(location, callback) {
19741 var cache = iD.services.nominatim.cache,
19742 countryCodes = cache.search([location[0], location[1], location[0], location[1]]);
19744 if (countryCodes.length > 0)
19745 return callback(null, countryCodes[0][4]);
19753 }), function(err, result) {
19755 return callback(err);
19756 else if (result && result.error)
19757 return callback(result.error);
19759 var extent = iD.geo.Extent(location).padByMeters(1000);
19761 cache.insert(extent.rectangle().concat(result.address.country_code));
19763 callback(null, result.address.country_code);
19767 nominatim.reset = function() {
19768 iD.services.nominatim.cache = rbush();
19773 if (!iD.services.nominatim.cache) {
19779 iD.services.taginfo = function() {
19781 endpoint = 'https://taginfo.openstreetmap.org/api/4/',
19783 point: 'count_nodes',
19784 vertex: 'count_nodes',
19785 area: 'count_ways',
19796 function sets(parameters, n, o) {
19797 if (parameters.geometry && o[parameters.geometry]) {
19798 parameters[n] = o[parameters.geometry];
19803 function setFilter(parameters) {
19804 return sets(parameters, 'filter', tag_filters);
19807 function setSort(parameters) {
19808 return sets(parameters, 'sortname', tag_sorts);
19811 function clean(parameters) {
19812 return _.omit(parameters, 'geometry', 'debounce');
19815 function popularKeys(parameters) {
19816 var pop_field = 'count_all';
19817 if (parameters.filter) pop_field = 'count_' + parameters.filter;
19818 return function(d) { return parseFloat(d[pop_field]) > 5000 || d.in_wiki; };
19821 function popularValues() {
19822 return function(d) { return parseFloat(d.fraction) > 0.01 || d.in_wiki; };
19825 function valKey(d) { return { value: d.key }; }
19827 function valKeyDescription(d) {
19830 title: d.description
19834 // sort keys with ':' lower than keys without ':'
19835 function sortKeys(a, b) {
19836 return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
19837 : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
19841 var debounced = _.debounce(d3.json, 100, true);
19843 function request(url, debounce, callback) {
19844 var cache = iD.services.taginfo.cache;
19847 callback(null, cache[url]);
19848 } else if (debounce) {
19849 debounced(url, done);
19851 d3.json(url, done);
19854 function done(err, data) {
19855 if (!err) cache[url] = data;
19856 callback(err, data);
19860 taginfo.keys = function(parameters, callback) {
19861 var debounce = parameters.debounce;
19862 parameters = clean(setSort(parameters));
19863 request(endpoint + 'keys/all?' +
19864 iD.util.qsString(_.extend({
19866 sortname: 'count_all',
19869 }, parameters)), debounce, function(err, d) {
19870 if (err) return callback(err);
19871 callback(null, d.data.filter(popularKeys(parameters)).sort(sortKeys).map(valKey));
19875 taginfo.values = function(parameters, callback) {
19876 var debounce = parameters.debounce;
19877 parameters = clean(setSort(setFilter(parameters)));
19878 request(endpoint + 'key/values?' +
19879 iD.util.qsString(_.extend({
19881 sortname: 'count_all',
19884 }, parameters)), debounce, function(err, d) {
19885 if (err) return callback(err);
19886 callback(null, d.data.filter(popularValues()).map(valKeyDescription), parameters);
19890 taginfo.docs = function(parameters, callback) {
19891 var debounce = parameters.debounce;
19892 parameters = clean(setSort(parameters));
19894 var path = 'key/wiki_pages?';
19895 if (parameters.value) path = 'tag/wiki_pages?';
19896 else if (parameters.rtype) path = 'relation/wiki_pages?';
19898 request(endpoint + path + iD.util.qsString(parameters), debounce, function(err, d) {
19899 if (err) return callback(err);
19900 callback(null, d.data);
19904 taginfo.endpoint = function(_) {
19905 if (!arguments.length) return endpoint;
19910 taginfo.reset = function() {
19911 iD.services.taginfo.cache = {};
19916 if (!iD.services.taginfo.cache) {
19922 iD.services.wikipedia = function() {
19924 endpoint = 'https://en.wikipedia.org/w/api.php?';
19926 wiki.search = function(lang, query, callback) {
19927 lang = lang || 'en';
19928 d3.jsonp(endpoint.replace('en', lang) +
19933 srinfo: 'suggestion',
19935 callback: '{callback}',
19937 }), function(data) {
19938 if (!data.query) return;
19939 callback(query, data.query.search.map(function(d) {
19945 wiki.suggestions = function(lang, query, callback) {
19946 lang = lang || 'en';
19947 d3.jsonp(endpoint.replace('en', lang) +
19949 action: 'opensearch',
19953 callback: '{callback}',
19956 callback(d[0], d[1]);
19960 wiki.translations = function(lang, title, callback) {
19961 d3.jsonp(endpoint.replace('en', lang) +
19966 callback: '{callback}',
19970 var list = d.query.pages[Object.keys(d.query.pages)[0]],
19972 if (list && list.langlinks) {
19973 list.langlinks.forEach(function(d) {
19974 translations[d.lang] = d['*'];
19976 callback(translations);
19985 iD.util.tagText = function(entity) {
19986 return d3.entries(entity.tags).map(function(e) {
19987 return e.key + '=' + e.value;
19991 iD.util.entitySelector = function(ids) {
19992 return ids.length ? '.' + ids.join(',.') : 'nothing';
19995 iD.util.entityOrMemberSelector = function(ids, graph) {
19996 var s = iD.util.entitySelector(ids);
19998 ids.forEach(function(id) {
19999 var entity = graph.hasEntity(id);
20000 if (entity && entity.type === 'relation') {
20001 entity.members.forEach(function(member) {
20002 s += ',.' + member.id;
20010 iD.util.displayName = function(entity) {
20011 var localeName = 'name:' + iD.detect().locale.toLowerCase().split('-')[0];
20012 return entity.tags[localeName] || entity.tags.name || entity.tags.ref;
20015 iD.util.displayType = function(id) {
20017 n: t('inspector.node'),
20018 w: t('inspector.way'),
20019 r: t('inspector.relation')
20023 iD.util.stringQs = function(str) {
20024 return str.split('&').reduce(function(obj, pair){
20025 var parts = pair.split('=');
20026 if (parts.length === 2) {
20027 obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
20033 iD.util.qsString = function(obj, noencode) {
20034 function softEncode(s) {
20035 // encode everything except special characters used in certain hash parameters:
20036 // "/" in map states, ":", ",", {" and "}" in background
20037 return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
20039 return Object.keys(obj).sort().map(function(key) {
20040 return encodeURIComponent(key) + '=' + (
20041 noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
20045 iD.util.prefixDOMProperty = function(property) {
20046 var prefixes = ['webkit', 'ms', 'moz', 'o'],
20048 n = prefixes.length,
20054 property = property.substr(0, 1).toUpperCase() + property.substr(1);
20057 if (prefixes[i] + property in s)
20058 return prefixes[i] + property;
20063 iD.util.prefixCSSProperty = function(property) {
20064 var prefixes = ['webkit', 'ms', 'Moz', 'O'],
20066 n = prefixes.length,
20067 s = document.body.style;
20069 if (property.toLowerCase() in s)
20070 return property.toLowerCase();
20073 if (prefixes[i] + property in s)
20074 return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
20080 iD.util.setTransform = function(el, x, y, scale) {
20081 var prop = iD.util.transformProperty = iD.util.transformProperty || iD.util.prefixCSSProperty('Transform'),
20082 translate = iD.detect().opera ?
20083 'translate(' + x + 'px,' + y + 'px)' :
20084 'translate3d(' + x + 'px,' + y + 'px,0)';
20085 return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
20088 iD.util.getStyle = function(selector) {
20089 for (var i = 0; i < document.styleSheets.length; i++) {
20090 var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules || [];
20091 for (var k = 0; k < rules.length; k++) {
20092 var selectorText = rules[k].selectorText && rules[k].selectorText.split(', ');
20093 if (_.contains(selectorText, selector)) {
20100 iD.util.editDistance = function(a, b) {
20101 if (a.length === 0) return b.length;
20102 if (b.length === 0) return a.length;
20104 for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
20105 for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
20106 for (i = 1; i <= b.length; i++) {
20107 for (j = 1; j <= a.length; j++) {
20108 if (b.charAt(i-1) === a.charAt(j-1)) {
20109 matrix[i][j] = matrix[i-1][j-1];
20111 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
20112 Math.min(matrix[i][j-1] + 1, // insertion
20113 matrix[i-1][j] + 1)); // deletion
20117 return matrix[b.length][a.length];
20120 // a d3.mouse-alike which
20121 // 1. Only works on HTML elements, not SVG
20122 // 2. Does not cause style recalculation
20123 iD.util.fastMouse = function(container) {
20124 var rect = container.getBoundingClientRect(),
20125 rectLeft = rect.left,
20126 rectTop = rect.top,
20127 clientLeft = +container.clientLeft,
20128 clientTop = +container.clientTop;
20129 return function(e) {
20131 e.clientX - rectLeft - clientLeft,
20132 e.clientY - rectTop - clientTop];
20136 /* eslint-disable no-proto */
20137 iD.util.getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
20138 /* eslint-enable no-proto */
20140 iD.util.asyncMap = function(inputs, func, callback) {
20141 var remaining = inputs.length,
20145 inputs.forEach(function(d, i) {
20146 func(d, function done(err, data) {
20150 if (!remaining) callback(errors, results);
20155 // wraps an index to an interval [0..length-1]
20156 iD.util.wrap = function(index, length) {
20158 index += Math.ceil(-index/length)*length;
20159 return index % length;
20161 // A per-domain session mutex backed by a cookie and dead man's
20162 // switch. If the session crashes, the mutex will auto-release
20163 // after 5 seconds.
20165 iD.util.SessionMutex = function(name) {
20170 var expires = new Date();
20171 expires.setSeconds(expires.getSeconds() + 5);
20172 document.cookie = name + '=1; expires=' + expires.toUTCString();
20175 mutex.lock = function() {
20176 if (intervalID) return true;
20177 var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
20178 if (cookie) return false;
20180 intervalID = window.setInterval(renew, 4000);
20184 mutex.unlock = function() {
20185 if (!intervalID) return;
20186 document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
20187 clearInterval(intervalID);
20191 mutex.locked = function() {
20192 return !!intervalID;
20197 iD.util.SuggestNames = function(preset, suggestions) {
20198 preset = preset.id.split('/', 2);
20202 return function(value, callback) {
20204 if (value && value.length > 2) {
20205 if (suggestions[k] && suggestions[k][v]) {
20206 for (var sugg in suggestions[k][v]) {
20207 var dist = iD.util.editDistance(value, sugg.substring(0, value.length));
20217 result.sort(function(a, b) {
20218 return a.dist - b.dist;
20221 result = result.slice(0,3);
20227 iD.geo.roundCoords = function(c) {
20228 return [Math.floor(c[0]), Math.floor(c[1])];
20231 iD.geo.interp = function(p1, p2, t) {
20232 return [p1[0] + (p2[0] - p1[0]) * t,
20233 p1[1] + (p2[1] - p1[1]) * t];
20236 // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
20237 // Returns a positive value, if OAB makes a counter-clockwise turn,
20238 // negative for clockwise turn, and zero if the points are collinear.
20239 iD.geo.cross = function(o, a, b) {
20240 return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
20243 // http://jsperf.com/id-dist-optimization
20244 iD.geo.euclideanDistance = function(a, b) {
20245 var x = a[0] - b[0], y = a[1] - b[1];
20246 return Math.sqrt((x * x) + (y * y));
20249 // using WGS84 polar radius (6356752.314245179 m)
20250 // const = 2 * PI * r / 360
20251 iD.geo.latToMeters = function(dLat) {
20252 return dLat * 110946.257617;
20255 // using WGS84 equatorial radius (6378137.0 m)
20256 // const = 2 * PI * r / 360
20257 iD.geo.lonToMeters = function(dLon, atLat) {
20258 return Math.abs(atLat) >= 90 ? 0 :
20259 dLon * 111319.490793 * Math.abs(Math.cos(atLat * (Math.PI/180)));
20262 // using WGS84 polar radius (6356752.314245179 m)
20263 // const = 2 * PI * r / 360
20264 iD.geo.metersToLat = function(m) {
20265 return m / 110946.257617;
20268 // using WGS84 equatorial radius (6378137.0 m)
20269 // const = 2 * PI * r / 360
20270 iD.geo.metersToLon = function(m, atLat) {
20271 return Math.abs(atLat) >= 90 ? 0 :
20272 m / 111319.490793 / Math.abs(Math.cos(atLat * (Math.PI/180)));
20275 // Equirectangular approximation of spherical distances on Earth
20276 iD.geo.sphericalDistance = function(a, b) {
20277 var x = iD.geo.lonToMeters(a[0] - b[0], (a[1] + b[1]) / 2),
20278 y = iD.geo.latToMeters(a[1] - b[1]);
20279 return Math.sqrt((x * x) + (y * y));
20282 iD.geo.edgeEqual = function(a, b) {
20283 return (a[0] === b[0] && a[1] === b[1]) ||
20284 (a[0] === b[1] && a[1] === b[0]);
20287 // Return the counterclockwise angle in the range (-pi, pi)
20288 // between the positive X axis and the line intersecting a and b.
20289 iD.geo.angle = function(a, b, projection) {
20290 a = projection(a.loc);
20291 b = projection(b.loc);
20292 return Math.atan2(b[1] - a[1], b[0] - a[0]);
20295 // Choose the edge with the minimal distance from `point` to its orthogonal
20296 // projection onto that edge, if such a projection exists, or the distance to
20297 // the closest vertex on that edge. Returns an object with the `index` of the
20298 // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
20299 iD.geo.chooseEdge = function(nodes, point, projection) {
20300 var dist = iD.geo.euclideanDistance,
20301 points = nodes.map(function(n) { return projection(n.loc); }),
20305 function dot(p, q) {
20306 return p[0] * q[0] + p[1] * q[1];
20309 for (var i = 0; i < points.length - 1; i++) {
20311 s = [points[i + 1][0] - o[0],
20312 points[i + 1][1] - o[1]],
20313 v = [point[0] - o[0],
20315 proj = dot(v, s) / dot(s, s),
20320 } else if (proj > 1) {
20323 p = [o[0] + proj * s[0], o[1] + proj * s[1]];
20326 var d = dist(p, point);
20330 loc = projection.invert(p);
20341 // Return the intersection point of 2 line segments.
20342 // From https://github.com/pgkelley4/line-segments-intersect
20343 // This uses the vector cross product approach described below:
20344 // http://stackoverflow.com/a/565282/786339
20345 iD.geo.lineIntersection = function(a, b) {
20346 function subtractPoints(point1, point2) {
20347 return [point1[0] - point2[0], point1[1] - point2[1]];
20349 function crossProduct(point1, point2) {
20350 return point1[0] * point2[1] - point1[1] * point2[0];
20353 var p = [a[0][0], a[0][1]],
20354 p2 = [a[1][0], a[1][1]],
20355 q = [b[0][0], b[0][1]],
20356 q2 = [b[1][0], b[1][1]],
20357 r = subtractPoints(p2, p),
20358 s = subtractPoints(q2, q),
20359 uNumerator = crossProduct(subtractPoints(q, p), r),
20360 denominator = crossProduct(r, s);
20362 if (uNumerator && denominator) {
20363 var u = uNumerator / denominator,
20364 t = crossProduct(subtractPoints(q, p), s) / denominator;
20366 if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
20367 return iD.geo.interp(p, p2, t);
20374 iD.geo.pathIntersections = function(path1, path2) {
20375 var intersections = [];
20376 for (var i = 0; i < path1.length - 1; i++) {
20377 for (var j = 0; j < path2.length - 1; j++) {
20378 var a = [ path1[i], path1[i+1] ],
20379 b = [ path2[j], path2[j+1] ],
20380 hit = iD.geo.lineIntersection(a, b);
20381 if (hit) intersections.push(hit);
20384 return intersections;
20387 // Return whether point is contained in polygon.
20389 // `point` should be a 2-item array of coordinates.
20390 // `polygon` should be an array of 2-item arrays of coordinates.
20392 // From https://github.com/substack/point-in-polygon.
20393 // ray-casting algorithm based on
20394 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
20396 iD.geo.pointInPolygon = function(point, polygon) {
20401 for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
20402 var xi = polygon[i][0], yi = polygon[i][1];
20403 var xj = polygon[j][0], yj = polygon[j][1];
20405 var intersect = ((yi > y) !== (yj > y)) &&
20406 (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
20407 if (intersect) inside = !inside;
20413 iD.geo.polygonContainsPolygon = function(outer, inner) {
20414 return _.every(inner, function(point) {
20415 return iD.geo.pointInPolygon(point, outer);
20419 iD.geo.polygonIntersectsPolygon = function(outer, inner, checkSegments) {
20420 function testSegments(outer, inner) {
20421 for (var i = 0; i < outer.length - 1; i++) {
20422 for (var j = 0; j < inner.length - 1; j++) {
20423 var a = [ outer[i], outer[i+1] ],
20424 b = [ inner[j], inner[j+1] ];
20425 if (iD.geo.lineIntersection(a, b)) return true;
20431 function testPoints(outer, inner) {
20432 return _.some(inner, function(point) {
20433 return iD.geo.pointInPolygon(point, outer);
20437 return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
20440 iD.geo.pathLength = function(path) {
20443 for (var i = 0; i < path.length - 1; i++) {
20444 dx = path[i][0] - path[i + 1][0];
20445 dy = path[i][1] - path[i + 1][1];
20446 length += Math.sqrt(dx * dx + dy * dy);
20450 iD.geo.Extent = function geoExtent(min, max) {
20451 if (!(this instanceof iD.geo.Extent)) return new iD.geo.Extent(min, max);
20452 if (min instanceof iD.geo.Extent) {
20454 } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
20458 this[0] = min || [ Infinity, Infinity];
20459 this[1] = max || min || [-Infinity, -Infinity];
20463 iD.geo.Extent.prototype = new Array(2);
20465 _.extend(iD.geo.Extent.prototype, {
20466 equals: function (obj) {
20467 return this[0][0] === obj[0][0] &&
20468 this[0][1] === obj[0][1] &&
20469 this[1][0] === obj[1][0] &&
20470 this[1][1] === obj[1][1];
20473 extend: function(obj) {
20474 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20475 return iD.geo.Extent([Math.min(obj[0][0], this[0][0]),
20476 Math.min(obj[0][1], this[0][1])],
20477 [Math.max(obj[1][0], this[1][0]),
20478 Math.max(obj[1][1], this[1][1])]);
20481 _extend: function(extent) {
20482 this[0][0] = Math.min(extent[0][0], this[0][0]);
20483 this[0][1] = Math.min(extent[0][1], this[0][1]);
20484 this[1][0] = Math.max(extent[1][0], this[1][0]);
20485 this[1][1] = Math.max(extent[1][1], this[1][1]);
20489 return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
20492 center: function() {
20493 return [(this[0][0] + this[1][0]) / 2,
20494 (this[0][1] + this[1][1]) / 2];
20497 rectangle: function() {
20498 return [this[0][0], this[0][1], this[1][0], this[1][1]];
20501 polygon: function() {
20503 [this[0][0], this[0][1]],
20504 [this[0][0], this[1][1]],
20505 [this[1][0], this[1][1]],
20506 [this[1][0], this[0][1]],
20507 [this[0][0], this[0][1]]
20511 contains: function(obj) {
20512 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20513 return obj[0][0] >= this[0][0] &&
20514 obj[0][1] >= this[0][1] &&
20515 obj[1][0] <= this[1][0] &&
20516 obj[1][1] <= this[1][1];
20519 intersects: function(obj) {
20520 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20521 return obj[0][0] <= this[1][0] &&
20522 obj[0][1] <= this[1][1] &&
20523 obj[1][0] >= this[0][0] &&
20524 obj[1][1] >= this[0][1];
20527 intersection: function(obj) {
20528 if (!this.intersects(obj)) return new iD.geo.Extent();
20529 return new iD.geo.Extent([Math.max(obj[0][0], this[0][0]),
20530 Math.max(obj[0][1], this[0][1])],
20531 [Math.min(obj[1][0], this[1][0]),
20532 Math.min(obj[1][1], this[1][1])]);
20535 percentContainedIn: function(obj) {
20536 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20537 var a1 = this.intersection(obj).area(),
20540 if (a1 === Infinity || a2 === Infinity || a1 === 0 || a2 === 0) {
20547 padByMeters: function(meters) {
20548 var dLat = iD.geo.metersToLat(meters),
20549 dLon = iD.geo.metersToLon(meters, this.center()[1]);
20550 return iD.geo.Extent(
20551 [this[0][0] - dLon, this[0][1] - dLat],
20552 [this[1][0] + dLon, this[1][1] + dLat]);
20555 toParam: function() {
20556 return this.rectangle().join(',');
20560 iD.geo.Turn = function(turn) {
20561 if (!(this instanceof iD.geo.Turn))
20562 return new iD.geo.Turn(turn);
20563 _.extend(this, turn);
20566 iD.geo.Intersection = function(graph, vertexId) {
20567 var vertex = graph.entity(vertexId),
20568 parentWays = graph.parentWays(vertex),
20572 function addHighway(way, adjacentNodeId) {
20573 if (highways[adjacentNodeId]) {
20574 coincident.push(adjacentNodeId);
20576 highways[adjacentNodeId] = way;
20580 // Pre-split ways that would need to be split in
20581 // order to add a restriction. The real split will
20582 // happen when the restriction is added.
20583 parentWays.forEach(function(way) {
20584 if (!way.tags.highway || way.isArea() || way.isDegenerate())
20587 var isFirst = (vertexId === way.first()),
20588 isLast = (vertexId === way.last()),
20589 isAffix = (isFirst || isLast),
20590 isClosingNode = (isFirst && isLast);
20592 if (isAffix && !isClosingNode) {
20593 var index = (isFirst ? 1 : way.nodes.length - 2);
20594 addHighway(way, way.nodes[index]);
20597 var splitIndex, wayA, wayB, indexA, indexB;
20598 if (isClosingNode) {
20599 splitIndex = Math.ceil(way.nodes.length / 2); // split at midpoint
20600 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
20601 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
20603 indexB = way.nodes.length - 2;
20605 splitIndex = _.indexOf(way.nodes, vertex.id, 1); // split at vertexid
20606 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
20607 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
20608 indexA = splitIndex - 1;
20609 indexB = splitIndex + 1;
20611 graph = graph.replace(wayA).replace(wayB);
20612 addHighway(wayA, way.nodes[indexA]);
20613 addHighway(wayB, way.nodes[indexB]);
20617 // remove any ways from this intersection that are coincident
20618 // (i.e. any adjacent node used by more than one intersecting way)
20619 coincident.forEach(function (n) {
20620 delete highways[n];
20624 var intersection = {
20625 highways: highways,
20626 ways: _.values(highways),
20630 intersection.adjacentNodeId = function(fromWayId) {
20631 return _.find(_.keys(highways), function(k) {
20632 return highways[k].id === fromWayId;
20636 intersection.turns = function(fromNodeId) {
20637 var start = highways[fromNodeId];
20641 if (start.first() === vertex.id && start.tags.oneway === 'yes')
20643 if (start.last() === vertex.id && start.tags.oneway === '-1')
20646 function withRestriction(turn) {
20647 graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
20648 if (relation.tags.type !== 'restriction')
20651 var f = relation.memberByRole('from'),
20652 t = relation.memberByRole('to'),
20653 v = relation.memberByRole('via');
20655 if (f && f.id === turn.from.way &&
20656 v && v.id === turn.via.node &&
20657 t && t.id === turn.to.way) {
20658 turn.restriction = relation.id;
20659 } else if (/^only_/.test(relation.tags.restriction) &&
20660 f && f.id === turn.from.way &&
20661 v && v.id === turn.via.node &&
20662 t && t.id !== turn.to.way) {
20663 turn.restriction = relation.id;
20664 turn.indirect_restriction = true;
20668 return iD.geo.Turn(turn);
20673 way: start.id.split(/-(a|b)/)[0]
20675 via = { node: vertex.id },
20678 _.each(highways, function(end, adjacentNodeId) {
20683 if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
20684 turns.push(withRestriction({
20688 node: adjacentNodeId,
20689 way: end.id.split(/-(a|b)/)[0]
20695 if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
20696 turns.push(withRestriction({
20700 node: adjacentNodeId,
20701 way: end.id.split(/-(a|b)/)[0]
20709 if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
20710 turns.push(withRestriction({
20721 return intersection;
20725 iD.geo.inferRestriction = function(graph, from, via, to, projection) {
20726 var fromWay = graph.entity(from.way),
20727 fromNode = graph.entity(from.node),
20728 toWay = graph.entity(to.way),
20729 toNode = graph.entity(to.node),
20730 viaNode = graph.entity(via.node),
20731 fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
20732 (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
20733 toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
20734 (toWay.tags.oneway === '-1' && toWay.last() === via.node),
20735 angle = iD.geo.angle(viaNode, fromNode, projection) -
20736 iD.geo.angle(viaNode, toNode, projection);
20738 angle = angle * 180 / Math.PI;
20743 if (fromNode === toNode)
20744 return 'no_u_turn';
20745 if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
20746 return 'no_u_turn';
20748 return 'no_right_turn';
20750 return 'no_left_turn';
20752 return 'no_straight_on';
20754 // For fixing up rendering of multipolygons with tags on the outer member.
20755 // https://github.com/openstreetmap/iD/issues/613
20756 iD.geo.isSimpleMultipolygonOuterMember = function(entity, graph) {
20757 if (entity.type !== 'way')
20760 var parents = graph.parentRelations(entity);
20761 if (parents.length !== 1)
20764 var parent = parents[0];
20765 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
20768 var members = parent.members, member;
20769 for (var i = 0; i < members.length; i++) {
20770 member = members[i];
20771 if (member.id === entity.id && member.role && member.role !== 'outer')
20772 return false; // Not outer member
20773 if (member.id !== entity.id && (!member.role || member.role === 'outer'))
20774 return false; // Not a simple multipolygon
20780 iD.geo.simpleMultipolygonOuterMember = function(entity, graph) {
20781 if (entity.type !== 'way')
20784 var parents = graph.parentRelations(entity);
20785 if (parents.length !== 1)
20788 var parent = parents[0];
20789 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
20792 var members = parent.members, member, outerMember;
20793 for (var i = 0; i < members.length; i++) {
20794 member = members[i];
20795 if (!member.role || member.role === 'outer') {
20797 return false; // Not a simple multipolygon
20798 outerMember = member;
20802 return outerMember && graph.hasEntity(outerMember.id);
20805 // Join `array` into sequences of connecting ways.
20807 // Segments which share identical start/end nodes will, as much as possible,
20808 // be connected with each other.
20810 // The return value is a nested array. Each constituent array contains elements
20811 // of `array` which have been determined to connect. Each consitituent array
20812 // also has a `nodes` property whose value is an ordered array of member nodes,
20813 // with appropriate order reversal and start/end coordinate de-duplication.
20815 // Members of `array` must have, at minimum, `type` and `id` properties.
20816 // Thus either an array of `iD.Way`s or a relation member array may be
20819 // If an member has a `tags` property, its tags will be reversed via
20820 // `iD.actions.Reverse` in the output.
20822 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
20823 // false) and non-way members are ignored.
20825 iD.geo.joinWays = function(array, graph) {
20826 var joined = [], member, current, nodes, first, last, i, how, what;
20828 array = array.filter(function(member) {
20829 return member.type === 'way' && graph.hasEntity(member.id);
20832 function resolve(member) {
20833 return graph.childNodes(graph.entity(member.id));
20836 function reverse(member) {
20837 return member.tags ? iD.actions.Reverse(member.id, {reverseOneway: true})(graph).entity(member.id) : member;
20840 while (array.length) {
20841 member = array.shift();
20842 current = [member];
20843 current.nodes = nodes = resolve(member).slice();
20844 joined.push(current);
20846 while (array.length && _.first(nodes) !== _.last(nodes)) {
20847 first = _.first(nodes);
20848 last = _.last(nodes);
20850 for (i = 0; i < array.length; i++) {
20852 what = resolve(member);
20854 if (last === _.first(what)) {
20856 what = what.slice(1);
20858 } else if (last === _.last(what)) {
20860 what = what.slice(0, -1).reverse();
20861 member = reverse(member);
20863 } else if (first === _.last(what)) {
20864 how = nodes.unshift;
20865 what = what.slice(0, -1);
20867 } else if (first === _.first(what)) {
20868 how = nodes.unshift;
20869 what = what.slice(1).reverse();
20870 member = reverse(member);
20878 break; // No more joinable ways.
20880 how.apply(current, [member]);
20881 how.apply(nodes, what);
20883 array.splice(i, 1);
20890 Bypasses features of D3's default projection stream pipeline that are unnecessary:
20891 * Antimeridian clipping
20892 * Spherical rotation
20895 iD.geo.RawMercator = function () {
20896 var project = d3.geo.mercator.raw,
20897 k = 512 / Math.PI, // scale
20898 x = 0, y = 0, // translate
20899 clipExtent = [[0, 0], [0, 0]];
20901 function projection(point) {
20902 point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
20903 return [point[0] * k + x, y - point[1] * k];
20906 projection.invert = function(point) {
20907 point = project.invert((point[0] - x) / k, (y - point[1]) / k);
20908 return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
20911 projection.scale = function(_) {
20912 if (!arguments.length) return k;
20917 projection.translate = function(_) {
20918 if (!arguments.length) return [x, y];
20924 projection.clipExtent = function(_) {
20925 if (!arguments.length) return clipExtent;
20930 projection.stream = d3.geo.transform({
20931 point: function(x, y) {
20932 x = projection([x, y]);
20933 this.stream.point(x[0], x[1]);
20940 iD.actions.AddEntity = function(way) {
20941 return function(graph) {
20942 return graph.replace(way);
20945 iD.actions.AddMember = function(relationId, member, memberIndex) {
20946 return function(graph) {
20947 var relation = graph.entity(relationId);
20949 if (isNaN(memberIndex) && member.type === 'way') {
20950 var members = relation.indexedMembers();
20951 members.push(member);
20953 var joined = iD.geo.joinWays(members, graph);
20954 for (var i = 0; i < joined.length; i++) {
20955 var segment = joined[i];
20956 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
20957 if (segment[j] !== member)
20961 memberIndex = segment[j + 1].index;
20962 } else if (j === segment.length - 1) {
20963 memberIndex = segment[j - 1].index + 1;
20965 memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
20971 return graph.replace(relation.addMember(member, memberIndex));
20974 iD.actions.AddMidpoint = function(midpoint, node) {
20975 return function(graph) {
20976 graph = graph.replace(node.move(midpoint.loc));
20978 var parents = _.intersection(
20979 graph.parentWays(graph.entity(midpoint.edge[0])),
20980 graph.parentWays(graph.entity(midpoint.edge[1])));
20982 parents.forEach(function(way) {
20983 for (var i = 0; i < way.nodes.length - 1; i++) {
20984 if (iD.geo.edgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
20985 graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
20987 // Add only one midpoint on doubled-back segments,
20988 // turning them into self-intersections.
20997 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
20998 iD.actions.AddVertex = function(wayId, nodeId, index) {
20999 return function(graph) {
21000 return graph.replace(graph.entity(wayId).addNode(nodeId, index));
21003 iD.actions.ChangeMember = function(relationId, member, memberIndex) {
21004 return function(graph) {
21005 return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
21008 iD.actions.ChangePreset = function(entityId, oldPreset, newPreset) {
21009 return function(graph) {
21010 var entity = graph.entity(entityId),
21011 geometry = entity.geometry(graph),
21012 tags = entity.tags;
21014 if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
21015 if (newPreset) tags = newPreset.applyTags(tags, geometry);
21017 return graph.replace(entity.update({tags: tags}));
21020 iD.actions.ChangeTags = function(entityId, tags) {
21021 return function(graph) {
21022 var entity = graph.entity(entityId);
21023 return graph.replace(entity.update({tags: tags}));
21026 iD.actions.Circularize = function(wayId, projection, maxAngle) {
21027 maxAngle = (maxAngle || 20) * Math.PI / 180;
21029 var action = function(graph) {
21030 var way = graph.entity(wayId);
21032 if (!way.isConvex(graph)) {
21033 graph = action.makeConvex(graph);
21036 var nodes = _.uniq(graph.childNodes(way)),
21037 keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
21038 points = nodes.map(function(n) { return projection(n.loc); }),
21039 keyPoints = keyNodes.map(function(n) { return projection(n.loc); }),
21040 centroid = (points.length === 2) ? iD.geo.interp(points[0], points[1], 0.5) : d3.geom.polygon(points).centroid(),
21041 radius = d3.median(points, function(p) { return iD.geo.euclideanDistance(centroid, p); }),
21042 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
21045 // we need atleast two key nodes for the algorithm to work
21046 if (!keyNodes.length) {
21047 keyNodes = [nodes[0]];
21048 keyPoints = [points[0]];
21051 if (keyNodes.length === 1) {
21052 var index = nodes.indexOf(keyNodes[0]),
21053 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
21055 keyNodes.push(nodes[oppositeIndex]);
21056 keyPoints.push(points[oppositeIndex]);
21059 // key points and nodes are those connected to the ways,
21060 // they are projected onto the circle, inbetween nodes are moved
21061 // to constant intervals between key nodes, extra inbetween nodes are
21062 // added if necessary.
21063 for (var i = 0; i < keyPoints.length; i++) {
21064 var nextKeyNodeIndex = (i + 1) % keyNodes.length,
21065 startNode = keyNodes[i],
21066 endNode = keyNodes[nextKeyNodeIndex],
21067 startNodeIndex = nodes.indexOf(startNode),
21068 endNodeIndex = nodes.indexOf(endNode),
21069 numberNewPoints = -1,
21070 indexRange = endNodeIndex - startNodeIndex,
21071 distance, totalAngle, eachAngle, startAngle, endAngle,
21072 angle, loc, node, j,
21073 inBetweenNodes = [];
21075 if (indexRange < 0) {
21076 indexRange += nodes.length;
21079 // position this key node
21080 distance = iD.geo.euclideanDistance(centroid, keyPoints[i]);
21081 if (distance === 0) { distance = 1e-4; }
21083 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius,
21084 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
21085 graph = graph.replace(keyNodes[i].move(projection.invert(keyPoints[i])));
21087 // figure out the between delta angle we want to match to
21088 startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
21089 endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
21090 totalAngle = endAngle - startAngle;
21092 // detects looping around -pi/pi
21093 if (totalAngle * sign > 0) {
21094 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
21099 eachAngle = totalAngle / (indexRange + numberNewPoints);
21100 } while (Math.abs(eachAngle) > maxAngle);
21102 // move existing points
21103 for (j = 1; j < indexRange; j++) {
21104 angle = startAngle + j * eachAngle;
21105 loc = projection.invert([
21106 centroid[0] + Math.cos(angle)*radius,
21107 centroid[1] + Math.sin(angle)*radius]);
21109 node = nodes[(j + startNodeIndex) % nodes.length].move(loc);
21110 graph = graph.replace(node);
21113 // add new inbetween nodes if necessary
21114 for (j = 0; j < numberNewPoints; j++) {
21115 angle = startAngle + (indexRange + j) * eachAngle;
21116 loc = projection.invert([
21117 centroid[0] + Math.cos(angle) * radius,
21118 centroid[1] + Math.sin(angle) * radius]);
21120 node = iD.Node({loc: loc});
21121 graph = graph.replace(node);
21123 nodes.splice(endNodeIndex + j, 0, node);
21124 inBetweenNodes.push(node.id);
21127 // Check for other ways that share these keyNodes..
21128 // If keyNodes are adjacent in both ways,
21129 // we can add inBetween nodes to that shared way too..
21130 if (indexRange === 1 && inBetweenNodes.length) {
21131 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
21132 endIndex1 = way.nodes.lastIndexOf(endNode.id),
21133 wayDirection1 = (endIndex1 - startIndex1);
21134 if (wayDirection1 < -1) { wayDirection1 = 1; }
21136 /* eslint-disable no-loop-func */
21137 _.each(_.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
21138 if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
21139 var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
21140 endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
21141 wayDirection2 = (endIndex2 - startIndex2),
21142 insertAt = endIndex2;
21143 if (wayDirection2 < -1) { wayDirection2 = 1; }
21145 if (wayDirection1 !== wayDirection2) {
21146 inBetweenNodes.reverse();
21147 insertAt = startIndex2;
21149 for (j = 0; j < inBetweenNodes.length; j++) {
21150 sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
21152 graph = graph.replace(sharedWay);
21155 /* eslint-enable no-loop-func */
21160 // update the way to have all the new nodes
21161 ids = nodes.map(function(n) { return n.id; });
21164 way = way.update({nodes: ids});
21165 graph = graph.replace(way);
21170 action.makeConvex = function(graph) {
21171 var way = graph.entity(wayId),
21172 nodes = _.uniq(graph.childNodes(way)),
21173 points = nodes.map(function(n) { return projection(n.loc); }),
21174 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
21175 hull = d3.geom.hull(points);
21177 // D3 convex hulls go counterclockwise..
21183 for (var i = 0; i < hull.length - 1; i++) {
21184 var startIndex = points.indexOf(hull[i]),
21185 endIndex = points.indexOf(hull[i+1]),
21186 indexRange = (endIndex - startIndex);
21188 if (indexRange < 0) {
21189 indexRange += nodes.length;
21192 // move interior nodes to the surface of the convex hull..
21193 for (var j = 1; j < indexRange; j++) {
21194 var point = iD.geo.interp(hull[i], hull[i+1], j / indexRange),
21195 node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
21196 graph = graph.replace(node);
21202 action.disabled = function(graph) {
21203 if (!graph.entity(wayId).isClosed())
21204 return 'not_closed';
21209 // Connect the ways at the given nodes.
21211 // The last node will survive. All other nodes will be replaced with
21212 // the surviving node in parent ways, and then removed.
21214 // Tags and relation memberships of of non-surviving nodes are merged
21215 // to the survivor.
21217 // This is the inverse of `iD.actions.Disconnect`.
21220 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
21221 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
21223 iD.actions.Connect = function(nodeIds) {
21224 return function(graph) {
21225 var survivor = graph.entity(_.last(nodeIds));
21227 for (var i = 0; i < nodeIds.length - 1; i++) {
21228 var node = graph.entity(nodeIds[i]);
21230 /* eslint-disable no-loop-func */
21231 graph.parentWays(node).forEach(function(parent) {
21232 if (!parent.areAdjacent(node.id, survivor.id)) {
21233 graph = graph.replace(parent.replaceNode(node.id, survivor.id));
21237 graph.parentRelations(node).forEach(function(parent) {
21238 graph = graph.replace(parent.replaceMember(node, survivor));
21240 /* eslint-enable no-loop-func */
21242 survivor = survivor.mergeTags(node.tags);
21243 graph = iD.actions.DeleteNode(node.id)(graph);
21246 graph = graph.replace(survivor);
21251 iD.actions.CopyEntities = function(ids, fromGraph) {
21254 var action = function(graph) {
21255 ids.forEach(function(id) {
21256 fromGraph.entity(id).copy(fromGraph, copies);
21259 for (var id in copies) {
21260 graph = graph.replace(copies[id]);
21266 action.copies = function() {
21272 iD.actions.DeleteMember = function(relationId, memberIndex) {
21273 return function(graph) {
21274 var relation = graph.entity(relationId)
21275 .removeMember(memberIndex);
21277 graph = graph.replace(relation);
21279 if (relation.isDegenerate())
21280 graph = iD.actions.DeleteRelation(relation.id)(graph);
21285 iD.actions.DeleteMultiple = function(ids) {
21287 way: iD.actions.DeleteWay,
21288 node: iD.actions.DeleteNode,
21289 relation: iD.actions.DeleteRelation
21292 var action = function(graph) {
21293 ids.forEach(function(id) {
21294 if (graph.hasEntity(id)) { // It may have been deleted aready.
21295 graph = actions[graph.entity(id).type](id)(graph);
21302 action.disabled = function(graph) {
21303 for (var i = 0; i < ids.length; i++) {
21305 disabled = actions[graph.entity(id).type](id).disabled(graph);
21306 if (disabled) return disabled;
21312 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
21313 iD.actions.DeleteNode = function(nodeId) {
21314 var action = function(graph) {
21315 var node = graph.entity(nodeId);
21317 graph.parentWays(node)
21318 .forEach(function(parent) {
21319 parent = parent.removeNode(nodeId);
21320 graph = graph.replace(parent);
21322 if (parent.isDegenerate()) {
21323 graph = iD.actions.DeleteWay(parent.id)(graph);
21327 graph.parentRelations(node)
21328 .forEach(function(parent) {
21329 parent = parent.removeMembersWithID(nodeId);
21330 graph = graph.replace(parent);
21332 if (parent.isDegenerate()) {
21333 graph = iD.actions.DeleteRelation(parent.id)(graph);
21337 return graph.remove(node);
21340 action.disabled = function() {
21346 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
21347 iD.actions.DeleteRelation = function(relationId) {
21348 function deleteEntity(entity, graph) {
21349 return !graph.parentWays(entity).length &&
21350 !graph.parentRelations(entity).length &&
21351 !entity.hasInterestingTags();
21354 var action = function(graph) {
21355 var relation = graph.entity(relationId);
21357 graph.parentRelations(relation)
21358 .forEach(function(parent) {
21359 parent = parent.removeMembersWithID(relationId);
21360 graph = graph.replace(parent);
21362 if (parent.isDegenerate()) {
21363 graph = iD.actions.DeleteRelation(parent.id)(graph);
21367 _.uniq(_.pluck(relation.members, 'id')).forEach(function(memberId) {
21368 graph = graph.replace(relation.removeMembersWithID(memberId));
21370 var entity = graph.entity(memberId);
21371 if (deleteEntity(entity, graph)) {
21372 graph = iD.actions.DeleteMultiple([memberId])(graph);
21376 return graph.remove(relation);
21379 action.disabled = function(graph) {
21380 if (!graph.entity(relationId).isComplete(graph))
21381 return 'incomplete_relation';
21386 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
21387 iD.actions.DeleteWay = function(wayId) {
21388 function deleteNode(node, graph) {
21389 return !graph.parentWays(node).length &&
21390 !graph.parentRelations(node).length &&
21391 !node.hasInterestingTags();
21394 var action = function(graph) {
21395 var way = graph.entity(wayId);
21397 graph.parentRelations(way)
21398 .forEach(function(parent) {
21399 parent = parent.removeMembersWithID(wayId);
21400 graph = graph.replace(parent);
21402 if (parent.isDegenerate()) {
21403 graph = iD.actions.DeleteRelation(parent.id)(graph);
21407 _.uniq(way.nodes).forEach(function(nodeId) {
21408 graph = graph.replace(way.removeNode(nodeId));
21410 var node = graph.entity(nodeId);
21411 if (deleteNode(node, graph)) {
21412 graph = graph.remove(node);
21416 return graph.remove(way);
21419 action.disabled = function(graph) {
21420 var disabled = false;
21422 graph.parentRelations(graph.entity(wayId)).forEach(function(parent) {
21423 var type = parent.tags.type,
21424 role = parent.memberById(wayId).role || 'outer';
21425 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
21426 disabled = 'part_of_relation';
21435 iD.actions.DeprecateTags = function(entityId) {
21436 return function(graph) {
21437 var entity = graph.entity(entityId),
21438 newtags = _.clone(entity.tags),
21442 // This handles deprecated tags with a single condition
21443 for (var i = 0; i < iD.data.deprecated.length; i++) {
21445 rule = iD.data.deprecated[i];
21446 var match = _.pairs(rule.old)[0],
21447 replacements = rule.replace ? _.pairs(rule.replace) : null;
21449 if (entity.tags[match[0]] && match[1] === '*') {
21451 var value = entity.tags[match[0]];
21452 if (replacements && !newtags[replacements[0][0]]) {
21453 newtags[replacements[0][0]] = value;
21455 delete newtags[match[0]];
21458 } else if (entity.tags[match[0]] === match[1]) {
21459 newtags = _.assign({}, rule.replace || {}, _.omit(newtags, match[0]));
21465 return graph.replace(entity.update({tags: newtags}));
21471 iD.actions.DiscardTags = function(difference) {
21472 return function(graph) {
21473 function discardTags(entity) {
21474 if (!_.isEmpty(entity.tags)) {
21476 _.each(entity.tags, function(v, k) {
21477 if (v) tags[k] = v;
21480 graph = graph.replace(entity.update({
21481 tags: _.omit(tags, iD.data.discarded)
21486 difference.modified().forEach(discardTags);
21487 difference.created().forEach(discardTags);
21492 // Disconect the ways at the given node.
21494 // Optionally, disconnect only the given ways.
21496 // For testing convenience, accepts an ID to assign to the (first) new node.
21497 // Normally, this will be undefined and the way will automatically
21498 // be assigned a new ID.
21500 // This is the inverse of `iD.actions.Connect`.
21503 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
21504 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
21506 iD.actions.Disconnect = function(nodeId, newNodeId) {
21509 var action = function(graph) {
21510 var node = graph.entity(nodeId),
21511 connections = action.connections(graph);
21513 connections.forEach(function(connection) {
21514 var way = graph.entity(connection.wayID),
21515 newNode = iD.Node({id: newNodeId, loc: node.loc, tags: node.tags});
21517 graph = graph.replace(newNode);
21518 if (connection.index === 0 && way.isArea()) {
21519 // replace shared node with shared node..
21520 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
21522 // replace shared node with multiple new nodes..
21523 graph = graph.replace(way.updateNode(newNode.id, connection.index));
21530 action.connections = function(graph) {
21531 var candidates = [],
21533 parentWays = graph.parentWays(graph.entity(nodeId));
21535 parentWays.forEach(function(way) {
21536 if (wayIds && wayIds.indexOf(way.id) === -1) {
21540 if (way.isArea() && (way.nodes[0] === nodeId)) {
21541 candidates.push({wayID: way.id, index: 0});
21543 way.nodes.forEach(function(waynode, index) {
21544 if (waynode === nodeId) {
21545 candidates.push({wayID: way.id, index: index});
21551 return keeping ? candidates : candidates.slice(1);
21554 action.disabled = function(graph) {
21555 var connections = action.connections(graph);
21556 if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
21557 return 'not_connected';
21559 var parentWays = graph.parentWays(graph.entity(nodeId)),
21560 seenRelationIds = {},
21563 parentWays.forEach(function(way) {
21564 if (wayIds && wayIds.indexOf(way.id) === -1)
21567 var relations = graph.parentRelations(way);
21568 relations.forEach(function(relation) {
21569 if (relation.id in seenRelationIds) {
21570 sharedRelation = relation;
21572 seenRelationIds[relation.id] = true;
21577 if (sharedRelation)
21581 action.limitWays = function(_) {
21582 if (!arguments.length) return wayIds;
21589 // Join ways at the end node they share.
21591 // This is the inverse of `iD.actions.Split`.
21594 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
21595 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
21597 iD.actions.Join = function(ids) {
21599 function groupEntitiesByGeometry(graph) {
21600 var entities = ids.map(function(id) { return graph.entity(id); });
21601 return _.extend({line: []}, _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
21604 var action = function(graph) {
21605 var ways = ids.map(graph.entity, graph),
21606 survivor = ways[0];
21608 // Prefer to keep an existing way.
21609 for (var i = 0; i < ways.length; i++) {
21610 if (!ways[i].isNew()) {
21611 survivor = ways[i];
21616 var joined = iD.geo.joinWays(ways, graph)[0];
21618 survivor = survivor.update({nodes: _.pluck(joined.nodes, 'id')});
21619 graph = graph.replace(survivor);
21621 joined.forEach(function(way) {
21622 if (way.id === survivor.id)
21625 graph.parentRelations(way).forEach(function(parent) {
21626 graph = graph.replace(parent.replaceMember(way, survivor));
21629 survivor = survivor.mergeTags(way.tags);
21631 graph = graph.replace(survivor);
21632 graph = iD.actions.DeleteWay(way.id)(graph);
21638 action.disabled = function(graph) {
21639 var geometries = groupEntitiesByGeometry(graph);
21640 if (ids.length < 2 || ids.length !== geometries.line.length)
21641 return 'not_eligible';
21643 var joined = iD.geo.joinWays(ids.map(graph.entity, graph), graph);
21644 if (joined.length > 1)
21645 return 'not_adjacent';
21647 var nodeIds = _.pluck(joined[0].nodes, 'id').slice(1, -1),
21650 conflicting = false;
21652 joined[0].forEach(function(way) {
21653 var parents = graph.parentRelations(way);
21654 parents.forEach(function(parent) {
21655 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
21659 for (var k in way.tags) {
21660 if (!(k in tags)) {
21661 tags[k] = way.tags[k];
21662 } else if (tags[k] && iD.interestingTag(k) && tags[k] !== way.tags[k]) {
21663 conflicting = true;
21669 return 'restriction';
21672 return 'conflicting_tags';
21677 iD.actions.Merge = function(ids) {
21678 function groupEntitiesByGeometry(graph) {
21679 var entities = ids.map(function(id) { return graph.entity(id); });
21680 return _.extend({point: [], area: [], line: [], relation: []},
21681 _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
21684 var action = function(graph) {
21685 var geometries = groupEntitiesByGeometry(graph),
21686 target = geometries.area[0] || geometries.line[0],
21687 points = geometries.point;
21689 points.forEach(function(point) {
21690 target = target.mergeTags(point.tags);
21692 graph.parentRelations(point).forEach(function(parent) {
21693 graph = graph.replace(parent.replaceMember(point, target));
21696 graph = graph.remove(point);
21699 graph = graph.replace(target);
21704 action.disabled = function(graph) {
21705 var geometries = groupEntitiesByGeometry(graph);
21706 if (geometries.point.length === 0 ||
21707 (geometries.area.length + geometries.line.length) !== 1 ||
21708 geometries.relation.length !== 0)
21709 return 'not_eligible';
21714 iD.actions.MergePolygon = function(ids, newRelationId) {
21716 function groupEntities(graph) {
21717 var entities = ids.map(function (id) { return graph.entity(id); });
21722 }, _.groupBy(entities, function(entity) {
21723 if (entity.type === 'way' && entity.isClosed()) {
21724 return 'closedWay';
21725 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
21726 return 'multipolygon';
21733 var action = function(graph) {
21734 var entities = groupEntities(graph);
21736 // An array representing all the polygons that are part of the multipolygon.
21738 // Each element is itself an array of objects with an id property, and has a
21739 // locs property which is an array of the locations forming the polygon.
21740 var polygons = entities.multipolygon.reduce(function(polygons, m) {
21741 return polygons.concat(iD.geo.joinWays(m.members, graph));
21742 }, []).concat(entities.closedWay.map(function(d) {
21743 var member = [{id: d.id}];
21744 member.nodes = graph.childNodes(d);
21748 // contained is an array of arrays of boolean values,
21749 // where contained[j][k] is true iff the jth way is
21750 // contained by the kth way.
21751 var contained = polygons.map(function(w, i) {
21752 return polygons.map(function(d, n) {
21753 if (i === n) return null;
21754 return iD.geo.polygonContainsPolygon(
21755 _.pluck(d.nodes, 'loc'),
21756 _.pluck(w.nodes, 'loc'));
21760 // Sort all polygons as either outer or inner ways
21764 while (polygons.length) {
21765 extractUncontained(polygons);
21766 polygons = polygons.filter(isContained);
21767 contained = contained.filter(isContained).map(filterContained);
21770 function isContained(d, i) {
21771 return _.any(contained[i]);
21774 function filterContained(d) {
21775 return d.filter(isContained);
21778 function extractUncontained(polygons) {
21779 polygons.forEach(function(d, i) {
21780 if (!isContained(d, i)) {
21781 d.forEach(function(member) {
21785 role: outer ? 'outer' : 'inner'
21793 // Move all tags to one relation
21794 var relation = entities.multipolygon[0] ||
21795 iD.Relation({ id: newRelationId, tags: { type: 'multipolygon' }});
21797 entities.multipolygon.slice(1).forEach(function(m) {
21798 relation = relation.mergeTags(m.tags);
21799 graph = graph.remove(m);
21802 entities.closedWay.forEach(function(way) {
21803 function isThisOuter(m) {
21804 return m.id === way.id && m.role !== 'inner';
21806 if (members.some(isThisOuter)) {
21807 relation = relation.mergeTags(way.tags);
21808 graph = graph.replace(way.update({ tags: {} }));
21812 return graph.replace(relation.update({
21814 tags: _.omit(relation.tags, 'area')
21818 action.disabled = function(graph) {
21819 var entities = groupEntities(graph);
21820 if (entities.other.length > 0 ||
21821 entities.closedWay.length + entities.multipolygon.length < 2)
21822 return 'not_eligible';
21823 if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
21824 return 'incomplete_relation';
21829 iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser) {
21830 var option = 'safe', // 'safe', 'force_local', 'force_remote'
21834 return _.isFunction(formatUser) ? formatUser(d) : d;
21838 function mergeLocation(remote, target) {
21839 function pointEqual(a, b) {
21840 var epsilon = 1e-6;
21841 return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
21844 if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
21847 if (option === 'force_remote') {
21848 return target.update({loc: remote.loc});
21851 conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
21856 function mergeNodes(base, remote, target) {
21857 if (option === 'force_local' || _.isEqual(target.nodes, remote.nodes)) {
21860 if (option === 'force_remote') {
21861 return target.update({nodes: remote.nodes});
21864 var ccount = conflicts.length,
21865 o = base.nodes || [],
21866 a = target.nodes || [],
21867 b = remote.nodes || [],
21869 hunks = Diff3.diff3_merge(a, o, b, true);
21871 for (var i = 0; i < hunks.length; i++) {
21872 var hunk = hunks[i];
21874 nodes.push.apply(nodes, hunk.ok);
21876 // for all conflicts, we can assume c.a !== c.b
21877 // because `diff3_merge` called with `true` option to exclude false conflicts..
21878 var c = hunk.conflict;
21879 if (_.isEqual(c.o, c.a)) { // only changed remotely
21880 nodes.push.apply(nodes, c.b);
21881 } else if (_.isEqual(c.o, c.b)) { // only changed locally
21882 nodes.push.apply(nodes, c.a);
21883 } else { // changed both locally and remotely
21884 conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
21890 return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
21894 function mergeChildren(targetWay, children, updates, graph) {
21895 function isUsed(node, targetWay) {
21896 var parentWays = _.pluck(graph.parentWays(node), 'id');
21897 return node.hasInterestingTags() ||
21898 _.without(parentWays, targetWay.id).length > 0 ||
21899 graph.parentRelations(node).length > 0;
21902 var ccount = conflicts.length;
21904 for (var i = 0; i < children.length; i++) {
21905 var id = children[i],
21906 node = graph.hasEntity(id);
21908 // remove unused childNodes..
21909 if (targetWay.nodes.indexOf(id) === -1) {
21910 if (node && !isUsed(node, targetWay)) {
21911 updates.removeIds.push(id);
21916 // restore used childNodes..
21917 var local = localGraph.hasEntity(id),
21918 remote = remoteGraph.hasEntity(id),
21921 if (option === 'force_remote' && remote && remote.visible) {
21922 updates.replacements.push(remote);
21924 } else if (option === 'force_local' && local) {
21925 target = iD.Entity(local);
21927 target = target.update({ version: remote.version });
21929 updates.replacements.push(target);
21931 } else if (option === 'safe' && local && remote && local.version !== remote.version) {
21932 target = iD.Entity(local, { version: remote.version });
21933 if (remote.visible) {
21934 target = mergeLocation(remote, target);
21936 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
21939 if (conflicts.length !== ccount) break;
21940 updates.replacements.push(target);
21948 function updateChildren(updates, graph) {
21949 for (var i = 0; i < updates.replacements.length; i++) {
21950 graph = graph.replace(updates.replacements[i]);
21952 if (updates.removeIds.length) {
21953 graph = iD.actions.DeleteMultiple(updates.removeIds)(graph);
21959 function mergeMembers(remote, target) {
21960 if (option === 'force_local' || _.isEqual(target.members, remote.members)) {
21963 if (option === 'force_remote') {
21964 return target.update({members: remote.members});
21967 conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
21972 function mergeTags(base, remote, target) {
21973 function ignoreKey(k) {
21974 return _.contains(iD.data.discarded, k);
21977 if (option === 'force_local' || _.isEqual(target.tags, remote.tags)) {
21980 if (option === 'force_remote') {
21981 return target.update({tags: remote.tags});
21984 var ccount = conflicts.length,
21985 o = base.tags || {},
21986 a = target.tags || {},
21987 b = remote.tags || {},
21988 keys = _.reject(_.union(_.keys(o), _.keys(a), _.keys(b)), ignoreKey),
21992 for (var i = 0; i < keys.length; i++) {
21995 if (o[k] !== b[k] && a[k] !== b[k]) { // changed remotely..
21996 if (o[k] !== a[k]) { // changed locally..
21997 conflicts.push(t('merge_remote_changes.conflict.tags',
21998 { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
22000 } else { // unchanged locally, accept remote change..
22001 if (b.hasOwnProperty(k)) {
22011 return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
22015 // `graph.base()` is the common ancestor of the two graphs.
22016 // `localGraph` contains user's edits up to saving
22017 // `remoteGraph` contains remote edits to modified nodes
22018 // `graph` must be a descendent of `localGraph` and may include
22019 // some conflict resolution actions performed on it.
22021 // --- ... --- `localGraph` -- ... -- `graph`
22023 // `graph.base()` --- ... --- `remoteGraph`
22025 var action = function(graph) {
22026 var updates = { replacements: [], removeIds: [] },
22027 base = graph.base().entities[id],
22028 local = localGraph.entity(id),
22029 remote = remoteGraph.entity(id),
22030 target = iD.Entity(local, { version: remote.version });
22033 if (!remote.visible) {
22034 if (option === 'force_remote') {
22035 return iD.actions.DeleteMultiple([id])(graph);
22037 } else if (option === 'force_local') {
22038 if (target.type === 'way') {
22039 target = mergeChildren(target, _.uniq(local.nodes), updates, graph);
22040 graph = updateChildren(updates, graph);
22042 return graph.replace(target);
22045 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
22046 return graph; // do nothing
22051 if (target.type === 'node') {
22052 target = mergeLocation(remote, target);
22054 } else if (target.type === 'way') {
22055 // pull in any child nodes that may not be present locally..
22056 graph.rebase(remoteGraph.childNodes(remote), [graph], false);
22057 target = mergeNodes(base, remote, target);
22058 target = mergeChildren(target, _.union(local.nodes, remote.nodes), updates, graph);
22060 } else if (target.type === 'relation') {
22061 target = mergeMembers(remote, target);
22064 target = mergeTags(base, remote, target);
22066 if (!conflicts.length) {
22067 graph = updateChildren(updates, graph).replace(target);
22073 action.withOption = function(opt) {
22078 action.conflicts = function() {
22084 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
22085 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
22086 iD.actions.Move = function(moveIds, tryDelta, projection, cache) {
22087 var delta = tryDelta;
22089 function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
22090 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
22092 function setupCache(graph) {
22093 function canMove(nodeId) {
22094 var parents = _.pluck(graph.parentWays(graph.entity(nodeId)), 'id');
22095 if (parents.length < 3) return true;
22097 // Don't move a vertex where >2 ways meet, unless all parentWays are moving too..
22098 var parentsMoving = _.all(parents, function(id) { return cache.moving[id]; });
22099 if (!parentsMoving) delete cache.moving[nodeId];
22101 return parentsMoving;
22104 function cacheEntities(ids) {
22105 _.each(ids, function(id) {
22106 if (cache.moving[id]) return;
22107 cache.moving[id] = true;
22109 var entity = graph.hasEntity(id);
22110 if (!entity) return;
22112 if (entity.type === 'node') {
22113 cache.nodes.push(id);
22114 cache.startLoc[id] = entity.loc;
22115 } else if (entity.type === 'way') {
22116 cache.ways.push(id);
22117 cacheEntities(entity.nodes);
22119 cacheEntities(_.pluck(entity.members, 'id'));
22124 function cacheIntersections(ids) {
22125 function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
22127 _.each(ids, function(id) {
22128 // consider only intersections with 1 moved and 1 unmoved way.
22129 _.each(graph.childNodes(graph.entity(id)), function(node) {
22130 var parents = graph.parentWays(node);
22131 if (parents.length !== 2) return;
22133 var moved = graph.entity(id),
22134 unmoved = _.find(parents, function(way) { return !cache.moving[way.id]; });
22135 if (!unmoved) return;
22137 // exclude ways that are overly connected..
22138 if (_.intersection(moved.nodes, unmoved.nodes).length > 2) return;
22140 if (moved.isArea() || unmoved.isArea()) return;
22142 cache.intersection[node.id] = {
22145 unmovedId: unmoved.id,
22146 movedIsEP: isEndpoint(moved, node.id),
22147 unmovedIsEP: isEndpoint(unmoved, node.id)
22159 cache.intersection = {};
22160 cache.replacedVertex = {};
22161 cache.startLoc = {};
22165 cacheEntities(moveIds);
22166 cacheIntersections(cache.ways);
22167 cache.nodes = _.filter(cache.nodes, canMove);
22174 // Place a vertex where the moved vertex used to be, to preserve way shape..
22175 function replaceMovedVertex(nodeId, wayId, graph, delta) {
22176 var way = graph.entity(wayId),
22177 moved = graph.entity(nodeId),
22178 movedIndex = way.nodes.indexOf(nodeId),
22179 len, prevIndex, nextIndex;
22181 if (way.isClosed()) {
22182 len = way.nodes.length - 1;
22183 prevIndex = (movedIndex + len - 1) % len;
22184 nextIndex = (movedIndex + len + 1) % len;
22186 len = way.nodes.length;
22187 prevIndex = movedIndex - 1;
22188 nextIndex = movedIndex + 1;
22191 var prev = graph.hasEntity(way.nodes[prevIndex]),
22192 next = graph.hasEntity(way.nodes[nextIndex]);
22194 // Don't add orig vertex at endpoint..
22195 if (!prev || !next) return graph;
22197 var key = wayId + '_' + nodeId,
22198 orig = cache.replacedVertex[key];
22201 cache.replacedVertex[key] = orig;
22202 cache.startLoc[orig.id] = cache.startLoc[nodeId];
22207 start = projection(cache.startLoc[nodeId]);
22208 end = projection.invert(vecAdd(start, delta));
22210 end = cache.startLoc[nodeId];
22212 orig = orig.move(end);
22214 var angle = Math.abs(iD.geo.angle(orig, prev, projection) -
22215 iD.geo.angle(orig, next, projection)) * 180 / Math.PI;
22217 // Don't add orig vertex if it would just make a straight line..
22218 if (angle > 175 && angle < 185) return graph;
22220 // Don't add orig vertex if another point is already nearby (within 10m)
22221 if (iD.geo.sphericalDistance(prev.loc, orig.loc) < 10 ||
22222 iD.geo.sphericalDistance(orig.loc, next.loc) < 10) return graph;
22224 // moving forward or backward along way?
22225 var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
22226 p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
22227 d1 = iD.geo.pathLength(p1),
22228 d2 = iD.geo.pathLength(p2),
22229 insertAt = (d1 < d2) ? movedIndex : nextIndex;
22231 // moving around closed loop?
22232 if (way.isClosed() && insertAt === 0) insertAt = len;
22234 way = way.addNode(orig.id, insertAt);
22235 return graph.replace(orig).replace(way);
22238 // Reorder nodes around intersections that have moved..
22239 function unZorroIntersection(intersection, graph) {
22240 var vertex = graph.entity(intersection.nodeId),
22241 way1 = graph.entity(intersection.movedId),
22242 way2 = graph.entity(intersection.unmovedId),
22243 isEP1 = intersection.movedIsEP,
22244 isEP2 = intersection.unmovedIsEP;
22246 // don't move the vertex if it is the endpoint of both ways.
22247 if (isEP1 && isEP2) return graph;
22249 var nodes1 = _.without(graph.childNodes(way1), vertex),
22250 nodes2 = _.without(graph.childNodes(way2), vertex);
22252 if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
22253 if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
22255 var edge1 = !isEP1 && iD.geo.chooseEdge(nodes1, projection(vertex.loc), projection),
22256 edge2 = !isEP2 && iD.geo.chooseEdge(nodes2, projection(vertex.loc), projection),
22259 // snap vertex to nearest edge (or some point between them)..
22260 if (!isEP1 && !isEP2) {
22261 var epsilon = 1e-4, maxIter = 10;
22262 for (var i = 0; i < maxIter; i++) {
22263 loc = iD.geo.interp(edge1.loc, edge2.loc, 0.5);
22264 edge1 = iD.geo.chooseEdge(nodes1, projection(loc), projection);
22265 edge2 = iD.geo.chooseEdge(nodes2, projection(loc), projection);
22266 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
22268 } else if (!isEP1) {
22274 graph = graph.replace(vertex.move(loc));
22276 // if zorro happened, reorder nodes..
22277 if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
22278 way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
22279 graph = graph.replace(way1);
22281 if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
22282 way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
22283 graph = graph.replace(way2);
22290 function cleanupIntersections(graph) {
22291 _.each(cache.intersection, function(obj) {
22292 graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
22293 graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
22294 graph = unZorroIntersection(obj, graph);
22300 // check if moving way endpoint can cross an unmoved way, if so limit delta..
22301 function limitDelta(graph) {
22302 _.each(cache.intersection, function(obj) {
22303 if (!obj.movedIsEP) return;
22305 var node = graph.entity(obj.nodeId),
22306 start = projection(node.loc),
22307 end = vecAdd(start, delta),
22308 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
22309 movedPath = _.map(_.pluck(movedNodes, 'loc'),
22310 function(loc) { return vecAdd(projection(loc), delta); }),
22311 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
22312 unmovedPath = _.map(_.pluck(unmovedNodes, 'loc'), projection),
22313 hits = iD.geo.pathIntersections(movedPath, unmovedPath);
22315 for (var i = 0; i < hits.length; i++) {
22316 if (_.isEqual(hits[i], end)) continue;
22317 var edge = iD.geo.chooseEdge(unmovedNodes, end, projection);
22318 delta = vecSub(projection(edge.loc), start);
22324 var action = function(graph) {
22325 if (delta[0] === 0 && delta[1] === 0) return graph;
22329 if (!_.isEmpty(cache.intersection)) {
22333 _.each(cache.nodes, function(id) {
22334 var node = graph.entity(id),
22335 start = projection(node.loc),
22336 end = vecAdd(start, delta);
22337 graph = graph.replace(node.move(projection.invert(end)));
22340 if (!_.isEmpty(cache.intersection)) {
22341 graph = cleanupIntersections(graph);
22347 action.disabled = function(graph) {
22348 function incompleteRelation(id) {
22349 var entity = graph.entity(id);
22350 return entity.type === 'relation' && !entity.isComplete(graph);
22353 if (_.any(moveIds, incompleteRelation))
22354 return 'incomplete_relation';
22357 action.delta = function() {
22363 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
22364 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
22365 iD.actions.MoveNode = function(nodeId, loc) {
22366 return function(graph) {
22367 return graph.replace(graph.entity(nodeId).move(loc));
22370 iD.actions.Noop = function() {
22371 return function(graph) {
22376 * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
22379 iD.actions.Orthogonalize = function(wayId, projection) {
22380 var threshold = 12, // degrees within right or straight to alter
22381 lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
22382 upperThreshold = Math.cos(threshold * Math.PI / 180);
22384 var action = function(graph) {
22385 var way = graph.entity(wayId),
22386 nodes = graph.childNodes(way),
22387 points = _.uniq(nodes).map(function(n) { return projection(n.loc); }),
22388 corner = {i: 0, dotp: 1},
22390 i, j, score, motions;
22392 if (nodes.length === 4) {
22393 for (i = 0; i < 1000; i++) {
22394 motions = points.map(calcMotion);
22395 points[corner.i] = addPoints(points[corner.i],motions[corner.i]);
22396 score = corner.dotp;
22397 if (score < epsilon) {
22402 graph = graph.replace(graph.entity(nodes[corner.i].id)
22403 .move(projection.invert(points[corner.i])));
22406 originalPoints = _.clone(points);
22409 for (i = 0; i < 1000; i++) {
22410 motions = points.map(calcMotion);
22411 for (j = 0; j < motions.length; j++) {
22412 points[j] = addPoints(points[j],motions[j]);
22414 var newScore = squareness(points);
22415 if (newScore < score) {
22416 best = _.clone(points);
22419 if (score < epsilon) {
22426 for (i = 0; i < points.length; i++) {
22427 // only move the points that actually moved
22428 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
22429 graph = graph.replace(graph.entity(nodes[i].id)
22430 .move(projection.invert(points[i])));
22434 // remove empty nodes on straight sections
22435 for (i = 0; i < points.length; i++) {
22436 var node = nodes[i];
22438 if (graph.parentWays(node).length > 1 ||
22439 graph.parentRelations(node).length ||
22440 node.hasInterestingTags()) {
22445 var dotp = normalizedDotProduct(i, points);
22446 if (dotp < -1 + epsilon) {
22447 graph = iD.actions.DeleteNode(nodes[i].id)(graph);
22454 function calcMotion(b, i, array) {
22455 var a = array[(i - 1 + array.length) % array.length],
22456 c = array[(i + 1) % array.length],
22457 p = subtractPoints(a, b),
22458 q = subtractPoints(c, b),
22461 scale = 2 * Math.min(iD.geo.euclideanDistance(p, [0, 0]), iD.geo.euclideanDistance(q, [0, 0]));
22462 p = normalizePoint(p, 1.0);
22463 q = normalizePoint(q, 1.0);
22465 dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
22467 // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
22468 if (array.length > 3) {
22469 if (dotp < -0.707106781186547) {
22472 } else if (dotp && Math.abs(dotp) < corner.dotp) {
22474 corner.dotp = Math.abs(dotp);
22477 return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
22481 function squareness(points) {
22482 return points.reduce(function(sum, val, i, array) {
22483 var dotp = normalizedDotProduct(i, array);
22485 dotp = filterDotProduct(dotp);
22486 return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
22490 function normalizedDotProduct(i, points) {
22491 var a = points[(i - 1 + points.length) % points.length],
22493 c = points[(i + 1) % points.length],
22494 p = subtractPoints(a, b),
22495 q = subtractPoints(c, b);
22497 p = normalizePoint(p, 1.0);
22498 q = normalizePoint(q, 1.0);
22500 return p[0] * q[0] + p[1] * q[1];
22503 function subtractPoints(a, b) {
22504 return [a[0] - b[0], a[1] - b[1]];
22507 function addPoints(a, b) {
22508 return [a[0] + b[0], a[1] + b[1]];
22511 function normalizePoint(point, scale) {
22512 var vector = [0, 0];
22513 var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
22514 if (length !== 0) {
22515 vector[0] = point[0] / length;
22516 vector[1] = point[1] / length;
22519 vector[0] *= scale;
22520 vector[1] *= scale;
22525 function filterDotProduct(dotp) {
22526 if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
22533 action.disabled = function(graph) {
22534 var way = graph.entity(wayId),
22535 nodes = graph.childNodes(way),
22536 points = _.uniq(nodes).map(function(n) { return projection(n.loc); });
22538 if (squareness(points)) {
22542 return 'not_squarish';
22547 // Create a restriction relation for `turn`, which must have the following structure:
22550 // from: { node: <node ID>, way: <way ID> },
22551 // via: { node: <node ID> },
22552 // to: { node: <node ID>, way: <way ID> },
22553 // restriction: <'no_right_turn', 'no_left_turn', etc.>
22556 // This specifies a restriction of type `restriction` when traveling from
22557 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
22558 // (The action does not check that these entities form a valid intersection.)
22560 // If `restriction` is not provided, it is automatically determined by
22561 // iD.geo.inferRestriction.
22563 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
22564 // and `to.node` are used to determine which portion of the split ways become
22565 // members of the restriction.
22567 // For testing convenience, accepts an ID to assign to the new relation.
22568 // Normally, this will be undefined and the relation will automatically
22569 // be assigned a new ID.
22571 iD.actions.RestrictTurn = function(turn, projection, restrictionId) {
22572 return function(graph) {
22573 var from = graph.entity(turn.from.way),
22574 via = graph.entity(turn.via.node),
22575 to = graph.entity(turn.to.way);
22577 function isClosingNode(way, nodeId) {
22578 return nodeId === way.first() && nodeId === way.last();
22581 function split(toOrFrom) {
22582 var newID = toOrFrom.newID || iD.Way().id;
22583 graph = iD.actions.Split(via.id, [newID])
22584 .limitWays([toOrFrom.way])(graph);
22586 var a = graph.entity(newID),
22587 b = graph.entity(toOrFrom.way);
22589 if (a.nodes.indexOf(toOrFrom.node) !== -1) {
22596 if (!from.affix(via.id) || isClosingNode(from, via.id)) {
22597 if (turn.from.node === turn.to.node) {
22599 from = to = split(turn.from)[0];
22600 } else if (turn.from.way === turn.to.way) {
22601 // Straight-on or circular
22602 var s = split(turn.from);
22607 from = split(turn.from)[0];
22611 if (!to.affix(via.id) || isClosingNode(to, via.id)) {
22612 to = split(turn.to)[0];
22615 return graph.replace(iD.Relation({
22618 type: 'restriction',
22619 restriction: turn.restriction ||
22620 iD.geo.inferRestriction(
22628 {id: from.id, type: 'way', role: 'from'},
22629 {id: via.id, type: 'node', role: 'via'},
22630 {id: to.id, type: 'way', role: 'to'}
22636 Order the nodes of a way in reverse order and reverse any direction dependent tags
22637 other than `oneway`. (We assume that correcting a backwards oneway is the primary
22638 reason for reversing a way.)
22640 The following transforms are performed:
22643 *:right=* ⟺ *:left=*
22644 *:forward=* ⟺ *:backward=*
22645 direction=up ⟺ direction=down
22646 incline=up ⟺ incline=down
22650 role=forward ⟺ role=backward
22651 role=north ⟺ role=south
22652 role=east ⟺ role=west
22654 In addition, numeric-valued `incline` tags are negated.
22656 The JOSM implementation was used as a guide, but transformations that were of unclear benefit
22657 or adjusted tags that don't seem to be used in practice were omitted.
22660 http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
22661 http://wiki.openstreetmap.org/wiki/Key:direction#Steps
22662 http://wiki.openstreetmap.org/wiki/Key:incline
22663 http://wiki.openstreetmap.org/wiki/Route#Members
22664 http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
22666 iD.actions.Reverse = function(wayId, options) {
22667 var replacements = [
22668 [/:right$/, ':left'], [/:left$/, ':right'],
22669 [/:forward$/, ':backward'], [/:backward$/, ':forward']
22671 numeric = /^([+\-]?)(?=[\d.])/,
22673 forward: 'backward',
22674 backward: 'forward',
22681 function reverseKey(key) {
22682 for (var i = 0; i < replacements.length; ++i) {
22683 var replacement = replacements[i];
22684 if (replacement[0].test(key)) {
22685 return key.replace(replacement[0], replacement[1]);
22691 function reverseValue(key, value) {
22692 if (key === 'incline' && numeric.test(value)) {
22693 return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
22694 } else if (key === 'incline' || key === 'direction') {
22695 return {up: 'down', down: 'up'}[value] || value;
22696 } else if (options && options.reverseOneway && key === 'oneway') {
22697 return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
22699 return {left: 'right', right: 'left'}[value] || value;
22703 return function(graph) {
22704 var way = graph.entity(wayId),
22705 nodes = way.nodes.slice().reverse(),
22706 tags = {}, key, role;
22708 for (key in way.tags) {
22709 tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
22712 graph.parentRelations(way).forEach(function(relation) {
22713 relation.members.forEach(function(member, index) {
22714 if (member.id === way.id && (role = roleReversals[member.role])) {
22715 relation = relation.updateMember({role: role}, index);
22716 graph = graph.replace(relation);
22721 return graph.replace(way.update({nodes: nodes, tags: tags}));
22724 iD.actions.Revert = function(id) {
22726 var action = function(graph) {
22727 var entity = graph.hasEntity(id),
22728 base = graph.base().entities[id];
22730 if (entity && !base) { // entity will be removed..
22731 if (entity.type === 'node') {
22732 graph.parentWays(entity)
22733 .forEach(function(parent) {
22734 parent = parent.removeNode(id);
22735 graph = graph.replace(parent);
22737 if (parent.isDegenerate()) {
22738 graph = iD.actions.DeleteWay(parent.id)(graph);
22743 graph.parentRelations(entity)
22744 .forEach(function(parent) {
22745 parent = parent.removeMembersWithID(id);
22746 graph = graph.replace(parent);
22748 if (parent.isDegenerate()) {
22749 graph = iD.actions.DeleteRelation(parent.id)(graph);
22754 return graph.revert(id);
22759 iD.actions.RotateWay = function(wayId, pivot, angle, projection) {
22760 return function(graph) {
22761 return graph.update(function(graph) {
22762 var way = graph.entity(wayId);
22764 _.unique(way.nodes).forEach(function(id) {
22766 var node = graph.entity(id),
22767 point = projection(node.loc),
22770 radial[0] = point[0] - pivot[0];
22771 radial[1] = point[1] - pivot[1];
22774 radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + pivot[0],
22775 radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + pivot[1]
22778 graph = graph.replace(node.move(projection.invert(point)));
22785 // Split a way at the given node.
22787 // Optionally, split only the given ways, if multiple ways share
22790 // This is the inverse of `iD.actions.Join`.
22792 // For testing convenience, accepts an ID to assign to the new way.
22793 // Normally, this will be undefined and the way will automatically
22794 // be assigned a new ID.
22797 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
22799 iD.actions.Split = function(nodeId, newWayIds) {
22802 // if the way is closed, we need to search for a partner node
22803 // to split the way at.
22805 // The following looks for a node that is both far away from
22806 // the initial node in terms of way segment length and nearby
22807 // in terms of beeline-distance. This assures that areas get
22808 // split on the most "natural" points (independent of the number
22810 // For example: bone-shaped areas get split across their waist
22811 // line, circles across the diameter.
22812 function splitArea(nodes, idxA, graph) {
22813 var lengths = new Array(nodes.length),
22819 function wrap(index) {
22820 return iD.util.wrap(index, nodes.length);
22823 function dist(nA, nB) {
22824 return iD.geo.sphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
22827 // calculate lengths
22829 for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
22830 length += dist(nodes[i], nodes[wrap(i-1)]);
22831 lengths[i] = length;
22835 for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
22836 length += dist(nodes[i], nodes[wrap(i+1)]);
22837 if (length < lengths[i])
22838 lengths[i] = length;
22841 // determine best opposite node to split
22842 for (i = 0; i < nodes.length; i++) {
22843 var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
22853 function split(graph, wayA, newWayId) {
22854 var wayB = iD.Way({id: newWayId, tags: wayA.tags}),
22857 isArea = wayA.isArea(),
22858 isOuter = iD.geo.isSimpleMultipolygonOuterMember(wayA, graph);
22860 if (wayA.isClosed()) {
22861 var nodes = wayA.nodes.slice(0, -1),
22862 idxA = _.indexOf(nodes, nodeId),
22863 idxB = splitArea(nodes, idxA, graph);
22866 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
22867 nodesB = nodes.slice(idxB, idxA + 1);
22869 nodesA = nodes.slice(idxA, idxB + 1);
22870 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
22873 var idx = _.indexOf(wayA.nodes, nodeId, 1);
22874 nodesA = wayA.nodes.slice(0, idx + 1);
22875 nodesB = wayA.nodes.slice(idx);
22878 wayA = wayA.update({nodes: nodesA});
22879 wayB = wayB.update({nodes: nodesB});
22881 graph = graph.replace(wayA);
22882 graph = graph.replace(wayB);
22884 graph.parentRelations(wayA).forEach(function(relation) {
22885 if (relation.isRestriction()) {
22886 var via = relation.memberByRole('via');
22887 if (via && wayB.contains(via.id)) {
22888 relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
22889 graph = graph.replace(relation);
22892 if (relation === isOuter) {
22893 graph = graph.replace(relation.mergeTags(wayA.tags));
22894 graph = graph.replace(wayA.update({tags: {}}));
22895 graph = graph.replace(wayB.update({tags: {}}));
22901 role: relation.memberById(wayA.id).role
22904 graph = iD.actions.AddMember(relation.id, member)(graph);
22908 if (!isOuter && isArea) {
22909 var multipolygon = iD.Relation({
22910 tags: _.extend({}, wayA.tags, {type: 'multipolygon'}),
22912 {id: wayA.id, role: 'outer', type: 'way'},
22913 {id: wayB.id, role: 'outer', type: 'way'}
22916 graph = graph.replace(multipolygon);
22917 graph = graph.replace(wayA.update({tags: {}}));
22918 graph = graph.replace(wayB.update({tags: {}}));
22924 var action = function(graph) {
22925 var candidates = action.ways(graph);
22926 for (var i = 0; i < candidates.length; i++) {
22927 graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
22932 action.ways = function(graph) {
22933 var node = graph.entity(nodeId),
22934 parents = graph.parentWays(node),
22935 hasLines = _.any(parents, function(parent) { return parent.geometry(graph) === 'line'; });
22937 return parents.filter(function(parent) {
22938 if (wayIds && wayIds.indexOf(parent.id) === -1)
22941 if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
22944 if (parent.isClosed()) {
22948 for (var i = 1; i < parent.nodes.length - 1; i++) {
22949 if (parent.nodes[i] === nodeId) {
22958 action.disabled = function(graph) {
22959 var candidates = action.ways(graph);
22960 if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
22961 return 'not_eligible';
22964 action.limitWays = function(_) {
22965 if (!arguments.length) return wayIds;
22973 * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
22976 iD.actions.Straighten = function(wayId, projection) {
22977 function positionAlongWay(n, s, e) {
22978 return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1]))/
22979 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
22982 var action = function(graph) {
22983 var way = graph.entity(wayId),
22984 nodes = graph.childNodes(way),
22985 points = nodes.map(function(n) { return projection(n.loc); }),
22986 startPoint = points[0],
22987 endPoint = points[points.length-1],
22991 for (i = 1; i < points.length-1; i++) {
22992 var node = nodes[i],
22995 if (graph.parentWays(node).length > 1 ||
22996 graph.parentRelations(node).length ||
22997 node.hasInterestingTags()) {
22999 var u = positionAlongWay(point, startPoint, endPoint),
23000 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
23001 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]);
23003 graph = graph.replace(graph.entity(node.id)
23004 .move(projection.invert([p0, p1])));
23007 if (toDelete.indexOf(node) === -1) {
23008 toDelete.push(node);
23013 for (i = 0; i < toDelete.length; i++) {
23014 graph = iD.actions.DeleteNode(toDelete[i].id)(graph);
23020 action.disabled = function(graph) {
23021 // check way isn't too bendy
23022 var way = graph.entity(wayId),
23023 nodes = graph.childNodes(way),
23024 points = nodes.map(function(n) { return projection(n.loc); }),
23025 startPoint = points[0],
23026 endPoint = points[points.length-1],
23027 threshold = 0.2 * Math.sqrt(Math.pow(startPoint[0] - endPoint[0], 2) + Math.pow(startPoint[1] - endPoint[1], 2)),
23030 for (i = 1; i < points.length-1; i++) {
23031 var point = points[i],
23032 u = positionAlongWay(point, startPoint, endPoint),
23033 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
23034 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
23035 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
23037 // to bendy if point is off by 20% of total start/end distance in projected space
23038 if (dist > threshold) {
23039 return 'too_bendy';
23046 // Remove the effects of `turn.restriction` on `turn`, which must have the
23047 // following structure:
23050 // from: { node: <node ID>, way: <way ID> },
23051 // via: { node: <node ID> },
23052 // to: { node: <node ID>, way: <way ID> },
23053 // restriction: <relation ID>
23056 // In the simple case, `restriction` is a reference to a `no_*` restriction
23057 // on the turn itself. In this case, it is simply deleted.
23059 // The more complex case is where `restriction` references an `only_*`
23060 // restriction on a different turn in the same intersection. In that case,
23061 // that restriction is also deleted, but at the same time restrictions on
23062 // the turns other than the first two are created.
23064 iD.actions.UnrestrictTurn = function(turn) {
23065 return function(graph) {
23066 return iD.actions.DeleteRelation(turn.restriction)(graph);
23070 iD.behavior.AddWay = function(context) {
23071 var event = d3.dispatch('start', 'startFromWay', 'startFromNode'),
23072 draw = iD.behavior.Draw(context);
23074 var addWay = function(surface) {
23075 draw.on('click', event.start)
23076 .on('clickWay', event.startFromWay)
23077 .on('clickNode', event.startFromNode)
23078 .on('cancel', addWay.cancel)
23079 .on('finish', addWay.cancel);
23082 .dblclickEnable(false);
23084 surface.call(draw);
23087 addWay.off = function(surface) {
23088 surface.call(draw.off);
23091 addWay.cancel = function() {
23092 window.setTimeout(function() {
23093 context.map().dblclickEnable(true);
23096 context.enter(iD.modes.Browse(context));
23099 addWay.tail = function(text) {
23104 return d3.rebind(addWay, event, 'on');
23106 iD.behavior.Breathe = function() {
23107 var duration = 800,
23108 selector = '.selected.shadow, .selected .shadow',
23109 selected = d3.select(null),
23114 function reset(selection) {
23116 .style('stroke-opacity', null)
23117 .style('stroke-width', null)
23118 .style('fill-opacity', null)
23122 function setAnimationParams(transition, fromTo) {
23124 .style('stroke-opacity', function(d) { return params[d.id][fromTo].opacity; })
23125 .style('stroke-width', function(d) { return params[d.id][fromTo].width; })
23126 .style('fill-opacity', function(d) { return params[d.id][fromTo].opacity; })
23127 .style('r', function(d) { return params[d.id][fromTo].width; });
23130 function calcAnimationParams(selection) {
23133 .each(function(d) {
23134 var s = d3.select(this),
23135 tag = s.node().tagName,
23136 p = {'from': {}, 'to': {}},
23139 // determine base opacity and width
23140 if (tag === 'circle') {
23141 opacity = parseFloat(s.style('fill-opacity') || 0.5);
23142 width = parseFloat(s.style('r') || 15.5);
23144 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
23145 width = parseFloat(s.style('stroke-width') || 10);
23148 // calculate from/to interpolation params..
23150 p.from.opacity = opacity * 0.6;
23151 p.to.opacity = opacity * 1.25;
23152 p.from.width = width * 0.9;
23153 p.to.width = width * (tag === 'circle' ? 1.5 : 1.25);
23158 function run(surface, fromTo) {
23159 var toFrom = (fromTo === 'from' ? 'to': 'from'),
23160 currSelected = surface.selectAll(selector),
23161 currClassed = surface.attr('class'),
23164 if (done || currSelected.empty()) {
23165 selected.call(reset);
23169 if (!_.isEqual(currSelected, selected) || currClassed !== classed) {
23170 selected.call(reset);
23171 classed = currClassed;
23172 selected = currSelected.call(calcAnimationParams);
23177 .call(setAnimationParams, fromTo)
23178 .duration(duration)
23179 .each(function() { ++n; })
23180 .each('end', function() {
23181 if (!--n) { // call once
23182 surface.call(run, toFrom);
23187 var breathe = function(surface) {
23189 d3.timer(function() {
23190 if (done) return true;
23192 var currSelected = surface.selectAll(selector);
23193 if (currSelected.empty()) return false;
23195 surface.call(run, 'from');
23200 breathe.off = function() {
23211 iD.behavior.Copy = function(context) {
23212 var keybinding = d3.keybinding('copy');
23214 function groupEntities(ids, graph) {
23215 var entities = ids.map(function (id) { return graph.entity(id); });
23216 return _.extend({relation: [], way: [], node: []},
23217 _.groupBy(entities, function(entity) { return entity.type; }));
23220 function getDescendants(id, graph, descendants) {
23221 var entity = graph.entity(id),
23224 descendants = descendants || {};
23226 if (entity.type === 'relation') {
23227 children = _.pluck(entity.members, 'id');
23228 } else if (entity.type === 'way') {
23229 children = entity.nodes;
23234 for (i = 0; i < children.length; i++) {
23235 if (!descendants[children[i]]) {
23236 descendants[children[i]] = true;
23237 descendants = getDescendants(children[i], graph, descendants);
23241 return descendants;
23244 function doCopy() {
23245 d3.event.preventDefault();
23246 if (context.inIntro()) return;
23248 var graph = context.graph(),
23249 selected = groupEntities(context.selectedIDs(), graph),
23254 for (i = 0; i < selected.relation.length; i++) {
23255 entity = selected.relation[i];
23256 if (!skip[entity.id] && entity.isComplete(graph)) {
23257 canCopy.push(entity.id);
23258 skip = getDescendants(entity.id, graph, skip);
23261 for (i = 0; i < selected.way.length; i++) {
23262 entity = selected.way[i];
23263 if (!skip[entity.id]) {
23264 canCopy.push(entity.id);
23265 skip = getDescendants(entity.id, graph, skip);
23268 for (i = 0; i < selected.node.length; i++) {
23269 entity = selected.node[i];
23270 if (!skip[entity.id]) {
23271 canCopy.push(entity.id);
23275 context.copyIDs(canCopy);
23279 keybinding.on(iD.ui.cmd('⌘C'), doCopy);
23280 d3.select(document).call(keybinding);
23284 copy.off = function() {
23285 d3.select(document).call(keybinding.off);
23291 `iD.behavior.drag` is like `d3.behavior.drag`, with the following differences:
23293 * The `origin` function is expected to return an [x, y] tuple rather than an
23295 * The events are `start`, `move`, and `end`.
23296 (https://github.com/mbostock/d3/issues/563)
23297 * The `start` event is not dispatched until the first cursor movement occurs.
23298 (https://github.com/mbostock/d3/pull/368)
23299 * The `move` event has a `point` and `delta` [x, y] tuple properties rather
23300 than `x`, `y`, `dx`, and `dy` properties.
23301 * The `end` event is not dispatched if no movement occurs.
23302 * An `off` function is available that unbinds the drag's internal event handlers.
23303 * Delegation is supported via the `delegate` function.
23306 iD.behavior.drag = function() {
23307 function d3_eventCancel() {
23308 d3.event.stopPropagation();
23309 d3.event.preventDefault();
23312 var event = d3.dispatch('start', 'move', 'end'),
23316 event_, target, surface;
23318 event.of = function(thiz, argumentz) {
23319 return function(e1) {
23320 var e0 = e1.sourceEvent = d3.event;
23324 event[e1.type].apply(thiz, argumentz);
23331 var d3_event_userSelectProperty = iD.util.prefixCSSProperty('UserSelect'),
23332 d3_event_userSelectSuppress = d3_event_userSelectProperty ?
23334 var selection = d3.selection(),
23335 select = selection.style(d3_event_userSelectProperty);
23336 selection.style(d3_event_userSelectProperty, 'none');
23337 return function () {
23338 selection.style(d3_event_userSelectProperty, select);
23342 var w = d3.select(window).on('selectstart.' + type, d3_eventCancel);
23343 return function () {
23344 w.on('selectstart.' + type, null);
23348 function mousedown() {
23350 event_ = event.of(target, arguments);
23351 var eventTarget = d3.event.target,
23352 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
23356 selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
23358 var w = d3.select(window)
23359 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
23360 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
23363 offset = origin.apply(target, arguments);
23364 offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
23369 if (touchId === null) d3.event.stopPropagation();
23372 var p = target.parentNode || surface;
23373 return touchId !== null ? d3.touches(p).filter(function(p) {
23374 return p.identifier === touchId;
23375 })[0] : d3.mouse(p);
23378 function dragmove() {
23381 dx = p[0] - origin_[0],
23382 dy = p[1] - origin_[1];
23384 if (dx === 0 && dy === 0)
23399 point: [p[0] + offset[0], p[1] + offset[1]],
23404 function dragend() {
23411 if (d3.event.target === eventTarget) w.on('click.drag', click, true);
23414 w.on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
23415 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
23421 w.on('click.drag', null);
23425 function drag(selection) {
23426 var matchesSelector = iD.util.prefixDOMProperty('matchesSelector'),
23427 delegate = mousedown;
23430 delegate = function() {
23432 target = d3.event.target;
23433 for (; target && target !== root; target = target.parentNode) {
23434 if (target[matchesSelector](selector) &&
23435 (!filter || filter(target.__data__))) {
23436 return mousedown.call(target, target.__data__);
23442 selection.on('mousedown.drag' + selector, delegate)
23443 .on('touchstart.drag' + selector, delegate);
23446 drag.off = function(selection) {
23447 selection.on('mousedown.drag' + selector, null)
23448 .on('touchstart.drag' + selector, null);
23451 drag.delegate = function(_) {
23452 if (!arguments.length) return selector;
23457 drag.filter = function(_) {
23458 if (!arguments.length) return origin;
23463 drag.origin = function (_) {
23464 if (!arguments.length) return origin;
23469 drag.cancel = function() {
23471 .on('mousemove.drag', null)
23472 .on('mouseup.drag', null);
23476 drag.target = function() {
23477 if (!arguments.length) return target;
23478 target = arguments[0];
23479 event_ = event.of(target, Array.prototype.slice.call(arguments, 1));
23483 drag.surface = function() {
23484 if (!arguments.length) return surface;
23485 surface = arguments[0];
23489 return d3.rebind(drag, event, 'on');
23491 iD.behavior.Draw = function(context) {
23492 var event = d3.dispatch('move', 'click', 'clickWay',
23493 'clickNode', 'undo', 'cancel', 'finish'),
23494 keybinding = d3.keybinding('draw'),
23495 hover = iD.behavior.Hover(context)
23497 .on('hover', context.ui().sidebar.hover),
23498 tail = iD.behavior.Tail(),
23499 edit = iD.behavior.Edit(context),
23500 closeTolerance = 4,
23504 if (d3.event.altKey) return {};
23505 else return d3.event.target.__data__ || {};
23508 function mousedown() {
23511 var p = context.container().node();
23512 return touchId !== null ? d3.touches(p).filter(function(p) {
23513 return p.identifier === touchId;
23514 })[0] : d3.mouse(p);
23517 var element = d3.select(this),
23518 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
23522 element.on('mousemove.draw', null);
23524 d3.select(window).on('mouseup.draw', function() {
23525 var t2 = +new Date(),
23527 dist = iD.geo.euclideanDistance(p1, p2);
23529 element.on('mousemove.draw', mousemove);
23530 d3.select(window).on('mouseup.draw', null);
23532 if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
23533 // Prevent a quick second click
23534 d3.select(window).on('click.draw-block', function() {
23535 d3.event.stopPropagation();
23538 context.map().dblclickEnable(false);
23540 window.setTimeout(function() {
23541 context.map().dblclickEnable(true);
23542 d3.select(window).on('click.draw-block', null);
23550 function mousemove() {
23551 event.move(datum());
23556 if (d.type === 'way') {
23557 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection),
23558 edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
23559 event.clickWay(choice.loc, edge);
23561 } else if (d.type === 'node') {
23562 event.clickNode(d);
23565 event.click(context.map().mouseCoordinates());
23569 function backspace() {
23570 d3.event.preventDefault();
23575 d3.event.preventDefault();
23580 d3.event.preventDefault();
23584 function draw(selection) {
23585 context.install(hover);
23586 context.install(edit);
23588 if (!context.inIntro() && !iD.behavior.Draw.usedTails[tail.text()]) {
23589 context.install(tail);
23593 .on('⌫', backspace)
23599 .on('mousedown.draw', mousedown)
23600 .on('mousemove.draw', mousemove);
23602 d3.select(document)
23608 draw.off = function(selection) {
23609 context.ui().sidebar.hover.cancel();
23610 context.uninstall(hover);
23611 context.uninstall(edit);
23613 if (!context.inIntro() && !iD.behavior.Draw.usedTails[tail.text()]) {
23614 context.uninstall(tail);
23615 iD.behavior.Draw.usedTails[tail.text()] = true;
23619 .on('mousedown.draw', null)
23620 .on('mousemove.draw', null);
23623 .on('mouseup.draw', null);
23625 d3.select(document)
23626 .call(keybinding.off);
23629 draw.tail = function(_) {
23634 return d3.rebind(draw, event, 'on');
23637 iD.behavior.Draw.usedTails = {};
23638 iD.behavior.DrawWay = function(context, wayId, index, mode, baseGraph) {
23639 var way = context.entity(wayId),
23640 isArea = context.geometry(wayId) === 'area',
23642 annotation = t((way.isDegenerate() ?
23643 'operations.start.annotation.' :
23644 'operations.continue.annotation.') + context.geometry(wayId)),
23645 draw = iD.behavior.Draw(context);
23647 var startIndex = typeof index === 'undefined' ? way.nodes.length - 1 : 0,
23648 start = iD.Node({loc: context.graph().entity(way.nodes[startIndex]).loc}),
23649 end = iD.Node({loc: context.map().mouseCoordinates()}),
23651 nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
23652 tags: _.clone(way.tags)
23655 var f = context[way.isDegenerate() ? 'replace' : 'perform'];
23657 f(iD.actions.AddEntity(end),
23658 iD.actions.AddVertex(wayId, end.id, index));
23660 f(iD.actions.AddEntity(start),
23661 iD.actions.AddEntity(end),
23662 iD.actions.AddEntity(segment));
23665 function move(datum) {
23668 if (datum.type === 'node' && datum.id !== end.id) {
23670 } else if (datum.type === 'way' && datum.id !== segment.id) {
23671 loc = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
23673 loc = context.map().mouseCoordinates();
23676 context.replace(iD.actions.MoveNode(end.id, loc));
23679 function undone() {
23681 context.enter(iD.modes.Browse(context));
23684 function setActiveElements() {
23685 var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
23686 context.surface().selectAll(iD.util.entitySelector(active))
23687 .classed('active', true);
23690 var drawWay = function(surface) {
23691 draw.on('move', move)
23692 .on('click', drawWay.add)
23693 .on('clickWay', drawWay.addWay)
23694 .on('clickNode', drawWay.addNode)
23695 .on('undo', context.undo)
23696 .on('cancel', drawWay.cancel)
23697 .on('finish', drawWay.finish);
23700 .dblclickEnable(false)
23701 .on('drawn.draw', setActiveElements);
23703 setActiveElements();
23705 surface.call(draw);
23708 .on('undone.draw', undone);
23711 drawWay.off = function(surface) {
23716 .on('drawn.draw', null);
23718 surface.call(draw.off)
23719 .selectAll('.active')
23720 .classed('active', false);
23723 .on('undone.draw', null);
23726 function ReplaceTemporaryNode(newNode) {
23727 return function(graph) {
23730 .replace(way.addNode(newNode.id, index))
23735 .replace(graph.entity(wayId).addNode(newNode.id, index))
23743 // Accept the current position of the temporary node and continue drawing.
23744 drawWay.add = function(loc) {
23746 // prevent duplicate nodes
23747 var last = context.hasEntity(way.nodes[way.nodes.length - (isArea ? 2 : 1)]);
23748 if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
23750 var newNode = iD.Node({loc: loc});
23753 iD.actions.AddEntity(newNode),
23754 ReplaceTemporaryNode(newNode),
23758 context.enter(mode);
23761 // Connect the way to an existing way.
23762 drawWay.addWay = function(loc, edge) {
23763 var previousEdge = startIndex ?
23764 [way.nodes[startIndex], way.nodes[startIndex - 1]] :
23765 [way.nodes[0], way.nodes[1]];
23767 // Avoid creating duplicate segments
23768 if (!isArea && iD.geo.edgeEqual(edge, previousEdge))
23771 var newNode = iD.Node({ loc: loc });
23774 iD.actions.AddMidpoint({ loc: loc, edge: edge}, newNode),
23775 ReplaceTemporaryNode(newNode),
23779 context.enter(mode);
23782 // Connect the way to an existing node and continue drawing.
23783 drawWay.addNode = function(node) {
23785 // Avoid creating duplicate segments
23786 if (way.areAdjacent(node.id, way.nodes[way.nodes.length - 1])) return;
23789 ReplaceTemporaryNode(node),
23793 context.enter(mode);
23796 // Finish the draw operation, removing the temporary node. If the way has enough
23797 // nodes to be valid, it's selected. Otherwise, return to browse mode.
23798 drawWay.finish = function() {
23802 window.setTimeout(function() {
23803 context.map().dblclickEnable(true);
23806 if (context.hasEntity(wayId)) {
23808 iD.modes.Select(context, [wayId])
23809 .suppressMenu(true)
23810 .newFeature(true));
23812 context.enter(iD.modes.Browse(context));
23816 // Cancel the draw operation and return to browse, deleting everything drawn.
23817 drawWay.cancel = function() {
23819 d3.functor(baseGraph),
23820 t('operations.cancel_draw.annotation'));
23822 window.setTimeout(function() {
23823 context.map().dblclickEnable(true);
23827 context.enter(iD.modes.Browse(context));
23830 drawWay.tail = function(text) {
23837 iD.behavior.Edit = function(context) {
23840 .minzoom(context.minEditableZoom());
23843 edit.off = function() {
23850 iD.behavior.Hash = function(context) {
23851 var s0 = null, // cached location.hash
23852 lat = 90 - 1e-8; // allowable latitude range
23854 var parser = function(map, s) {
23855 var q = iD.util.stringQs(s);
23856 var args = (q.map || '').split('/').map(Number);
23857 if (args.length < 3 || args.some(isNaN)) {
23858 return true; // replace bogus hash
23859 } else if (s !== formatter(map).slice(1)) {
23860 map.centerZoom([args[1],
23861 Math.min(lat, Math.max(-lat, args[2]))], args[0]);
23865 var formatter = function(map) {
23866 var mode = context.mode(),
23867 center = map.center(),
23869 precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)),
23870 q = _.omit(iD.util.stringQs(location.hash.substring(1)), 'comment'),
23873 if (mode && mode.id === 'browse') {
23876 var selected = context.selectedIDs().filter(function(id) {
23877 return !context.entity(id).isNew();
23879 if (selected.length) {
23880 newParams.id = selected.join(',');
23884 newParams.map = zoom.toFixed(2) +
23885 '/' + center[0].toFixed(precision) +
23886 '/' + center[1].toFixed(precision);
23888 return '#' + iD.util.qsString(_.assign(q, newParams), true);
23891 function update() {
23892 if (context.inIntro()) return;
23893 var s1 = formatter(context.map());
23894 if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map!
23897 var throttledUpdate = _.throttle(update, 500);
23899 function hashchange() {
23900 if (location.hash === s0) return; // ignore spurious hashchange events
23901 if (parser(context.map(), (s0 = location.hash).substring(1))) {
23902 update(); // replace bogus hash
23908 .on('move.hash', throttledUpdate);
23911 .on('enter.hash', throttledUpdate);
23914 .on('hashchange.hash', hashchange);
23916 if (location.hash) {
23917 var q = iD.util.stringQs(location.hash.substring(1));
23918 if (q.id) context.zoomToEntity(q.id.split(',')[0], !q.map);
23919 if (q.comment) context.storage('comment', q.comment);
23921 if (q.map) hash.hadHash = true;
23925 hash.off = function() {
23926 throttledUpdate.cancel();
23929 .on('move.hash', null);
23932 .on('enter.hash', null);
23935 .on('hashchange.hash', null);
23937 location.hash = '';
23943 The hover behavior adds the `.hover` class on mouseover to all elements to which
23944 the identical datum is bound, and removes it on mouseout.
23946 The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
23947 representation may consist of several elements scattered throughout the DOM hierarchy.
23948 Only one of these elements can have the :hover pseudo-class, but all of them will
23949 have the .hover class.
23951 iD.behavior.Hover = function() {
23952 var dispatch = d3.dispatch('hover'),
23957 function keydown() {
23958 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
23959 dispatch.hover(null);
23960 selection.selectAll('.hover')
23961 .classed('hover-suppressed', true)
23962 .classed('hover', false);
23967 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
23968 dispatch.hover(target ? target.id : null);
23969 selection.selectAll('.hover-suppressed')
23970 .classed('hover-suppressed', false)
23971 .classed('hover', true);
23975 var hover = function(__) {
23978 function enter(d) {
23979 if (d === target) return;
23983 selection.selectAll('.hover')
23984 .classed('hover', false);
23985 selection.selectAll('.hover-suppressed')
23986 .classed('hover-suppressed', false);
23988 if (target instanceof iD.Entity) {
23989 var selector = '.' + target.id;
23991 if (target.type === 'relation') {
23992 target.members.forEach(function(member) {
23993 selector += ', .' + member.id;
23997 var suppressed = altDisables && d3.event && d3.event.altKey;
23999 selection.selectAll(selector)
24000 .classed(suppressed ? 'hover-suppressed' : 'hover', true);
24002 dispatch.hover(target.id);
24004 dispatch.hover(null);
24010 function mouseover() {
24012 var target = d3.event.target;
24013 enter(target ? target.__data__ : null);
24016 function mouseout() {
24018 var target = d3.event.relatedTarget;
24019 enter(target ? target.__data__ : null);
24022 function mousedown() {
24025 .on('mouseup.hover', mouseup);
24028 function mouseup() {
24033 .on('mouseover.hover', mouseover)
24034 .on('mouseout.hover', mouseout)
24035 .on('mousedown.hover', mousedown)
24036 .on('mouseup.hover', mouseup);
24039 .on('keydown.hover', keydown)
24040 .on('keyup.hover', keyup);
24043 hover.off = function(selection) {
24044 selection.selectAll('.hover')
24045 .classed('hover', false);
24046 selection.selectAll('.hover-suppressed')
24047 .classed('hover-suppressed', false);
24050 .on('mouseover.hover', null)
24051 .on('mouseout.hover', null)
24052 .on('mousedown.hover', null)
24053 .on('mouseup.hover', null);
24056 .on('keydown.hover', null)
24057 .on('keyup.hover', null)
24058 .on('mouseup.hover', null);
24061 hover.altDisables = function(_) {
24062 if (!arguments.length) return altDisables;
24067 return d3.rebind(hover, dispatch, 'on');
24069 iD.behavior.Lasso = function(context) {
24071 var behavior = function(selection) {
24075 function mousedown() {
24076 if (d3.event.shiftKey === true) {
24078 mouse = context.mouse();
24082 .on('mousemove.lasso', mousemove)
24083 .on('mouseup.lasso', mouseup);
24085 d3.event.stopPropagation();
24089 function mousemove() {
24091 lasso = iD.ui.Lasso(context).a(mouse);
24092 context.surface().call(lasso);
24095 lasso.b(context.mouse());
24098 function normalize(a, b) {
24100 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
24101 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
24104 function mouseup() {
24106 .on('mousemove.lasso', null)
24107 .on('mouseup.lasso', null);
24109 if (!lasso) return;
24111 var graph = context.graph(),
24112 extent = iD.geo.Extent(
24113 normalize(context.projection.invert(lasso.a()),
24114 context.projection.invert(lasso.b())));
24118 var selected = context.intersects(extent).filter(function(entity) {
24119 return entity.type === 'node' &&
24120 !context.features().isHidden(entity, graph, entity.geometry(graph));
24123 if (selected.length) {
24124 context.enter(iD.modes.Select(context, _.pluck(selected, 'id')));
24129 .on('mousedown.lasso', mousedown);
24132 behavior.off = function(selection) {
24133 selection.on('mousedown.lasso', null);
24138 iD.behavior.Paste = function(context) {
24139 var keybinding = d3.keybinding('paste');
24141 function omitTag(v, k) {
24149 k === 'description' ||
24150 k.indexOf('name') !== -1 ||
24151 k.indexOf('wiki') === 0 ||
24152 k.indexOf('addr:') === 0 ||
24153 k.indexOf('contact:') === 0
24157 function doPaste() {
24158 d3.event.preventDefault();
24159 if (context.inIntro()) return;
24161 var baseGraph = context.graph(),
24162 mouse = context.mouse(),
24163 projection = context.projection,
24164 viewport = iD.geo.Extent(projection.clipExtent()).polygon();
24166 if (!iD.geo.pointInPolygon(mouse, viewport)) return;
24168 var extent = iD.geo.Extent(),
24169 oldIDs = context.copyIDs(),
24170 oldGraph = context.copyGraph(),
24173 if (!oldIDs.length) return;
24175 var action = iD.actions.CopyEntities(oldIDs, oldGraph);
24176 context.perform(action);
24178 var copies = action.copies();
24179 for (var id in copies) {
24180 var oldEntity = oldGraph.entity(id),
24181 newEntity = copies[id];
24183 extent._extend(oldEntity.extent(oldGraph));
24184 newIDs.push(newEntity.id);
24185 context.perform(iD.actions.ChangeTags(newEntity.id, _.omit(newEntity.tags, omitTag)));
24188 // Put pasted objects where mouse pointer is..
24189 var center = projection(extent.center()),
24190 delta = [ mouse[0] - center[0], mouse[1] - center[1] ];
24192 context.perform(iD.actions.Move(newIDs, delta, projection));
24193 context.enter(iD.modes.Move(context, newIDs, baseGraph));
24197 keybinding.on(iD.ui.cmd('⌘V'), doPaste);
24198 d3.select(document).call(keybinding);
24202 paste.off = function() {
24203 d3.select(document).call(keybinding.off);
24208 iD.behavior.Select = function(context) {
24209 function keydown() {
24210 if (d3.event && d3.event.shiftKey) {
24212 .classed('behavior-multiselect', true);
24217 if (!d3.event || !d3.event.shiftKey) {
24219 .classed('behavior-multiselect', false);
24224 var datum = d3.event.target.__data__,
24225 lasso = d3.select('#surface .lasso').node(),
24226 mode = context.mode();
24228 if (!(datum instanceof iD.Entity)) {
24229 if (!d3.event.shiftKey && !lasso && mode.id !== 'browse')
24230 context.enter(iD.modes.Browse(context));
24232 } else if (!d3.event.shiftKey && !lasso) {
24233 // Avoid re-entering Select mode with same entity.
24234 if (context.selectedIDs().length !== 1 || context.selectedIDs()[0] !== datum.id) {
24235 context.enter(iD.modes.Select(context, [datum.id]));
24237 mode.suppressMenu(false).reselect();
24239 } else if (context.selectedIDs().indexOf(datum.id) >= 0) {
24240 var selectedIDs = _.without(context.selectedIDs(), datum.id);
24241 context.enter(selectedIDs.length ?
24242 iD.modes.Select(context, selectedIDs) :
24243 iD.modes.Browse(context));
24246 context.enter(iD.modes.Select(context, context.selectedIDs().concat([datum.id])));
24250 var behavior = function(selection) {
24252 .on('keydown.select', keydown)
24253 .on('keyup.select', keyup);
24255 selection.on('click.select', click);
24260 behavior.off = function(selection) {
24262 .on('keydown.select', null)
24263 .on('keyup.select', null);
24265 selection.on('click.select', null);
24272 iD.behavior.Tail = function() {
24276 tooltipSize = [0, 0],
24277 selectionSize = [0, 0];
24279 function tail(selection) {
24283 .on('resize.tail', function() { selectionSize = selection.dimensions(); });
24286 container.style('display', 'block');
24287 tooltipSize = container.dimensions();
24290 function mousemove() {
24291 if (container.style('display') === 'none') show();
24292 var xoffset = ((d3.event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
24293 -tooltipSize[0] - xmargin : xmargin;
24294 container.classed('left', xoffset > 0);
24295 iD.util.setTransform(container, d3.event.clientX + xoffset, d3.event.clientY);
24298 function mouseleave() {
24299 if (d3.event.relatedTarget !== container.node()) {
24300 container.style('display', 'none');
24304 function mouseenter() {
24305 if (d3.event.relatedTarget !== container.node()) {
24310 container = d3.select(document.body)
24312 .style('display', 'none')
24313 .attr('class', 'tail tooltip-inner');
24315 container.append('div')
24319 .on('mousemove.tail', mousemove)
24320 .on('mouseenter.tail', mouseenter)
24321 .on('mouseleave.tail', mouseleave);
24324 .on('mousemove.tail', mousemove);
24326 tooltipSize = container.dimensions();
24327 selectionSize = selection.dimensions();
24330 tail.off = function(selection) {
24334 .on('mousemove.tail', null)
24338 .on('mousemove.tail', null)
24339 .on('mouseenter.tail', null)
24340 .on('mouseleave.tail', null);
24343 .on('resize.tail', null);
24346 tail.text = function(_) {
24347 if (!arguments.length) return text;
24355 iD.modes.AddArea = function(context) {
24359 title: t('modes.add_area.title'),
24360 description: t('modes.add_area.description'),
24364 var behavior = iD.behavior.AddWay(context)
24365 .tail(t('modes.add_area.tail'))
24366 .on('start', start)
24367 .on('startFromWay', startFromWay)
24368 .on('startFromNode', startFromNode),
24369 defaultTags = {area: 'yes'};
24371 function start(loc) {
24372 var graph = context.graph(),
24373 node = iD.Node({loc: loc}),
24374 way = iD.Way({tags: defaultTags});
24377 iD.actions.AddEntity(node),
24378 iD.actions.AddEntity(way),
24379 iD.actions.AddVertex(way.id, node.id),
24380 iD.actions.AddVertex(way.id, node.id));
24382 context.enter(iD.modes.DrawArea(context, way.id, graph));
24385 function startFromWay(loc, edge) {
24386 var graph = context.graph(),
24387 node = iD.Node({loc: loc}),
24388 way = iD.Way({tags: defaultTags});
24391 iD.actions.AddEntity(node),
24392 iD.actions.AddEntity(way),
24393 iD.actions.AddVertex(way.id, node.id),
24394 iD.actions.AddVertex(way.id, node.id),
24395 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
24397 context.enter(iD.modes.DrawArea(context, way.id, graph));
24400 function startFromNode(node) {
24401 var graph = context.graph(),
24402 way = iD.Way({tags: defaultTags});
24405 iD.actions.AddEntity(way),
24406 iD.actions.AddVertex(way.id, node.id),
24407 iD.actions.AddVertex(way.id, node.id));
24409 context.enter(iD.modes.DrawArea(context, way.id, graph));
24412 mode.enter = function() {
24413 context.install(behavior);
24416 mode.exit = function() {
24417 context.uninstall(behavior);
24422 iD.modes.AddLine = function(context) {
24426 title: t('modes.add_line.title'),
24427 description: t('modes.add_line.description'),
24431 var behavior = iD.behavior.AddWay(context)
24432 .tail(t('modes.add_line.tail'))
24433 .on('start', start)
24434 .on('startFromWay', startFromWay)
24435 .on('startFromNode', startFromNode);
24437 function start(loc) {
24438 var baseGraph = context.graph(),
24439 node = iD.Node({loc: loc}),
24443 iD.actions.AddEntity(node),
24444 iD.actions.AddEntity(way),
24445 iD.actions.AddVertex(way.id, node.id));
24447 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24450 function startFromWay(loc, edge) {
24451 var baseGraph = context.graph(),
24452 node = iD.Node({loc: loc}),
24456 iD.actions.AddEntity(node),
24457 iD.actions.AddEntity(way),
24458 iD.actions.AddVertex(way.id, node.id),
24459 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
24461 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24464 function startFromNode(node) {
24465 var baseGraph = context.graph(),
24469 iD.actions.AddEntity(way),
24470 iD.actions.AddVertex(way.id, node.id));
24472 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24475 mode.enter = function() {
24476 context.install(behavior);
24479 mode.exit = function() {
24480 context.uninstall(behavior);
24485 iD.modes.AddPoint = function(context) {
24489 title: t('modes.add_point.title'),
24490 description: t('modes.add_point.description'),
24494 var behavior = iD.behavior.Draw(context)
24495 .tail(t('modes.add_point.tail'))
24497 .on('clickWay', addWay)
24498 .on('clickNode', addNode)
24499 .on('cancel', cancel)
24500 .on('finish', cancel);
24502 function add(loc) {
24503 var node = iD.Node({loc: loc});
24506 iD.actions.AddEntity(node),
24507 t('operations.add.annotation.point'));
24510 iD.modes.Select(context, [node.id])
24511 .suppressMenu(true)
24512 .newFeature(true));
24515 function addWay(loc) {
24519 function addNode(node) {
24523 function cancel() {
24524 context.enter(iD.modes.Browse(context));
24527 mode.enter = function() {
24528 context.install(behavior);
24531 mode.exit = function() {
24532 context.uninstall(behavior);
24537 iD.modes.Browse = function(context) {
24541 title: t('modes.browse.title'),
24542 description: t('modes.browse.description')
24546 iD.behavior.Paste(context),
24547 iD.behavior.Hover(context)
24548 .on('hover', context.ui().sidebar.hover),
24549 iD.behavior.Select(context),
24550 iD.behavior.Lasso(context),
24551 iD.modes.DragNode(context).behavior];
24553 mode.enter = function() {
24554 behaviors.forEach(function(behavior) {
24555 context.install(behavior);
24558 // Get focus on the body.
24559 if (document.activeElement && document.activeElement.blur) {
24560 document.activeElement.blur();
24564 context.ui().sidebar.show(sidebar);
24566 context.ui().sidebar.select(null);
24570 mode.exit = function() {
24571 context.ui().sidebar.hover.cancel();
24572 behaviors.forEach(function(behavior) {
24573 context.uninstall(behavior);
24577 context.ui().sidebar.hide();
24581 mode.sidebar = function(_) {
24582 if (!arguments.length) return sidebar;
24589 iD.modes.DragNode = function(context) {
24600 hover = iD.behavior.Hover(context)
24602 .on('hover', context.ui().sidebar.hover),
24603 edit = iD.behavior.Edit(context);
24605 function edge(point, size) {
24606 var pad = [30, 100, 30, 100];
24607 if (point[0] > size[0] - pad[0]) return [-10, 0];
24608 else if (point[0] < pad[2]) return [10, 0];
24609 else if (point[1] > size[1] - pad[1]) return [0, -10];
24610 else if (point[1] < pad[3]) return [0, 10];
24614 function startNudge(nudge) {
24615 if (nudgeInterval) window.clearInterval(nudgeInterval);
24616 nudgeInterval = window.setInterval(function() {
24617 context.pan(nudge);
24621 function stopNudge() {
24622 if (nudgeInterval) window.clearInterval(nudgeInterval);
24623 nudgeInterval = null;
24626 function moveAnnotation(entity) {
24627 return t('operations.move.annotation.' + entity.geometry(context.graph()));
24630 function connectAnnotation(entity) {
24631 return t('operations.connect.annotation.' + entity.geometry(context.graph()));
24634 function origin(entity) {
24635 return context.projection(entity.loc);
24638 function start(entity) {
24639 cancelled = d3.event.sourceEvent.shiftKey ||
24640 context.features().hasHiddenConnections(entity, context.graph());
24642 if (cancelled) return behavior.cancel();
24644 wasMidpoint = entity.type === 'midpoint';
24646 var midpoint = entity;
24647 entity = iD.Node();
24648 context.perform(iD.actions.AddMidpoint(midpoint, entity));
24650 var vertex = context.surface()
24651 .selectAll('.' + entity.id);
24652 behavior.target(vertex.node(), entity);
24656 iD.actions.Noop());
24659 activeIDs = _.pluck(context.graph().parentWays(entity), 'id');
24660 activeIDs.push(entity.id);
24662 context.enter(mode);
24666 if (d3.event.sourceEvent.altKey) {
24670 return d3.event.sourceEvent.target.__data__ || {};
24673 // via https://gist.github.com/shawnbot/4166283
24674 function childOf(p, c) {
24675 if (p === c) return false;
24676 while (c && c !== p) c = c.parentNode;
24680 function move(entity) {
24681 if (cancelled) return;
24682 d3.event.sourceEvent.stopPropagation();
24684 var nudge = childOf(context.container().node(),
24685 d3.event.sourceEvent.toElement) &&
24686 edge(d3.event.point, context.map().dimensions());
24688 if (nudge) startNudge(nudge);
24691 var loc = context.map().mouseCoordinates();
24694 if (d.type === 'node' && d.id !== entity.id) {
24696 } else if (d.type === 'way' && !d3.select(d3.event.sourceEvent.target).classed('fill')) {
24697 loc = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
24701 iD.actions.MoveNode(entity.id, loc),
24702 moveAnnotation(entity));
24705 function end(entity) {
24706 if (cancelled) return;
24710 if (d.type === 'way') {
24711 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection);
24713 iD.actions.AddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
24714 connectAnnotation(d));
24716 } else if (d.type === 'node' && d.id !== entity.id) {
24718 iD.actions.Connect([d.id, entity.id]),
24719 connectAnnotation(d));
24721 } else if (wasMidpoint) {
24724 t('operations.add.annotation.vertex'));
24729 moveAnnotation(entity));
24732 var reselection = selectedIDs.filter(function(id) {
24733 return context.graph().hasEntity(id);
24736 if (reselection.length) {
24738 iD.modes.Select(context, reselection)
24739 .suppressMenu(true));
24741 context.enter(iD.modes.Browse(context));
24745 function cancel() {
24747 context.enter(iD.modes.Browse(context));
24750 function setActiveElements() {
24751 context.surface().selectAll(iD.util.entitySelector(activeIDs))
24752 .classed('active', true);
24755 var behavior = iD.behavior.drag()
24756 .delegate('g.node, g.point, g.midpoint')
24757 .surface(context.surface().node())
24759 .on('start', start)
24763 mode.enter = function() {
24764 context.install(hover);
24765 context.install(edit);
24768 .on('undone.drag-node', cancel);
24771 .on('drawn.drag-node', setActiveElements);
24773 setActiveElements();
24776 mode.exit = function() {
24777 context.ui().sidebar.hover.cancel();
24778 context.uninstall(hover);
24779 context.uninstall(edit);
24782 .on('undone.drag-node', null);
24785 .on('drawn.drag-node', null);
24788 .selectAll('.active')
24789 .classed('active', false);
24794 mode.selectedIDs = function(_) {
24795 if (!arguments.length) return selectedIDs;
24800 mode.behavior = behavior;
24804 iD.modes.DrawArea = function(context, wayId, baseGraph) {
24812 mode.enter = function() {
24813 var way = context.entity(wayId),
24814 headId = way.nodes[way.nodes.length - 2],
24815 tailId = way.first();
24817 behavior = iD.behavior.DrawWay(context, wayId, -1, mode, baseGraph)
24818 .tail(t('modes.draw_area.tail'));
24820 var addNode = behavior.addNode;
24822 behavior.addNode = function(node) {
24823 if (node.id === headId || node.id === tailId) {
24830 context.install(behavior);
24833 mode.exit = function() {
24834 context.uninstall(behavior);
24837 mode.selectedIDs = function() {
24843 iD.modes.DrawLine = function(context, wayId, baseGraph, affix) {
24851 mode.enter = function() {
24852 var way = context.entity(wayId),
24853 index = (affix === 'prefix') ? 0 : undefined,
24854 headId = (affix === 'prefix') ? way.first() : way.last();
24856 behavior = iD.behavior.DrawWay(context, wayId, index, mode, baseGraph)
24857 .tail(t('modes.draw_line.tail'));
24859 var addNode = behavior.addNode;
24861 behavior.addNode = function(node) {
24862 if (node.id === headId) {
24869 context.install(behavior);
24872 mode.exit = function() {
24873 context.uninstall(behavior);
24876 mode.selectedIDs = function() {
24882 iD.modes.Move = function(context, entityIDs, baseGraph) {
24888 var keybinding = d3.keybinding('move'),
24889 edit = iD.behavior.Edit(context),
24890 annotation = entityIDs.length === 1 ?
24891 t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
24892 t('operations.move.annotation.multiple'),
24897 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
24899 function edge(point, size) {
24900 var pad = [30, 100, 30, 100];
24901 if (point[0] > size[0] - pad[0]) return [-10, 0];
24902 else if (point[0] < pad[2]) return [10, 0];
24903 else if (point[1] > size[1] - pad[1]) return [0, -10];
24904 else if (point[1] < pad[3]) return [0, 10];
24908 function startNudge(nudge) {
24909 if (nudgeInterval) window.clearInterval(nudgeInterval);
24910 nudgeInterval = window.setInterval(function() {
24911 context.pan(nudge);
24913 var currMouse = context.mouse(),
24914 origMouse = context.projection(origin),
24915 delta = vecSub(vecSub(currMouse, origMouse), nudge),
24916 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
24918 context.overwrite(action, annotation);
24923 function stopNudge() {
24924 if (nudgeInterval) window.clearInterval(nudgeInterval);
24925 nudgeInterval = null;
24929 var currMouse = context.mouse(),
24930 origMouse = context.projection(origin),
24931 delta = vecSub(currMouse, origMouse),
24932 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
24934 context.overwrite(action, annotation);
24936 var nudge = edge(currMouse, context.map().dimensions());
24937 if (nudge) startNudge(nudge);
24941 function finish() {
24942 d3.event.stopPropagation();
24943 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
24947 function cancel() {
24949 while (context.graph() !== baseGraph) context.pop();
24950 context.enter(iD.modes.Browse(context));
24953 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
24958 function undone() {
24959 context.enter(iD.modes.Browse(context));
24962 mode.enter = function() {
24963 origin = context.map().mouseCoordinates();
24966 context.install(edit);
24973 .on('mousemove.move', move)
24974 .on('click.move', finish);
24977 .on('undone.move', undone);
24983 d3.select(document)
24987 mode.exit = function() {
24990 context.uninstall(edit);
24993 .on('mousemove.move', null)
24994 .on('click.move', null);
24997 .on('undone.move', null);
25004 iD.modes.RotateWay = function(context, wayId) {
25010 var keybinding = d3.keybinding('rotate-way'),
25011 edit = iD.behavior.Edit(context);
25013 mode.enter = function() {
25014 context.install(edit);
25016 var annotation = t('operations.rotate.annotation.' + context.geometry(wayId)),
25017 way = context.graph().entity(wayId),
25018 nodes = _.uniq(context.graph().childNodes(way)),
25019 points = nodes.map(function(n) { return context.projection(n.loc); }),
25020 pivot = d3.geom.polygon(points).centroid(),
25027 function rotate() {
25029 var mousePoint = context.mouse(),
25030 newAngle = Math.atan2(mousePoint[1] - pivot[1], mousePoint[0] - pivot[0]);
25032 if (typeof angle === 'undefined') angle = newAngle;
25035 iD.actions.RotateWay(wayId, pivot, newAngle - angle, context.projection),
25041 function finish() {
25042 d3.event.stopPropagation();
25043 context.enter(iD.modes.Select(context, [wayId])
25044 .suppressMenu(true));
25047 function cancel() {
25049 context.enter(iD.modes.Select(context, [wayId])
25050 .suppressMenu(true));
25053 function undone() {
25054 context.enter(iD.modes.Browse(context));
25058 .on('mousemove.rotate-way', rotate)
25059 .on('click.rotate-way', finish);
25062 .on('undone.rotate-way', undone);
25068 d3.select(document)
25072 mode.exit = function() {
25073 context.uninstall(edit);
25076 .on('mousemove.rotate-way', null)
25077 .on('click.rotate-way', null);
25080 .on('undone.rotate-way', null);
25087 iD.modes.Save = function(context) {
25088 var ui = iD.ui.Commit(context)
25089 .on('cancel', cancel)
25092 function cancel() {
25093 context.enter(iD.modes.Browse(context));
25096 function save(e, tryAgain) {
25097 function withChildNodes(ids, graph) {
25098 return _.uniq(_.reduce(ids, function(result, id) {
25099 var e = graph.entity(id);
25100 if (e.type === 'way') {
25102 var cn = graph.childNodes(e);
25103 result.push.apply(result, _.pluck(_.filter(cn, 'version'), 'id'));
25105 /* eslint-disable no-console */
25106 if (typeof console !== 'undefined') console.error(err);
25107 /* eslint-enable no-console */
25114 var loading = iD.ui.Loading(context).message(t('save.uploading')).blocking(true),
25115 history = context.history(),
25116 origChanges = history.changes(iD.actions.DiscardTags(history.difference())),
25117 localGraph = context.graph(),
25118 remoteGraph = iD.Graph(history.base(), true),
25119 modified = _.filter(history.difference().summary(), {changeType: 'modified'}),
25120 toCheck = _.pluck(_.pluck(modified, 'entity'), 'id'),
25121 toLoad = withChildNodes(toCheck, localGraph),
25125 if (!tryAgain) history.perform(iD.actions.Noop()); // checkpoint
25126 context.container().call(loading);
25128 if (toCheck.length) {
25129 context.connection().loadMultiple(toLoad, loaded);
25135 // Reload modified entities into an alternate graph and check for conflicts..
25136 function loaded(err, result) {
25137 if (errors.length) return;
25141 msg: err.responseText,
25142 details: [ t('save.status_code', { code: err.status }) ]
25148 _.each(result.data, function(entity) {
25149 remoteGraph.replace(entity);
25150 toLoad = _.without(toLoad, entity.id);
25152 // Because loadMultiple doesn't download /full like loadEntity,
25153 // need to also load children that aren't already being checked..
25154 if (!entity.visible) return;
25155 if (entity.type === 'way') {
25156 loadMore.push.apply(loadMore,
25157 _.difference(entity.nodes, toCheck, toLoad, loadMore));
25158 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
25159 loadMore.push.apply(loadMore,
25160 _.difference(_.pluck(entity.members, 'id'), toCheck, toLoad, loadMore));
25164 if (loadMore.length) {
25165 toLoad.push.apply(toLoad, loadMore);
25166 context.connection().loadMultiple(loadMore, loaded);
25169 if (!toLoad.length) {
25176 function checkConflicts() {
25177 function choice(id, text, action) {
25178 return { id: id, text: text, action: function() { history.replace(action); } };
25180 function formatUser(d) {
25181 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
25183 function entityName(entity) {
25184 return iD.util.displayName(entity) || (iD.util.displayType(entity.id) + ' ' + entity.id);
25187 function compareVersions(local, remote) {
25188 if (local.version !== remote.version) return false;
25190 if (local.type === 'way') {
25191 var children = _.union(local.nodes, remote.nodes);
25193 for (var i = 0; i < children.length; i++) {
25194 var a = localGraph.hasEntity(children[i]),
25195 b = remoteGraph.hasEntity(children[i]);
25197 if (a && b && a.version !== b.version) return false;
25204 _.each(toCheck, function(id) {
25205 var local = localGraph.entity(id),
25206 remote = remoteGraph.entity(id);
25208 if (compareVersions(local, remote)) return;
25210 var action = iD.actions.MergeRemoteChanges,
25211 merge = action(id, localGraph, remoteGraph, formatUser);
25213 history.replace(merge);
25215 var mergeConflicts = merge.conflicts();
25216 if (!mergeConflicts.length) return; // merged safely
25218 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
25219 forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
25220 keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
25221 keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
25225 name: entityName(local),
25226 details: mergeConflicts,
25229 choice(id, keepMine, forceLocal),
25230 choice(id, keepTheirs, forceRemote)
25239 function finalize() {
25240 if (conflicts.length) {
25241 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
25243 } else if (errors.length) {
25246 var changes = history.changes(iD.actions.DiscardTags(history.difference()));
25247 if (changes.modified.length || changes.created.length || changes.deleted.length) {
25248 context.connection().putChangeset(
25251 history.imageryUsed(),
25252 function(err, changeset_id) {
25255 msg: err.responseText,
25256 details: [ t('save.status_code', { code: err.status }) ]
25260 history.clearSaved();
25261 success(e, changeset_id);
25262 // Add delay to allow for postgres replication #1646 #2678
25263 window.setTimeout(function() {
25269 } else { // changes were insignificant or reverted by user
25278 function showConflicts() {
25279 var selection = context.container()
25280 .select('#sidebar')
25282 .attr('class','sidebar-component');
25286 selection.call(iD.ui.Conflicts(context)
25288 .on('download', function() {
25289 var data = JXON.stringify(context.connection().osmChangeJXON('CHANGEME', origChanges)),
25290 win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
25293 .on('cancel', function() {
25295 selection.remove();
25297 .on('save', function() {
25298 for (var i = 0; i < conflicts.length; i++) {
25299 if (conflicts[i].chosen === 1) { // user chose "keep theirs"
25300 var entity = context.hasEntity(conflicts[i].id);
25301 if (entity && entity.type === 'way') {
25302 var children = _.uniq(entity.nodes);
25303 for (var j = 0; j < children.length; j++) {
25304 history.replace(iD.actions.Revert(children[j]));
25307 history.replace(iD.actions.Revert(conflicts[i].id));
25311 selection.remove();
25318 function showErrors() {
25319 var selection = iD.ui.confirm(context.container());
25325 .select('.modal-section.header')
25327 .text(t('save.error'));
25329 addErrors(selection, errors);
25330 selection.okButton();
25334 function addErrors(selection, data) {
25335 var message = selection
25336 .select('.modal-section.message-text');
25338 var items = message
25339 .selectAll('.error-container')
25342 var enter = items.enter()
25344 .attr('class', 'error-container');
25348 .attr('class', 'error-description')
25350 .classed('hide-toggle', true)
25351 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
25352 .on('click', function() {
25353 var error = d3.select(this),
25354 detail = d3.select(this.nextElementSibling),
25355 exp = error.classed('expanded');
25357 detail.style('display', exp ? 'none' : 'block');
25358 error.classed('expanded', !exp);
25360 d3.event.preventDefault();
25363 var details = enter
25365 .attr('class', 'error-detail-container')
25366 .style('display', 'none');
25370 .attr('class', 'error-detail-list')
25372 .data(function(d) { return d.details || []; })
25375 .attr('class', 'error-detail-item')
25376 .text(function(d) { return d; });
25385 function success(e, changeset_id) {
25386 context.enter(iD.modes.Browse(context)
25387 .sidebar(iD.ui.Success(context)
25392 .on('cancel', function() {
25393 context.ui().sidebar.hide();
25401 mode.enter = function() {
25402 context.connection().authenticate(function(err) {
25406 context.ui().sidebar.show(ui);
25411 mode.exit = function() {
25412 context.ui().sidebar.hide();
25417 iD.modes.Select = function(context, selectedIDs) {
25423 var keybinding = d3.keybinding('select'),
25426 iD.behavior.Copy(context),
25427 iD.behavior.Paste(context),
25428 iD.behavior.Breathe(context),
25429 iD.behavior.Hover(context),
25430 iD.behavior.Select(context),
25431 iD.behavior.Lasso(context),
25432 iD.modes.DragNode(context)
25433 .selectedIDs(selectedIDs)
25437 newFeature = false,
25438 suppressMenu = false;
25440 var wrap = context.container()
25441 .select('.inspector-wrap');
25444 function singular() {
25445 if (selectedIDs.length === 1) {
25446 return context.hasEntity(selectedIDs[0]);
25450 function closeMenu() {
25452 context.surface().call(radialMenu.close);
25456 function positionMenu() {
25457 if (suppressMenu || !radialMenu) { return; }
25459 var entity = singular();
25460 if (entity && context.geometry(entity.id) === 'relation') {
25461 suppressMenu = true;
25462 } else if (entity && entity.type === 'node') {
25463 radialMenu.center(context.projection(entity.loc));
25465 var point = context.mouse(),
25466 viewport = iD.geo.Extent(context.projection.clipExtent()).polygon();
25467 if (iD.geo.pointInPolygon(point, viewport)) {
25468 radialMenu.center(point);
25470 suppressMenu = true;
25475 function showMenu() {
25477 if (!suppressMenu && radialMenu) {
25478 context.surface().call(radialMenu);
25482 function toggleMenu() {
25483 if (d3.select('.radial-menu').empty()) {
25490 mode.selectedIDs = function() {
25491 return selectedIDs;
25494 mode.reselect = function() {
25495 var surfaceNode = context.surface().node();
25496 if (surfaceNode.focus) { // FF doesn't support it
25497 surfaceNode.focus();
25504 mode.newFeature = function(_) {
25505 if (!arguments.length) return newFeature;
25510 mode.suppressMenu = function(_) {
25511 if (!arguments.length) return suppressMenu;
25516 mode.enter = function() {
25517 function update() {
25519 if (_.any(selectedIDs, function(id) { return !context.hasEntity(id); })) {
25520 // Exit mode if selected entity gets undone
25521 context.enter(iD.modes.Browse(context));
25525 function dblclick() {
25526 var target = d3.select(d3.event.target),
25527 datum = target.datum();
25529 if (datum instanceof iD.Way && !target.classed('fill')) {
25530 var choice = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection),
25533 var prev = datum.nodes[choice.index - 1],
25534 next = datum.nodes[choice.index];
25537 iD.actions.AddMidpoint({loc: choice.loc, edge: [prev, next]}, node),
25538 t('operations.add.annotation.vertex'));
25540 d3.event.preventDefault();
25541 d3.event.stopPropagation();
25545 function selectElements(drawn) {
25546 var entity = singular();
25547 if (entity && context.geometry(entity.id) === 'relation') {
25548 suppressMenu = true;
25552 var selection = context.surface()
25553 .selectAll(iD.util.entityOrMemberSelector(selectedIDs, context.graph()));
25555 if (selection.empty()) {
25556 if (drawn) { // Exit mode if selected DOM elements have disappeared..
25557 context.enter(iD.modes.Browse(context));
25561 .classed('selected', true);
25566 if (!context.inIntro()) {
25567 context.enter(iD.modes.Browse(context));
25572 behaviors.forEach(function(behavior) {
25573 context.install(behavior);
25576 var operations = _.without(d3.values(iD.operations), iD.operations.Delete)
25577 .map(function(o) { return o(selectedIDs, context); })
25578 .filter(function(o) { return o.available(); });
25580 operations.unshift(iD.operations.Delete(selectedIDs, context));
25583 .on('⎋', esc, true)
25584 .on('space', toggleMenu);
25586 operations.forEach(function(operation) {
25587 operation.keys.forEach(function(key) {
25588 keybinding.on(key, function() {
25589 if (!(context.inIntro() || operation.disabled())) {
25596 d3.select(document)
25599 radialMenu = iD.ui.RadialMenu(context, operations);
25601 context.ui().sidebar
25602 .select(singular() ? singular().id : null, newFeature);
25605 .on('undone.select', update)
25606 .on('redone.select', update);
25609 .on('move.select', closeMenu)
25610 .on('drawn.select', selectElements);
25614 var show = d3.event && !suppressMenu;
25620 timeout = window.setTimeout(function() {
25626 .on('dblclick.select', dblclick);
25629 if (selectedIDs.length > 1) {
25630 var entities = iD.ui.SelectionList(context, selectedIDs);
25631 context.ui().sidebar.show(entities);
25635 mode.exit = function() {
25636 if (timeout) window.clearTimeout(timeout);
25638 if (inspector) wrap.call(inspector.close);
25640 behaviors.forEach(function(behavior) {
25641 context.uninstall(behavior);
25646 radialMenu = undefined;
25649 .on('undone.select', null)
25650 .on('redone.select', null);
25653 .on('dblclick.select', null)
25654 .selectAll('.selected')
25655 .classed('selected', false);
25657 context.map().on('drawn.select', null);
25658 context.ui().sidebar.hide();
25663 iD.operations = {};
25664 iD.operations.Circularize = function(selectedIDs, context) {
25665 var entityId = selectedIDs[0],
25666 entity = context.entity(entityId),
25667 extent = entity.extent(context.graph()),
25668 geometry = context.geometry(entityId),
25669 action = iD.actions.Circularize(entityId, context.projection);
25671 var operation = function() {
25672 var annotation = t('operations.circularize.annotation.' + geometry);
25673 context.perform(action, annotation);
25676 operation.available = function() {
25677 return selectedIDs.length === 1 &&
25678 entity.type === 'way' &&
25679 _.uniq(entity.nodes).length > 1;
25682 operation.disabled = function() {
25684 if (extent.percentContainedIn(context.extent()) < 0.8) {
25685 reason = 'too_large';
25686 } else if (context.hasHiddenConnections(entityId)) {
25687 reason = 'connected_to_hidden';
25689 return action.disabled(context.graph()) || reason;
25692 operation.tooltip = function() {
25693 var disable = operation.disabled();
25695 t('operations.circularize.' + disable) :
25696 t('operations.circularize.description.' + geometry);
25699 operation.id = 'circularize';
25700 operation.keys = [t('operations.circularize.key')];
25701 operation.title = t('operations.circularize.title');
25705 iD.operations.Continue = function(selectedIDs, context) {
25706 var graph = context.graph(),
25707 entities = selectedIDs.map(function(id) { return graph.entity(id); }),
25708 geometries = _.extend({line: [], vertex: []},
25709 _.groupBy(entities, function(entity) { return entity.geometry(graph); })),
25710 vertex = geometries.vertex[0];
25712 function candidateWays() {
25713 return graph.parentWays(vertex).filter(function(parent) {
25714 return parent.geometry(graph) === 'line' &&
25715 parent.affix(vertex.id) &&
25716 (geometries.line.length === 0 || geometries.line[0] === parent);
25720 var operation = function() {
25721 var candidate = candidateWays()[0];
25722 context.enter(iD.modes.DrawLine(
25726 candidate.affix(vertex.id)));
25729 operation.available = function() {
25730 return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
25731 !context.features().hasHiddenConnections(vertex, context.graph());
25734 operation.disabled = function() {
25735 var candidates = candidateWays();
25736 if (candidates.length === 0)
25737 return 'not_eligible';
25738 if (candidates.length > 1)
25742 operation.tooltip = function() {
25743 var disable = operation.disabled();
25745 t('operations.continue.' + disable) :
25746 t('operations.continue.description');
25749 operation.id = 'continue';
25750 operation.keys = [t('operations.continue.key')];
25751 operation.title = t('operations.continue.title');
25755 iD.operations.Delete = function(selectedIDs, context) {
25756 var action = iD.actions.DeleteMultiple(selectedIDs);
25758 var operation = function() {
25762 if (selectedIDs.length > 1) {
25763 annotation = t('operations.delete.annotation.multiple', {n: selectedIDs.length});
25766 var id = selectedIDs[0],
25767 entity = context.entity(id),
25768 geometry = context.geometry(id),
25769 parents = context.graph().parentWays(entity),
25770 parent = parents[0];
25772 annotation = t('operations.delete.annotation.' + geometry);
25774 // Select the next closest node in the way.
25775 if (geometry === 'vertex' && parents.length === 1 && parent.nodes.length > 2) {
25776 var nodes = parent.nodes,
25777 i = nodes.indexOf(id);
25781 } else if (i === nodes.length - 1) {
25784 var a = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
25785 b = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
25786 i = a < b ? i - 1 : i + 1;
25789 nextSelectedID = nodes[i];
25793 if (nextSelectedID && context.hasEntity(nextSelectedID)) {
25794 context.enter(iD.modes.Select(context, [nextSelectedID]));
25796 context.enter(iD.modes.Browse(context));
25804 operation.available = function() {
25808 operation.disabled = function() {
25810 if (_.any(selectedIDs, context.hasHiddenConnections)) {
25811 reason = 'connected_to_hidden';
25813 return action.disabled(context.graph()) || reason;
25816 operation.tooltip = function() {
25817 var disable = operation.disabled();
25819 t('operations.delete.' + disable) :
25820 t('operations.delete.description');
25823 operation.id = 'delete';
25824 operation.keys = [iD.ui.cmd('⌘⌫'), iD.ui.cmd('⌘⌦')];
25825 operation.title = t('operations.delete.title');
25829 iD.operations.Disconnect = function(selectedIDs, context) {
25830 var vertices = _.filter(selectedIDs, function vertex(entityId) {
25831 return context.geometry(entityId) === 'vertex';
25834 var entityId = vertices[0],
25835 action = iD.actions.Disconnect(entityId);
25837 if (selectedIDs.length > 1) {
25838 action.limitWays(_.without(selectedIDs, entityId));
25841 var operation = function() {
25842 context.perform(action, t('operations.disconnect.annotation'));
25845 operation.available = function() {
25846 return vertices.length === 1;
25849 operation.disabled = function() {
25851 if (_.any(selectedIDs, context.hasHiddenConnections)) {
25852 reason = 'connected_to_hidden';
25854 return action.disabled(context.graph()) || reason;
25857 operation.tooltip = function() {
25858 var disable = operation.disabled();
25860 t('operations.disconnect.' + disable) :
25861 t('operations.disconnect.description');
25864 operation.id = 'disconnect';
25865 operation.keys = [t('operations.disconnect.key')];
25866 operation.title = t('operations.disconnect.title');
25870 iD.operations.Merge = function(selectedIDs, context) {
25871 var join = iD.actions.Join(selectedIDs),
25872 merge = iD.actions.Merge(selectedIDs),
25873 mergePolygon = iD.actions.MergePolygon(selectedIDs);
25875 var operation = function() {
25876 var annotation = t('operations.merge.annotation', {n: selectedIDs.length}),
25879 if (!join.disabled(context.graph())) {
25881 } else if (!merge.disabled(context.graph())) {
25884 action = mergePolygon;
25887 context.perform(action, annotation);
25888 context.enter(iD.modes.Select(context, selectedIDs.filter(function(id) { return context.hasEntity(id); }))
25889 .suppressMenu(true));
25892 operation.available = function() {
25893 return selectedIDs.length >= 2;
25896 operation.disabled = function() {
25897 return join.disabled(context.graph()) &&
25898 merge.disabled(context.graph()) &&
25899 mergePolygon.disabled(context.graph());
25902 operation.tooltip = function() {
25903 var j = join.disabled(context.graph()),
25904 m = merge.disabled(context.graph()),
25905 p = mergePolygon.disabled(context.graph());
25907 if (j === 'restriction' && m && p)
25908 return t('operations.merge.restriction', {relation: context.presets().item('type/restriction').name()});
25910 if (p === 'incomplete_relation' && j && m)
25911 return t('operations.merge.incomplete_relation');
25914 return t('operations.merge.' + j);
25916 return t('operations.merge.description');
25919 operation.id = 'merge';
25920 operation.keys = [t('operations.merge.key')];
25921 operation.title = t('operations.merge.title');
25925 iD.operations.Move = function(selectedIDs, context) {
25926 var extent = selectedIDs.reduce(function(extent, id) {
25927 return extent.extend(context.entity(id).extent(context.graph()));
25928 }, iD.geo.Extent());
25930 var operation = function() {
25931 context.enter(iD.modes.Move(context, selectedIDs));
25934 operation.available = function() {
25935 return selectedIDs.length > 1 ||
25936 context.entity(selectedIDs[0]).type !== 'node';
25939 operation.disabled = function() {
25941 if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
25942 reason = 'too_large';
25943 } else if (_.any(selectedIDs, context.hasHiddenConnections)) {
25944 reason = 'connected_to_hidden';
25946 return iD.actions.Move(selectedIDs).disabled(context.graph()) || reason;
25949 operation.tooltip = function() {
25950 var disable = operation.disabled();
25952 t('operations.move.' + disable) :
25953 t('operations.move.description');
25956 operation.id = 'move';
25957 operation.keys = [t('operations.move.key')];
25958 operation.title = t('operations.move.title');
25962 iD.operations.Orthogonalize = function(selectedIDs, context) {
25963 var entityId = selectedIDs[0],
25964 entity = context.entity(entityId),
25965 extent = entity.extent(context.graph()),
25966 geometry = context.geometry(entityId),
25967 action = iD.actions.Orthogonalize(entityId, context.projection);
25969 var operation = function() {
25970 var annotation = t('operations.orthogonalize.annotation.' + geometry);
25971 context.perform(action, annotation);
25974 operation.available = function() {
25975 return selectedIDs.length === 1 &&
25976 entity.type === 'way' &&
25977 entity.isClosed() &&
25978 _.uniq(entity.nodes).length > 2;
25981 operation.disabled = function() {
25983 if (extent.percentContainedIn(context.extent()) < 0.8) {
25984 reason = 'too_large';
25985 } else if (context.hasHiddenConnections(entityId)) {
25986 reason = 'connected_to_hidden';
25988 return action.disabled(context.graph()) || reason;
25991 operation.tooltip = function() {
25992 var disable = operation.disabled();
25994 t('operations.orthogonalize.' + disable) :
25995 t('operations.orthogonalize.description.' + geometry);
25998 operation.id = 'orthogonalize';
25999 operation.keys = [t('operations.orthogonalize.key')];
26000 operation.title = t('operations.orthogonalize.title');
26004 iD.operations.Reverse = function(selectedIDs, context) {
26005 var entityId = selectedIDs[0];
26007 var operation = function() {
26009 iD.actions.Reverse(entityId),
26010 t('operations.reverse.annotation'));
26013 operation.available = function() {
26014 return selectedIDs.length === 1 &&
26015 context.geometry(entityId) === 'line';
26018 operation.disabled = function() {
26022 operation.tooltip = function() {
26023 return t('operations.reverse.description');
26026 operation.id = 'reverse';
26027 operation.keys = [t('operations.reverse.key')];
26028 operation.title = t('operations.reverse.title');
26032 iD.operations.Rotate = function(selectedIDs, context) {
26033 var entityId = selectedIDs[0],
26034 entity = context.entity(entityId),
26035 extent = entity.extent(context.graph()),
26036 geometry = context.geometry(entityId);
26038 var operation = function() {
26039 context.enter(iD.modes.RotateWay(context, entityId));
26042 operation.available = function() {
26043 if (selectedIDs.length !== 1 || entity.type !== 'way')
26045 if (geometry === 'area')
26047 if (entity.isClosed() &&
26048 context.graph().parentRelations(entity).some(function(r) { return r.isMultipolygon(); }))
26053 operation.disabled = function() {
26054 if (extent.percentContainedIn(context.extent()) < 0.8) {
26055 return 'too_large';
26056 } else if (context.hasHiddenConnections(entityId)) {
26057 return 'connected_to_hidden';
26063 operation.tooltip = function() {
26064 var disable = operation.disabled();
26066 t('operations.rotate.' + disable) :
26067 t('operations.rotate.description');
26070 operation.id = 'rotate';
26071 operation.keys = [t('operations.rotate.key')];
26072 operation.title = t('operations.rotate.title');
26076 iD.operations.Split = function(selectedIDs, context) {
26077 var vertices = _.filter(selectedIDs, function vertex(entityId) {
26078 return context.geometry(entityId) === 'vertex';
26081 var entityId = vertices[0],
26082 action = iD.actions.Split(entityId);
26084 if (selectedIDs.length > 1) {
26085 action.limitWays(_.without(selectedIDs, entityId));
26088 var operation = function() {
26091 var ways = action.ways(context.graph());
26092 if (ways.length === 1) {
26093 annotation = t('operations.split.annotation.' + context.geometry(ways[0].id));
26095 annotation = t('operations.split.annotation.multiple', {n: ways.length});
26098 var difference = context.perform(action, annotation);
26099 context.enter(iD.modes.Select(context, difference.extantIDs()));
26102 operation.available = function() {
26103 return vertices.length === 1;
26106 operation.disabled = function() {
26108 if (_.any(selectedIDs, context.hasHiddenConnections)) {
26109 reason = 'connected_to_hidden';
26111 return action.disabled(context.graph()) || reason;
26114 operation.tooltip = function() {
26115 var disable = operation.disabled();
26117 return t('operations.split.' + disable);
26120 var ways = action.ways(context.graph());
26121 if (ways.length === 1) {
26122 return t('operations.split.description.' + context.geometry(ways[0].id));
26124 return t('operations.split.description.multiple');
26128 operation.id = 'split';
26129 operation.keys = [t('operations.split.key')];
26130 operation.title = t('operations.split.title');
26134 iD.operations.Straighten = function(selectedIDs, context) {
26135 var entityId = selectedIDs[0],
26136 action = iD.actions.Straighten(entityId, context.projection);
26138 function operation() {
26139 var annotation = t('operations.straighten.annotation');
26140 context.perform(action, annotation);
26143 operation.available = function() {
26144 var entity = context.entity(entityId);
26145 return selectedIDs.length === 1 &&
26146 entity.type === 'way' &&
26147 !entity.isClosed() &&
26148 _.uniq(entity.nodes).length > 2;
26151 operation.disabled = function() {
26153 if (context.hasHiddenConnections(entityId)) {
26154 reason = 'connected_to_hidden';
26156 return action.disabled(context.graph()) || reason;
26159 operation.tooltip = function() {
26160 var disable = operation.disabled();
26162 t('operations.straighten.' + disable) :
26163 t('operations.straighten.description');
26166 operation.id = 'straighten';
26167 operation.keys = [t('operations.straighten.key')];
26168 operation.title = t('operations.straighten.title');
26172 iD.Connection = function(useHttps) {
26173 if (typeof useHttps !== 'boolean') {
26174 useHttps = window.location.protocol === 'https:';
26177 var event = d3.dispatch('authenticating', 'authenticated', 'auth', 'loading', 'loaded'),
26178 protocol = useHttps ? 'https:' : 'http:',
26179 url = protocol + '//www.openstreetmap.org',
26185 url: protocol + '//www.openstreetmap.org',
26186 oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
26187 oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
26188 loading: authenticating,
26189 done: authenticated
26193 memberStr = 'member',
26196 relationStr = 'relation',
26201 connection.changesetURL = function(changesetId) {
26202 return url + '/changeset/' + changesetId;
26205 connection.changesetsURL = function(center, zoom) {
26206 var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
26207 return url + '/history#map=' +
26208 Math.floor(zoom) + '/' +
26209 center[1].toFixed(precision) + '/' +
26210 center[0].toFixed(precision);
26213 connection.entityURL = function(entity) {
26214 return url + '/' + entity.type + '/' + entity.osmId();
26217 connection.userURL = function(username) {
26218 return url + '/user/' + username;
26221 connection.loadFromURL = function(url, callback) {
26222 function done(err, dom) {
26223 return callback(err, parse(dom));
26225 return d3.xml(url).get(done);
26228 connection.loadEntity = function(id, callback) {
26229 var type = iD.Entity.id.type(id),
26230 osmID = iD.Entity.id.toOSM(id);
26232 connection.loadFromURL(
26233 url + '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
26234 function(err, entities) {
26235 if (callback) callback(err, {data: entities});
26239 connection.loadEntityVersion = function(id, version, callback) {
26240 var type = iD.Entity.id.type(id),
26241 osmID = iD.Entity.id.toOSM(id);
26243 connection.loadFromURL(
26244 url + '/api/0.6/' + type + '/' + osmID + '/' + version,
26245 function(err, entities) {
26246 if (callback) callback(err, {data: entities});
26250 connection.loadMultiple = function(ids, callback) {
26251 _.each(_.groupBy(_.uniq(ids), iD.Entity.id.type), function(v, k) {
26252 var type = k + 's',
26253 osmIDs = _.map(v, iD.Entity.id.toOSM);
26255 _.each(_.chunk(osmIDs, 150), function(arr) {
26256 connection.loadFromURL(
26257 url + '/api/0.6/' + type + '?' + type + '=' + arr.join(),
26258 function(err, entities) {
26259 if (callback) callback(err, {data: entities});
26265 function authenticating() {
26266 event.authenticating();
26269 function authenticated() {
26270 event.authenticated();
26273 function getLoc(attrs) {
26274 var lon = attrs.lon && attrs.lon.value,
26275 lat = attrs.lat && attrs.lat.value;
26276 return [parseFloat(lon), parseFloat(lat)];
26279 function getNodes(obj) {
26280 var elems = obj.getElementsByTagName(ndStr),
26281 nodes = new Array(elems.length);
26282 for (var i = 0, l = elems.length; i < l; i++) {
26283 nodes[i] = 'n' + elems[i].attributes.ref.value;
26288 function getTags(obj) {
26289 var elems = obj.getElementsByTagName(tagStr),
26291 for (var i = 0, l = elems.length; i < l; i++) {
26292 var attrs = elems[i].attributes;
26293 tags[attrs.k.value] = attrs.v.value;
26298 function getMembers(obj) {
26299 var elems = obj.getElementsByTagName(memberStr),
26300 members = new Array(elems.length);
26301 for (var i = 0, l = elems.length; i < l; i++) {
26302 var attrs = elems[i].attributes;
26304 id: attrs.type.value[0] + attrs.ref.value,
26305 type: attrs.type.value,
26306 role: attrs.role.value
26312 function getVisible(attrs) {
26313 return (!attrs.visible || attrs.visible.value !== 'false');
26317 node: function nodeData(obj) {
26318 var attrs = obj.attributes;
26319 return new iD.Node({
26320 id: iD.Entity.id.fromOSM(nodeStr, attrs.id.value),
26321 loc: getLoc(attrs),
26322 version: attrs.version.value,
26323 user: attrs.user && attrs.user.value,
26324 tags: getTags(obj),
26325 visible: getVisible(attrs)
26329 way: function wayData(obj) {
26330 var attrs = obj.attributes;
26331 return new iD.Way({
26332 id: iD.Entity.id.fromOSM(wayStr, attrs.id.value),
26333 version: attrs.version.value,
26334 user: attrs.user && attrs.user.value,
26335 tags: getTags(obj),
26336 nodes: getNodes(obj),
26337 visible: getVisible(attrs)
26341 relation: function relationData(obj) {
26342 var attrs = obj.attributes;
26343 return new iD.Relation({
26344 id: iD.Entity.id.fromOSM(relationStr, attrs.id.value),
26345 version: attrs.version.value,
26346 user: attrs.user && attrs.user.value,
26347 tags: getTags(obj),
26348 members: getMembers(obj),
26349 visible: getVisible(attrs)
26354 function parse(dom) {
26355 if (!dom || !dom.childNodes) return;
26357 var root = dom.childNodes[0],
26358 children = root.childNodes,
26361 for (var i = 0, l = children.length; i < l; i++) {
26362 var child = children[i],
26363 parser = parsers[child.nodeName];
26365 entities.push(parser(child));
26372 connection.authenticated = function() {
26373 return oauth.authenticated();
26376 // Generate Changeset XML. Returns a string.
26377 connection.changesetJXON = function(tags) {
26381 tag: _.map(tags, function(value, key) {
26382 return { '@k': key, '@v': value };
26391 // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
26392 // XML. Returns a string.
26393 connection.osmChangeJXON = function(changeset_id, changes) {
26394 function nest(x, order) {
26396 for (var i = 0; i < x.length; i++) {
26397 var tagName = Object.keys(x[i])[0];
26398 if (!groups[tagName]) groups[tagName] = [];
26399 groups[tagName].push(x[i][tagName]);
26402 order.forEach(function(o) {
26403 if (groups[o]) ordered[o] = groups[o];
26408 function rep(entity) {
26409 return entity.asJXON(changeset_id);
26415 '@generator': 'iD',
26416 'create': nest(changes.created.map(rep), ['node', 'way', 'relation']),
26417 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
26418 'delete': _.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {'@if-unused': true})
26423 connection.changesetTags = function(comment, imageryUsed) {
26424 var detected = iD.detect(),
26426 created_by: 'iD ' + iD.version,
26427 imagery_used: imageryUsed.join(';').substr(0, 255),
26428 host: (window.location.origin + window.location.pathname).substr(0, 255),
26429 locale: detected.locale
26433 tags.comment = comment.substr(0, 255);
26439 connection.putChangeset = function(changes, comment, imageryUsed, callback) {
26442 path: '/api/0.6/changeset/create',
26443 options: { header: { 'Content-Type': 'text/xml' } },
26444 content: JXON.stringify(connection.changesetJXON(connection.changesetTags(comment, imageryUsed)))
26445 }, function(err, changeset_id) {
26446 if (err) return callback(err);
26449 path: '/api/0.6/changeset/' + changeset_id + '/upload',
26450 options: { header: { 'Content-Type': 'text/xml' } },
26451 content: JXON.stringify(connection.osmChangeJXON(changeset_id, changes))
26453 if (err) return callback(err);
26454 // POST was successful, safe to call the callback.
26455 // Still attempt to close changeset, but ignore response because #2667
26456 // Add delay to allow for postgres replication #1646 #2678
26457 window.setTimeout(function() { callback(null, changeset_id); }, 2500);
26460 path: '/api/0.6/changeset/' + changeset_id + '/close',
26461 options: { header: { 'Content-Type': 'text/xml' } }
26462 }, d3.functor(true));
26467 connection.userDetails = function(callback) {
26469 callback(undefined, userDetails);
26473 function done(err, user_details) {
26474 if (err) return callback(err);
26476 var u = user_details.getElementsByTagName('user')[0],
26477 img = u.getElementsByTagName('img'),
26480 if (img && img[0] && img[0].getAttribute('href')) {
26481 image_url = img[0].getAttribute('href');
26485 display_name: u.attributes.display_name.value,
26486 image_url: image_url,
26487 id: u.attributes.id.value
26490 callback(undefined, userDetails);
26493 oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
26496 connection.userChangesets = function(callback) {
26497 connection.userDetails(function(err, user) {
26498 if (err) return callback(err);
26500 function done(changesets) {
26501 callback(undefined, Array.prototype.map.call(changesets.getElementsByTagName('changeset'),
26502 function (changeset) {
26503 return { tags: getTags(changeset) };
26507 d3.xml(url + '/api/0.6/changesets?user=' + user.id).get()
26509 .on('error', callback);
26513 connection.status = function(callback) {
26514 function done(capabilities) {
26515 var apiStatus = capabilities.getElementsByTagName('status');
26516 callback(undefined, apiStatus[0].getAttribute('api'));
26518 d3.xml(url + '/api/capabilities').get()
26520 .on('error', callback);
26523 function abortRequest(i) { i.abort(); }
26525 connection.tileZoom = function(_) {
26526 if (!arguments.length) return tileZoom;
26531 connection.loadTiles = function(projection, dimensions, callback) {
26535 var s = projection.scale() * 2 * Math.PI,
26536 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
26537 ts = 256 * Math.pow(2, z - tileZoom),
26539 s / 2 - projection.translate()[0],
26540 s / 2 - projection.translate()[1]];
26542 var tiles = d3.geo.tile()
26543 .scaleExtent([tileZoom, tileZoom])
26546 .translate(projection.translate())()
26547 .map(function(tile) {
26548 var x = tile[0] * ts - origin[0],
26549 y = tile[1] * ts - origin[1];
26552 id: tile.toString(),
26553 extent: iD.geo.Extent(
26554 projection.invert([x, y + ts]),
26555 projection.invert([x + ts, y]))
26559 function bboxUrl(tile) {
26560 return url + '/api/0.6/map?bbox=' + tile.extent.toParam();
26563 _.filter(inflight, function(v, i) {
26564 var wanted = _.find(tiles, function(tile) {
26565 return i === tile.id;
26567 if (!wanted) delete inflight[i];
26569 }).map(abortRequest);
26571 tiles.forEach(function(tile) {
26574 if (loadedTiles[id] || inflight[id]) return;
26576 if (_.isEmpty(inflight)) {
26580 inflight[id] = connection.loadFromURL(bboxUrl(tile), function(err, parsed) {
26581 loadedTiles[id] = true;
26582 delete inflight[id];
26584 if (callback) callback(err, _.extend({data: parsed}, tile));
26586 if (_.isEmpty(inflight)) {
26593 connection.switch = function(options) {
26595 oauth.options(_.extend({
26596 loading: authenticating,
26597 done: authenticated
26600 connection.flush();
26604 connection.toggle = function(_) {
26609 connection.flush = function() {
26610 userDetails = undefined;
26611 _.forEach(inflight, abortRequest);
26617 connection.loadedTiles = function(_) {
26618 if (!arguments.length) return loadedTiles;
26623 connection.logout = function() {
26624 userDetails = undefined;
26630 connection.authenticate = function(callback) {
26631 userDetails = undefined;
26632 function done(err, res) {
26634 if (callback) callback(err, res);
26636 return oauth.authenticate(done);
26639 return d3.rebind(connection, event, 'on');
26642 iD.Difference represents the difference between two graphs.
26643 It knows how to calculate the set of entities that were
26644 created, modified, or deleted, and also contains the logic
26645 for recursively extending a difference to the complete set
26646 of entities that will require a redraw, taking into account
26647 child and parent relationships.
26649 iD.Difference = function(base, head) {
26650 var changes = {}, length = 0;
26652 function changed(h, b) {
26653 return h !== b && !_.isEqual(_.omit(h, 'v'), _.omit(b, 'v'));
26656 _.each(head.entities, function(h, id) {
26657 var b = base.entities[id];
26658 if (changed(h, b)) {
26659 changes[id] = {base: b, head: h};
26664 _.each(base.entities, function(b, id) {
26665 var h = head.entities[id];
26666 if (!changes[id] && changed(h, b)) {
26667 changes[id] = {base: b, head: h};
26672 function addParents(parents, result) {
26673 for (var i = 0; i < parents.length; i++) {
26674 var parent = parents[i];
26676 if (parent.id in result)
26679 result[parent.id] = parent;
26680 addParents(head.parentRelations(parent), result);
26684 var difference = {};
26686 difference.length = function() {
26690 difference.changes = function() {
26694 difference.extantIDs = function() {
26696 _.each(changes, function(change, id) {
26697 if (change.head) result.push(id);
26702 difference.modified = function() {
26704 _.each(changes, function(change) {
26705 if (change.base && change.head) result.push(change.head);
26710 difference.created = function() {
26712 _.each(changes, function(change) {
26713 if (!change.base && change.head) result.push(change.head);
26718 difference.deleted = function() {
26720 _.each(changes, function(change) {
26721 if (change.base && !change.head) result.push(change.base);
26726 difference.summary = function() {
26729 function addEntity(entity, graph, changeType) {
26730 relevant[entity.id] = {
26733 changeType: changeType
26737 function addParents(entity) {
26738 var parents = head.parentWays(entity);
26739 for (var j = parents.length - 1; j >= 0; j--) {
26740 var parent = parents[j];
26741 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
26745 _.each(changes, function(change) {
26746 if (change.head && change.head.geometry(head) !== 'vertex') {
26747 addEntity(change.head, head, change.base ? 'modified' : 'created');
26749 } else if (change.base && change.base.geometry(base) !== 'vertex') {
26750 addEntity(change.base, base, 'deleted');
26752 } else if (change.base && change.head) { // modified vertex
26753 var moved = !_.isEqual(change.base.loc, change.head.loc),
26754 retagged = !_.isEqual(change.base.tags, change.head.tags);
26757 addParents(change.head);
26760 if (retagged || (moved && change.head.hasInterestingTags())) {
26761 addEntity(change.head, head, 'modified');
26764 } else if (change.head && change.head.hasInterestingTags()) { // created vertex
26765 addEntity(change.head, head, 'created');
26767 } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
26768 addEntity(change.base, base, 'deleted');
26772 return d3.values(relevant);
26775 difference.complete = function(extent) {
26776 var result = {}, id, change;
26778 for (id in changes) {
26779 change = changes[id];
26781 var h = change.head,
26786 (!h || !h.intersects(extent, head)) &&
26787 (!b || !b.intersects(extent, base)))
26792 if (entity.type === 'way') {
26793 var nh = h ? h.nodes : [],
26794 nb = b ? b.nodes : [],
26797 diff = _.difference(nh, nb);
26798 for (i = 0; i < diff.length; i++) {
26799 result[diff[i]] = head.hasEntity(diff[i]);
26802 diff = _.difference(nb, nh);
26803 for (i = 0; i < diff.length; i++) {
26804 result[diff[i]] = head.hasEntity(diff[i]);
26808 addParents(head.parentWays(entity), result);
26809 addParents(head.parentRelations(entity), result);
26817 iD.Entity = function(attrs) {
26818 // For prototypal inheritance.
26819 if (this instanceof iD.Entity) return;
26821 // Create the appropriate subtype.
26822 if (attrs && attrs.type) {
26823 return iD.Entity[attrs.type].apply(this, arguments);
26824 } else if (attrs && attrs.id) {
26825 return iD.Entity[iD.Entity.id.type(attrs.id)].apply(this, arguments);
26828 // Initialize a generic Entity (used only in tests).
26829 return (new iD.Entity()).initialize(arguments);
26832 iD.Entity.id = function(type) {
26833 return iD.Entity.id.fromOSM(type, iD.Entity.id.next[type]--);
26836 iD.Entity.id.next = {node: -1, way: -1, relation: -1};
26838 iD.Entity.id.fromOSM = function(type, id) {
26839 return type[0] + id;
26842 iD.Entity.id.toOSM = function(id) {
26843 return id.slice(1);
26846 iD.Entity.id.type = function(id) {
26847 return {'n': 'node', 'w': 'way', 'r': 'relation'}[id[0]];
26850 // A function suitable for use as the second argument to d3.selection#data().
26851 iD.Entity.key = function(entity) {
26852 return entity.id + 'v' + (entity.v || 0);
26855 iD.Entity.prototype = {
26858 initialize: function(sources) {
26859 for (var i = 0; i < sources.length; ++i) {
26860 var source = sources[i];
26861 for (var prop in source) {
26862 if (Object.prototype.hasOwnProperty.call(source, prop)) {
26863 if (source[prop] === undefined) {
26866 this[prop] = source[prop];
26872 if (!this.id && this.type) {
26873 this.id = iD.Entity.id(this.type);
26875 if (!this.hasOwnProperty('visible')) {
26876 this.visible = true;
26880 Object.freeze(this);
26881 Object.freeze(this.tags);
26883 if (this.loc) Object.freeze(this.loc);
26884 if (this.nodes) Object.freeze(this.nodes);
26885 if (this.members) Object.freeze(this.members);
26891 copy: function(resolver, copies) {
26892 if (copies[this.id])
26893 return copies[this.id];
26895 var copy = iD.Entity(this, {id: undefined, user: undefined, version: undefined});
26896 copies[this.id] = copy;
26901 osmId: function() {
26902 return iD.Entity.id.toOSM(this.id);
26905 isNew: function() {
26906 return this.osmId() < 0;
26909 update: function(attrs) {
26910 return iD.Entity(this, attrs, {v: 1 + (this.v || 0)});
26913 mergeTags: function(tags) {
26914 var merged = _.clone(this.tags), changed = false;
26915 for (var k in tags) {
26916 var t1 = merged[k],
26921 } else if (t1 !== t2) {
26923 merged[k] = _.union(t1.split(/;\s*/), t2.split(/;\s*/)).join(';');
26926 return changed ? this.update({tags: merged}) : this;
26929 intersects: function(extent, resolver) {
26930 return this.extent(resolver).intersects(extent);
26933 isUsed: function(resolver) {
26934 return _.without(Object.keys(this.tags), 'area').length > 0 ||
26935 resolver.parentRelations(this).length > 0;
26938 hasInterestingTags: function() {
26939 return _.keys(this.tags).some(iD.interestingTag);
26942 isHighwayIntersection: function() {
26946 deprecatedTags: function() {
26947 var tags = _.pairs(this.tags);
26948 var deprecated = {};
26950 iD.data.deprecated.forEach(function(d) {
26951 var match = _.pairs(d.old)[0];
26952 tags.forEach(function(t) {
26953 if (t[0] === match[0] &&
26954 (t[1] === match[1] || match[1] === '*')) {
26955 deprecated[t[0]] = t[1];
26963 iD.Graph = function(other, mutable) {
26964 if (!(this instanceof iD.Graph)) return new iD.Graph(other, mutable);
26966 if (other instanceof iD.Graph) {
26967 var base = other.base();
26968 this.entities = _.assign(Object.create(base.entities), other.entities);
26969 this._parentWays = _.assign(Object.create(base.parentWays), other._parentWays);
26970 this._parentRels = _.assign(Object.create(base.parentRels), other._parentRels);
26973 this.entities = Object.create({});
26974 this._parentWays = Object.create({});
26975 this._parentRels = Object.create({});
26976 this.rebase(other || [], [this]);
26979 this.transients = {};
26980 this._childNodes = {};
26981 this.frozen = !mutable;
26984 iD.Graph.prototype = {
26985 hasEntity: function(id) {
26986 return this.entities[id];
26989 entity: function(id) {
26990 var entity = this.entities[id];
26992 throw new Error('entity ' + id + ' not found');
26997 transient: function(entity, key, fn) {
26998 var id = entity.id,
26999 transients = this.transients[id] ||
27000 (this.transients[id] = {});
27002 if (transients[key] !== undefined) {
27003 return transients[key];
27006 transients[key] = fn.call(entity);
27008 return transients[key];
27011 parentWays: function(entity) {
27012 var parents = this._parentWays[entity.id],
27016 for (var i = 0; i < parents.length; i++) {
27017 result.push(this.entity(parents[i]));
27023 isPoi: function(entity) {
27024 var parentWays = this._parentWays[entity.id];
27025 return !parentWays || parentWays.length === 0;
27028 isShared: function(entity) {
27029 var parentWays = this._parentWays[entity.id];
27030 return parentWays && parentWays.length > 1;
27033 parentRelations: function(entity) {
27034 var parents = this._parentRels[entity.id],
27038 for (var i = 0; i < parents.length; i++) {
27039 result.push(this.entity(parents[i]));
27045 childNodes: function(entity) {
27046 if (this._childNodes[entity.id]) return this._childNodes[entity.id];
27047 if (!entity.nodes) return [];
27050 for (var i = 0; i < entity.nodes.length; i++) {
27051 nodes[i] = this.entity(entity.nodes[i]);
27054 if (iD.debug) Object.freeze(nodes);
27056 this._childNodes[entity.id] = nodes;
27057 return this._childNodes[entity.id];
27062 'entities': iD.util.getPrototypeOf(this.entities),
27063 'parentWays': iD.util.getPrototypeOf(this._parentWays),
27064 'parentRels': iD.util.getPrototypeOf(this._parentRels)
27068 // Unlike other graph methods, rebase mutates in place. This is because it
27069 // is used only during the history operation that merges newly downloaded
27070 // data into each state. To external consumers, it should appear as if the
27071 // graph always contained the newly downloaded data.
27072 rebase: function(entities, stack, force) {
27073 var base = this.base(),
27076 for (i = 0; i < entities.length; i++) {
27077 var entity = entities[i];
27079 if (!entity.visible || (!force && base.entities[entity.id]))
27082 // Merging data into the base graph
27083 base.entities[entity.id] = entity;
27084 this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
27086 // Restore provisionally-deleted nodes that are discovered to have an extant parent
27087 if (entity.type === 'way') {
27088 for (j = 0; j < entity.nodes.length; j++) {
27089 id = entity.nodes[j];
27090 for (k = 1; k < stack.length; k++) {
27091 var ents = stack[k].entities;
27092 if (ents.hasOwnProperty(id) && ents[id] === undefined) {
27100 for (i = 0; i < stack.length; i++) {
27101 stack[i]._updateRebased();
27105 _updateRebased: function() {
27106 var base = this.base(),
27107 i, k, child, id, keys;
27109 keys = Object.keys(this._parentWays);
27110 for (i = 0; i < keys.length; i++) {
27112 if (base.parentWays[child]) {
27113 for (k = 0; k < base.parentWays[child].length; k++) {
27114 id = base.parentWays[child][k];
27115 if (!this.entities.hasOwnProperty(id) && !_.contains(this._parentWays[child], id)) {
27116 this._parentWays[child].push(id);
27122 keys = Object.keys(this._parentRels);
27123 for (i = 0; i < keys.length; i++) {
27125 if (base.parentRels[child]) {
27126 for (k = 0; k < base.parentRels[child].length; k++) {
27127 id = base.parentRels[child][k];
27128 if (!this.entities.hasOwnProperty(id) && !_.contains(this._parentRels[child], id)) {
27129 this._parentRels[child].push(id);
27135 this.transients = {};
27137 // this._childNodes is not updated, under the assumption that
27138 // ways are always downloaded with their child nodes.
27141 // Updates calculated properties (parentWays, parentRels) for the specified change
27142 _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
27144 parentWays = parentWays || this._parentWays;
27145 parentRels = parentRels || this._parentRels;
27147 var type = entity && entity.type || oldentity && oldentity.type,
27148 removed, added, ways, rels, i;
27151 if (type === 'way') {
27153 // Update parentWays
27154 if (oldentity && entity) {
27155 removed = _.difference(oldentity.nodes, entity.nodes);
27156 added = _.difference(entity.nodes, oldentity.nodes);
27157 } else if (oldentity) {
27158 removed = oldentity.nodes;
27160 } else if (entity) {
27162 added = entity.nodes;
27164 for (i = 0; i < removed.length; i++) {
27165 parentWays[removed[i]] = _.without(parentWays[removed[i]], oldentity.id);
27167 for (i = 0; i < added.length; i++) {
27168 ways = _.without(parentWays[added[i]], entity.id);
27169 ways.push(entity.id);
27170 parentWays[added[i]] = ways;
27173 } else if (type === 'relation') {
27175 // Update parentRels
27176 if (oldentity && entity) {
27177 removed = _.difference(oldentity.members, entity.members);
27178 added = _.difference(entity.members, oldentity);
27179 } else if (oldentity) {
27180 removed = oldentity.members;
27182 } else if (entity) {
27184 added = entity.members;
27186 for (i = 0; i < removed.length; i++) {
27187 parentRels[removed[i].id] = _.without(parentRels[removed[i].id], oldentity.id);
27189 for (i = 0; i < added.length; i++) {
27190 rels = _.without(parentRels[added[i].id], entity.id);
27191 rels.push(entity.id);
27192 parentRels[added[i].id] = rels;
27197 replace: function(entity) {
27198 if (this.entities[entity.id] === entity)
27201 return this.update(function() {
27202 this._updateCalculated(this.entities[entity.id], entity);
27203 this.entities[entity.id] = entity;
27207 remove: function(entity) {
27208 return this.update(function() {
27209 this._updateCalculated(entity, undefined);
27210 this.entities[entity.id] = undefined;
27214 revert: function(id) {
27215 var baseEntity = this.base().entities[id],
27216 headEntity = this.entities[id];
27218 if (headEntity === baseEntity)
27221 return this.update(function() {
27222 this._updateCalculated(headEntity, baseEntity);
27223 delete this.entities[id];
27227 update: function() {
27228 var graph = this.frozen ? iD.Graph(this, true) : this;
27230 for (var i = 0; i < arguments.length; i++) {
27231 arguments[i].call(graph, graph);
27234 if (this.frozen) graph.frozen = true;
27239 // Obliterates any existing entities
27240 load: function(entities) {
27241 var base = this.base();
27242 this.entities = Object.create(base.entities);
27244 for (var i in entities) {
27245 this.entities[i] = entities[i];
27246 this._updateCalculated(base.entities[i], this.entities[i]);
27252 iD.History = function(context) {
27253 var stack, index, tree,
27254 imageryUsed = ['Bing'],
27255 dispatch = d3.dispatch('change', 'undone', 'redone'),
27256 lock = iD.util.SessionMutex('lock');
27258 function perform(actions) {
27259 actions = Array.prototype.slice.call(actions);
27263 if (!_.isFunction(_.last(actions))) {
27264 annotation = actions.pop();
27267 var graph = stack[index].graph;
27268 for (var i = 0; i < actions.length; i++) {
27269 graph = actions[i](graph);
27274 annotation: annotation,
27275 imageryUsed: imageryUsed
27279 function change(previous) {
27280 var difference = iD.Difference(previous, history.graph());
27281 dispatch.change(difference);
27285 // iD uses namespaced keys so multiple installations do not conflict
27286 function getKey(n) {
27287 return 'iD_' + window.location.origin + '_' + n;
27291 graph: function() {
27292 return stack[index].graph;
27296 return stack[0].graph;
27299 merge: function(entities, extent) {
27300 stack[0].graph.rebase(entities, _.pluck(stack, 'graph'), false);
27301 tree.rebase(entities, false);
27303 dispatch.change(undefined, extent);
27306 perform: function() {
27307 var previous = stack[index].graph;
27309 stack = stack.slice(0, index + 1);
27310 stack.push(perform(arguments));
27313 return change(previous);
27316 replace: function() {
27317 var previous = stack[index].graph;
27319 // assert(index == stack.length - 1)
27320 stack[index] = perform(arguments);
27322 return change(previous);
27326 var previous = stack[index].graph;
27331 return change(previous);
27335 // Same as calling pop and then perform
27336 overwrite: function() {
27337 var previous = stack[index].graph;
27343 stack = stack.slice(0, index + 1);
27344 stack.push(perform(arguments));
27347 return change(previous);
27351 var previous = stack[index].graph;
27353 // Pop to the next annotated state.
27354 while (index > 0) {
27356 if (stack[index].annotation) break;
27360 return change(previous);
27364 var previous = stack[index].graph;
27366 while (index < stack.length - 1) {
27368 if (stack[index].annotation) break;
27372 return change(previous);
27375 undoAnnotation: function() {
27378 if (stack[i].annotation) return stack[i].annotation;
27383 redoAnnotation: function() {
27385 while (i <= stack.length - 1) {
27386 if (stack[i].annotation) return stack[i].annotation;
27391 intersects: function(extent) {
27392 return tree.intersects(extent, stack[index].graph);
27395 difference: function() {
27396 var base = stack[0].graph,
27397 head = stack[index].graph;
27398 return iD.Difference(base, head);
27401 changes: function(action) {
27402 var base = stack[0].graph,
27403 head = stack[index].graph;
27406 head = action(head);
27409 var difference = iD.Difference(base, head);
27412 modified: difference.modified(),
27413 created: difference.created(),
27414 deleted: difference.deleted()
27418 validate: function(changes) {
27419 return _(iD.validations)
27420 .map(function(fn) { return fn()(changes, stack[index].graph); })
27425 hasChanges: function() {
27426 return this.difference().length() > 0;
27429 imageryUsed: function(sources) {
27431 imageryUsed = sources;
27434 return _(stack.slice(1, index + 1))
27435 .pluck('imageryUsed')
27438 .without(undefined, 'Custom')
27443 reset: function() {
27444 stack = [{graph: iD.Graph()}];
27446 tree = iD.Tree(stack[0].graph);
27451 toJSON: function() {
27452 if (!this.hasChanges()) return;
27454 var allEntities = {},
27458 var s = stack.map(function(i) {
27459 var modified = [], deleted = [];
27461 _.forEach(i.graph.entities, function(entity, id) {
27463 var key = iD.Entity.key(entity);
27464 allEntities[key] = entity;
27465 modified.push(key);
27470 // make sure that the originals of changed or deleted entities get merged
27471 // into the base of the stack after restoring the data from JSON.
27472 if (id in base.graph.entities) {
27473 baseEntities[id] = base.graph.entities[id];
27475 // get originals of parent entities too
27476 _.forEach(base.graph._parentWays[id], function(parentId) {
27477 if (parentId in base.graph.entities) {
27478 baseEntities[parentId] = base.graph.entities[parentId];
27485 if (modified.length) x.modified = modified;
27486 if (deleted.length) x.deleted = deleted;
27487 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
27488 if (i.annotation) x.annotation = i.annotation;
27493 return JSON.stringify({
27495 entities: _.values(allEntities),
27496 baseEntities: _.values(baseEntities),
27498 nextIDs: iD.Entity.id.next,
27503 fromJSON: function(json, loadChildNodes) {
27504 var h = JSON.parse(json),
27505 loadComplete = true;
27507 iD.Entity.id.next = h.nextIDs;
27510 if (h.version === 2 || h.version === 3) {
27511 var allEntities = {};
27513 h.entities.forEach(function(entity) {
27514 allEntities[iD.Entity.key(entity)] = iD.Entity(entity);
27517 if (h.version === 3) {
27518 // This merges originals for changed entities into the base of
27519 // the stack even if the current stack doesn't have them (for
27520 // example when iD has been restarted in a different region)
27521 var baseEntities = h.baseEntities.map(function(d) { return iD.Entity(d); });
27522 stack[0].graph.rebase(baseEntities, _.pluck(stack, 'graph'), true);
27523 tree.rebase(baseEntities, true);
27525 // When we restore a modified way, we also need to fetch any missing
27526 // childnodes that would normally have been downloaded with it.. #2142
27527 if (loadChildNodes) {
27528 var missing = _(baseEntities)
27529 .filter('type', 'way')
27533 .reject(function(n) { return stack[0].graph.hasEntity(n); })
27536 if (!_.isEmpty(missing)) {
27537 loadComplete = false;
27538 context.redrawEnable(false);
27540 var loading = iD.ui.Loading(context).blocking(true);
27541 context.container().call(loading);
27543 var childNodesLoaded = function(err, result) {
27545 var visible = _.groupBy(result.data, 'visible');
27546 if (!_.isEmpty(visible.true)) {
27547 missing = _.difference(missing, _.pluck(visible.true, 'id'));
27548 stack[0].graph.rebase(visible.true, _.pluck(stack, 'graph'), true);
27549 tree.rebase(visible.true, true);
27552 // fetch older versions of nodes that were deleted..
27553 _.each(visible.false, function(entity) {
27554 context.connection()
27555 .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
27559 if (err || _.isEmpty(missing)) {
27561 context.redrawEnable(true);
27566 context.connection().loadMultiple(missing, childNodesLoaded);
27571 stack = h.stack.map(function(d) {
27572 var entities = {}, entity;
27575 d.modified.forEach(function(key) {
27576 entity = allEntities[key];
27577 entities[entity.id] = entity;
27582 d.deleted.forEach(function(id) {
27583 entities[id] = undefined;
27588 graph: iD.Graph(stack[0].graph).load(entities),
27589 annotation: d.annotation,
27590 imageryUsed: d.imageryUsed
27594 } else { // original version
27595 stack = h.stack.map(function(d) {
27598 for (var i in d.entities) {
27599 var entity = d.entities[i];
27600 entities[i] = entity === 'undefined' ? undefined : iD.Entity(entity);
27603 d.graph = iD.Graph(stack[0].graph).load(entities);
27608 if (loadComplete) {
27616 if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
27620 clearSaved: function() {
27621 context.debouncedSave.cancel();
27622 if (lock.locked()) context.storage(getKey('saved_history'), null);
27627 return lock.lock();
27630 unlock: function() {
27634 // is iD not open in another window and it detects that
27635 // there's a history stored in localStorage that's recoverable?
27636 restorableChanges: function() {
27637 return lock.locked() && !!context.storage(getKey('saved_history'));
27640 // load history from a version stored in localStorage
27641 restore: function() {
27642 if (!lock.locked()) return;
27644 var json = context.storage(getKey('saved_history'));
27645 if (json) history.fromJSON(json, true);
27654 return d3.rebind(history, dispatch, 'on');
27656 iD.Node = iD.Entity.node = function iD_Node() {
27657 if (!(this instanceof iD_Node)) {
27658 return (new iD_Node()).initialize(arguments);
27659 } else if (arguments.length) {
27660 this.initialize(arguments);
27664 iD.Node.prototype = Object.create(iD.Entity.prototype);
27666 _.extend(iD.Node.prototype, {
27669 extent: function() {
27670 return new iD.geo.Extent(this.loc);
27673 geometry: function(graph) {
27674 return graph.transient(this, 'geometry', function() {
27675 return graph.isPoi(this) ? 'point' : 'vertex';
27679 move: function(loc) {
27680 return this.update({loc: loc});
27683 isIntersection: function(resolver) {
27684 return resolver.transient(this, 'isIntersection', function() {
27685 return resolver.parentWays(this).filter(function(parent) {
27686 return (parent.tags.highway ||
27687 parent.tags.waterway ||
27688 parent.tags.railway ||
27689 parent.tags.aeroway) &&
27690 parent.geometry(resolver) === 'line';
27695 isHighwayIntersection: function(resolver) {
27696 return resolver.transient(this, 'isHighwayIntersection', function() {
27697 return resolver.parentWays(this).filter(function(parent) {
27698 return parent.tags.highway && parent.geometry(resolver) === 'line';
27703 asJXON: function(changeset_id) {
27706 '@id': this.osmId(),
27707 '@lon': this.loc[0],
27708 '@lat': this.loc[1],
27709 '@version': (this.version || 0),
27710 tag: _.map(this.tags, function(v, k) {
27711 return { keyAttributes: { k: k, v: v } };
27715 if (changeset_id) r.node['@changeset'] = changeset_id;
27719 asGeoJSON: function() {
27722 coordinates: this.loc
27726 iD.Relation = iD.Entity.relation = function iD_Relation() {
27727 if (!(this instanceof iD_Relation)) {
27728 return (new iD_Relation()).initialize(arguments);
27729 } else if (arguments.length) {
27730 this.initialize(arguments);
27734 iD.Relation.prototype = Object.create(iD.Entity.prototype);
27736 iD.Relation.creationOrder = function(a, b) {
27737 var aId = parseInt(iD.Entity.id.toOSM(a.id), 10);
27738 var bId = parseInt(iD.Entity.id.toOSM(b.id), 10);
27740 if (aId < 0 || bId < 0) return aId - bId;
27744 _.extend(iD.Relation.prototype, {
27748 copy: function(resolver, copies) {
27749 if (copies[this.id])
27750 return copies[this.id];
27752 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
27754 var members = this.members.map(function(member) {
27755 return _.extend({}, member, {id: resolver.entity(member.id).copy(resolver, copies).id});
27758 copy = copy.update({members: members});
27759 copies[this.id] = copy;
27764 extent: function(resolver, memo) {
27765 return resolver.transient(this, 'extent', function() {
27766 if (memo && memo[this.id]) return iD.geo.Extent();
27768 memo[this.id] = true;
27770 var extent = iD.geo.Extent();
27771 for (var i = 0; i < this.members.length; i++) {
27772 var member = resolver.hasEntity(this.members[i].id);
27774 extent._extend(member.extent(resolver, memo));
27781 geometry: function(graph) {
27782 return graph.transient(this, 'geometry', function() {
27783 return this.isMultipolygon() ? 'area' : 'relation';
27787 isDegenerate: function() {
27788 return this.members.length === 0;
27791 // Return an array of members, each extended with an 'index' property whose value
27792 // is the member index.
27793 indexedMembers: function() {
27794 var result = new Array(this.members.length);
27795 for (var i = 0; i < this.members.length; i++) {
27796 result[i] = _.extend({}, this.members[i], {index: i});
27801 // Return the first member with the given role. A copy of the member object
27802 // is returned, extended with an 'index' property whose value is the member index.
27803 memberByRole: function(role) {
27804 for (var i = 0; i < this.members.length; i++) {
27805 if (this.members[i].role === role) {
27806 return _.extend({}, this.members[i], {index: i});
27811 // Return the first member with the given id. A copy of the member object
27812 // is returned, extended with an 'index' property whose value is the member index.
27813 memberById: function(id) {
27814 for (var i = 0; i < this.members.length; i++) {
27815 if (this.members[i].id === id) {
27816 return _.extend({}, this.members[i], {index: i});
27821 // Return the first member with the given id and role. A copy of the member object
27822 // is returned, extended with an 'index' property whose value is the member index.
27823 memberByIdAndRole: function(id, role) {
27824 for (var i = 0; i < this.members.length; i++) {
27825 if (this.members[i].id === id && this.members[i].role === role) {
27826 return _.extend({}, this.members[i], {index: i});
27831 addMember: function(member, index) {
27832 var members = this.members.slice();
27833 members.splice(index === undefined ? members.length : index, 0, member);
27834 return this.update({members: members});
27837 updateMember: function(member, index) {
27838 var members = this.members.slice();
27839 members.splice(index, 1, _.extend({}, members[index], member));
27840 return this.update({members: members});
27843 removeMember: function(index) {
27844 var members = this.members.slice();
27845 members.splice(index, 1);
27846 return this.update({members: members});
27849 removeMembersWithID: function(id) {
27850 var members = _.reject(this.members, function(m) { return m.id === id; });
27851 return this.update({members: members});
27854 // Wherever a member appears with id `needle.id`, replace it with a member
27855 // with id `replacement.id`, type `replacement.type`, and the original role,
27856 // unless a member already exists with that id and role. Return an updated
27858 replaceMember: function(needle, replacement) {
27859 if (!this.memberById(needle.id))
27864 for (var i = 0; i < this.members.length; i++) {
27865 var member = this.members[i];
27866 if (member.id !== needle.id) {
27867 members.push(member);
27868 } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
27869 members.push({id: replacement.id, type: replacement.type, role: member.role});
27873 return this.update({members: members});
27876 asJXON: function(changeset_id) {
27879 '@id': this.osmId(),
27880 '@version': this.version || 0,
27881 member: _.map(this.members, function(member) {
27882 return { keyAttributes: { type: member.type, role: member.role, ref: iD.Entity.id.toOSM(member.id) } };
27884 tag: _.map(this.tags, function(v, k) {
27885 return { keyAttributes: { k: k, v: v } };
27889 if (changeset_id) r.relation['@changeset'] = changeset_id;
27893 asGeoJSON: function(resolver) {
27894 return resolver.transient(this, 'GeoJSON', function () {
27895 if (this.isMultipolygon()) {
27897 type: 'MultiPolygon',
27898 coordinates: this.multipolygon(resolver)
27902 type: 'FeatureCollection',
27903 properties: this.tags,
27904 features: this.members.map(function (member) {
27905 return _.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
27912 area: function(resolver) {
27913 return resolver.transient(this, 'area', function() {
27914 return d3.geo.area(this.asGeoJSON(resolver));
27918 isMultipolygon: function() {
27919 return this.tags.type === 'multipolygon';
27922 isComplete: function(resolver) {
27923 for (var i = 0; i < this.members.length; i++) {
27924 if (!resolver.hasEntity(this.members[i].id)) {
27931 isRestriction: function() {
27932 return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
27935 // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
27936 // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
27938 // This corresponds to the structure needed for rendering a multipolygon path using a
27939 // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
27941 // In the case of invalid geometries, this function will still return a result which
27942 // includes the nodes of all way members, but some Nds may be unclosed and some inner
27943 // rings not matched with the intended outer ring.
27945 multipolygon: function(resolver) {
27946 var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
27947 inners = this.members.filter(function(m) { return 'inner' === m.role; });
27949 outers = iD.geo.joinWays(outers, resolver);
27950 inners = iD.geo.joinWays(inners, resolver);
27952 outers = outers.map(function(outer) { return _.pluck(outer.nodes, 'loc'); });
27953 inners = inners.map(function(inner) { return _.pluck(inner.nodes, 'loc'); });
27955 var result = outers.map(function(o) {
27956 // Heuristic for detecting counterclockwise winding order. Assumes
27957 // that OpenStreetMap polygons are not hemisphere-spanning.
27958 return [d3.geo.area({type: 'Polygon', coordinates: [o]}) > 2 * Math.PI ? o.reverse() : o];
27961 function findOuter(inner) {
27964 for (o = 0; o < outers.length; o++) {
27966 if (iD.geo.polygonContainsPolygon(outer, inner))
27970 for (o = 0; o < outers.length; o++) {
27972 if (iD.geo.polygonIntersectsPolygon(outer, inner))
27977 for (var i = 0; i < inners.length; i++) {
27978 var inner = inners[i];
27980 if (d3.geo.area({type: 'Polygon', coordinates: [inner]}) < 2 * Math.PI) {
27981 inner = inner.reverse();
27984 var o = findOuter(inners[i]);
27985 if (o !== undefined)
27986 result[o].push(inners[i]);
27988 result.push([inners[i]]); // Invalid geometry
27996 'chair_lift': true,
27997 'mixed_lift': true,
28002 'magic_carpet': true,
28007 'motorway_link': true
28013 'piste:halfpipe': true
28037 iD.interestingTag = function (key) {
28038 return key !== 'attribution' &&
28039 key !== 'created_by' &&
28040 key !== 'source' &&
28042 key.indexOf('tiger:') !== 0;
28045 iD.Tree = function(head) {
28046 var rtree = rbush(),
28049 function entityRectangle(entity) {
28050 var rect = entity.extent(head).rectangle();
28051 rect.id = entity.id;
28052 rectangles[entity.id] = rect;
28056 function updateParents(entity, insertions, memo) {
28057 head.parentWays(entity).forEach(function(way) {
28058 if (rectangles[way.id]) {
28059 rtree.remove(rectangles[way.id]);
28060 insertions[way.id] = way;
28062 updateParents(way, insertions, memo);
28065 head.parentRelations(entity).forEach(function(relation) {
28066 if (memo[entity.id]) return;
28067 memo[entity.id] = true;
28068 if (rectangles[relation.id]) {
28069 rtree.remove(rectangles[relation.id]);
28070 insertions[relation.id] = relation;
28072 updateParents(relation, insertions, memo);
28078 tree.rebase = function(entities, force) {
28079 var insertions = {};
28081 for (var i = 0; i < entities.length; i++) {
28082 var entity = entities[i];
28084 if (!entity.visible)
28087 if (head.entities.hasOwnProperty(entity.id) || rectangles[entity.id]) {
28090 } else if (rectangles[entity.id]) {
28091 rtree.remove(rectangles[entity.id]);
28095 insertions[entity.id] = entity;
28096 updateParents(entity, insertions, {});
28099 rtree.load(_.map(insertions, entityRectangle));
28104 tree.intersects = function(extent, graph) {
28105 if (graph !== head) {
28106 var diff = iD.Difference(head, graph),
28111 diff.deleted().forEach(function(entity) {
28112 rtree.remove(rectangles[entity.id]);
28113 delete rectangles[entity.id];
28116 diff.modified().forEach(function(entity) {
28117 rtree.remove(rectangles[entity.id]);
28118 insertions[entity.id] = entity;
28119 updateParents(entity, insertions, {});
28122 diff.created().forEach(function(entity) {
28123 insertions[entity.id] = entity;
28126 rtree.load(_.map(insertions, entityRectangle));
28129 return rtree.search(extent.rectangle()).map(function(rect) {
28130 return head.entity(rect.id);
28136 iD.Way = iD.Entity.way = function iD_Way() {
28137 if (!(this instanceof iD_Way)) {
28138 return (new iD_Way()).initialize(arguments);
28139 } else if (arguments.length) {
28140 this.initialize(arguments);
28144 iD.Way.prototype = Object.create(iD.Entity.prototype);
28146 _.extend(iD.Way.prototype, {
28150 copy: function(resolver, copies) {
28151 if (copies[this.id])
28152 return copies[this.id];
28154 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
28156 var nodes = this.nodes.map(function(id) {
28157 return resolver.entity(id).copy(resolver, copies).id;
28160 copy = copy.update({nodes: nodes});
28161 copies[this.id] = copy;
28166 extent: function(resolver) {
28167 return resolver.transient(this, 'extent', function() {
28168 var extent = iD.geo.Extent();
28169 for (var i = 0; i < this.nodes.length; i++) {
28170 var node = resolver.hasEntity(this.nodes[i]);
28172 extent._extend(node.extent());
28179 first: function() {
28180 return this.nodes[0];
28184 return this.nodes[this.nodes.length - 1];
28187 contains: function(node) {
28188 return this.nodes.indexOf(node) >= 0;
28191 affix: function(node) {
28192 if (this.nodes[0] === node) return 'prefix';
28193 if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
28196 layer: function() {
28197 // explicit layer tag, clamp between -10, 10..
28198 if (this.tags.layer !== undefined) {
28199 return Math.max(-10, Math.min(+(this.tags.layer), 10));
28202 // implied layer tag..
28203 if (this.tags.location === 'overground') return 1;
28204 if (this.tags.location === 'underground') return -1;
28205 if (this.tags.location === 'underwater') return -10;
28207 if (this.tags.power === 'line') return 10;
28208 if (this.tags.power === 'minor_line') return 10;
28209 if (this.tags.aerialway) return 10;
28210 if (this.tags.bridge) return 1;
28211 if (this.tags.cutting) return -1;
28212 if (this.tags.tunnel) return -1;
28213 if (this.tags.waterway) return -1;
28214 if (this.tags.man_made === 'pipeline') return -10;
28215 if (this.tags.boundary) return -10;
28219 isOneWay: function() {
28220 // explicit oneway tag..
28221 if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
28222 if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
28224 // implied oneway tag..
28225 for (var key in this.tags) {
28226 if (key in iD.oneWayTags && (this.tags[key] in iD.oneWayTags[key]))
28232 isClosed: function() {
28233 return this.nodes.length > 0 && this.first() === this.last();
28236 isConvex: function(resolver) {
28237 if (!this.isClosed() || this.isDegenerate()) return null;
28239 var nodes = _.uniq(resolver.childNodes(this)),
28240 coords = _.pluck(nodes, 'loc'),
28241 curr = 0, prev = 0;
28243 for (var i = 0; i < coords.length; i++) {
28244 var o = coords[(i+1) % coords.length],
28246 b = coords[(i+2) % coords.length],
28247 res = iD.geo.cross(o, a, b);
28249 curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
28252 } else if (prev && curr !== prev) {
28260 isArea: function() {
28261 if (this.tags.area === 'yes')
28263 if (!this.isClosed() || this.tags.area === 'no')
28265 for (var key in this.tags)
28266 if (key in iD.areaKeys && !(this.tags[key] in iD.areaKeys[key]))
28271 isDegenerate: function() {
28272 return _.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
28275 areAdjacent: function(n1, n2) {
28276 for (var i = 0; i < this.nodes.length; i++) {
28277 if (this.nodes[i] === n1) {
28278 if (this.nodes[i - 1] === n2) return true;
28279 if (this.nodes[i + 1] === n2) return true;
28285 geometry: function(graph) {
28286 return graph.transient(this, 'geometry', function() {
28287 return this.isArea() ? 'area' : 'line';
28291 addNode: function(id, index) {
28292 var nodes = this.nodes.slice();
28293 nodes.splice(index === undefined ? nodes.length : index, 0, id);
28294 return this.update({nodes: nodes});
28297 updateNode: function(id, index) {
28298 var nodes = this.nodes.slice();
28299 nodes.splice(index, 1, id);
28300 return this.update({nodes: nodes});
28303 replaceNode: function(needle, replacement) {
28304 if (this.nodes.indexOf(needle) < 0)
28307 var nodes = this.nodes.slice();
28308 for (var i = 0; i < nodes.length; i++) {
28309 if (nodes[i] === needle) {
28310 nodes[i] = replacement;
28313 return this.update({nodes: nodes});
28316 removeNode: function(id) {
28319 for (var i = 0; i < this.nodes.length; i++) {
28320 var node = this.nodes[i];
28321 if (node !== id && nodes[nodes.length - 1] !== node) {
28326 // Preserve circularity
28327 if (this.nodes.length > 1 && this.first() === id && this.last() === id && nodes[nodes.length - 1] !== nodes[0]) {
28328 nodes.push(nodes[0]);
28331 return this.update({nodes: nodes});
28334 asJXON: function(changeset_id) {
28337 '@id': this.osmId(),
28338 '@version': this.version || 0,
28339 nd: _.map(this.nodes, function(id) {
28340 return { keyAttributes: { ref: iD.Entity.id.toOSM(id) } };
28342 tag: _.map(this.tags, function(v, k) {
28343 return { keyAttributes: { k: k, v: v } };
28347 if (changeset_id) r.way['@changeset'] = changeset_id;
28351 asGeoJSON: function(resolver) {
28352 return resolver.transient(this, 'GeoJSON', function() {
28353 var coordinates = _.pluck(resolver.childNodes(this), 'loc');
28354 if (this.isArea() && this.isClosed()) {
28357 coordinates: [coordinates]
28361 type: 'LineString',
28362 coordinates: coordinates
28368 area: function(resolver) {
28369 return resolver.transient(this, 'area', function() {
28370 var nodes = resolver.childNodes(this);
28374 coordinates: [_.pluck(nodes, 'loc')]
28377 if (!this.isClosed() && nodes.length) {
28378 json.coordinates[0].push(nodes[0].loc);
28381 var area = d3.geo.area(json);
28383 // Heuristic for detecting counterclockwise winding order. Assumes
28384 // that OpenStreetMap polygons are not hemisphere-spanning.
28385 if (area > 2 * Math.PI) {
28386 json.coordinates[0] = json.coordinates[0].reverse();
28387 area = d3.geo.area(json);
28390 return isNaN(area) ? 0 : area;
28394 iD.Background = function(context) {
28395 var dispatch = d3.dispatch('change'),
28396 baseLayer = iD.TileLayer().projection(context.projection),
28397 overlayLayers = [];
28399 var backgroundSources;
28401 function findSource(id) {
28402 return _.find(backgroundSources, function(d) {
28403 return d.id && d.id === id;
28407 function updateImagery() {
28408 var b = background.baseLayerSource(),
28409 o = overlayLayers.map(function (d) { return d.source().id; }).join(','),
28410 q = iD.util.stringQs(location.hash.substring(1));
28413 if (id === 'custom') {
28414 id = 'custom:' + b.template;
28420 delete q.background;
28429 location.replace('#' + iD.util.qsString(q, true));
28431 var imageryUsed = [b.imageryUsed()];
28433 overlayLayers.forEach(function (d) {
28434 var source = d.source();
28435 if (!source.isLocatorOverlay()) {
28436 imageryUsed.push(source.imageryUsed());
28440 var gpx = context.layers().layer('gpx');
28441 if (gpx && gpx.enabled() && gpx.hasGpx()) {
28442 imageryUsed.push('Local GPX');
28445 context.history().imageryUsed(imageryUsed);
28448 function background(selection) {
28449 var base = selection.selectAll('.layer-background')
28453 .insert('div', '.layer-data')
28454 .attr('class', 'layer layer-background');
28456 base.call(baseLayer);
28458 var overlays = selection.selectAll('.layer-overlay')
28459 .data(overlayLayers, function(d) { return d.source().name(); });
28462 .insert('div', '.layer-data')
28463 .attr('class', 'layer layer-overlay');
28465 overlays.each(function(layer) {
28466 d3.select(this).call(layer);
28473 background.sources = function(extent) {
28474 return backgroundSources.filter(function(source) {
28475 return source.intersects(extent);
28479 background.dimensions = function(_) {
28480 baseLayer.dimensions(_);
28482 overlayLayers.forEach(function(layer) {
28483 layer.dimensions(_);
28487 background.baseLayerSource = function(d) {
28488 if (!arguments.length) return baseLayer.source();
28490 baseLayer.source(d);
28497 background.bing = function() {
28498 background.baseLayerSource(findSource('Bing'));
28501 background.showsLayer = function(d) {
28502 return d === baseLayer.source() ||
28503 (d.id === 'custom' && baseLayer.source().id === 'custom') ||
28504 overlayLayers.some(function(l) { return l.source() === d; });
28507 background.overlayLayerSources = function() {
28508 return overlayLayers.map(function (l) { return l.source(); });
28511 background.toggleOverlayLayer = function(d) {
28514 for (var i = 0; i < overlayLayers.length; i++) {
28515 layer = overlayLayers[i];
28516 if (layer.source() === d) {
28517 overlayLayers.splice(i, 1);
28524 layer = iD.TileLayer()
28526 .projection(context.projection)
28527 .dimensions(baseLayer.dimensions());
28529 overlayLayers.push(layer);
28534 background.nudge = function(d, zoom) {
28535 baseLayer.source().nudge(d, zoom);
28540 background.offset = function(d) {
28541 if (!arguments.length) return baseLayer.source().offset();
28542 baseLayer.source().offset(d);
28547 background.load = function(imagery) {
28548 function parseMap(qmap) {
28549 if (!qmap) return false;
28550 var args = qmap.split('/').map(Number);
28551 if (args.length < 3 || args.some(isNaN)) return false;
28552 return iD.geo.Extent([args[1], args[2]]);
28555 var q = iD.util.stringQs(location.hash.substring(1)),
28556 chosen = q.background || q.layer,
28557 extent = parseMap(q.map),
28560 backgroundSources = imagery.map(function(source) {
28561 if (source.type === 'bing') {
28562 return iD.BackgroundSource.Bing(source, dispatch);
28564 return iD.BackgroundSource(source);
28568 backgroundSources.unshift(iD.BackgroundSource.None());
28570 if (!chosen && extent) {
28571 best = _.find(this.sources(extent), function(s) { return s.best(); });
28574 if (chosen && chosen.indexOf('custom:') === 0) {
28575 background.baseLayerSource(iD.BackgroundSource.Custom(chosen.replace(/^custom:/, '')));
28577 background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
28580 var locator = _.find(backgroundSources, function(d) {
28581 return d.overlay && d.default;
28585 background.toggleOverlayLayer(locator);
28588 var overlays = (q.overlays || '').split(',');
28589 overlays.forEach(function(overlay) {
28590 overlay = findSource(overlay);
28591 if (overlay) background.toggleOverlayLayer(overlay);
28595 var gpx = context.layers().layer('gpx');
28596 if (gpx) { gpx.url(q.gpx); }
28600 return d3.rebind(background, dispatch, 'on');
28602 iD.BackgroundSource = function(data) {
28603 var source = _.clone(data),
28605 name = source.name,
28606 best = !!source.best;
28608 source.scaleExtent = data.scaleExtent || [0, 20];
28609 source.overzoom = data.overzoom !== false;
28611 source.offset = function(_) {
28612 if (!arguments.length) return offset;
28617 source.nudge = function(_, zoomlevel) {
28618 offset[0] += _[0] / Math.pow(2, zoomlevel);
28619 offset[1] += _[1] / Math.pow(2, zoomlevel);
28623 source.name = function() {
28627 source.best = function() {
28631 source.imageryUsed = function() {
28632 return source.id || name;
28635 source.url = function(coord) {
28636 return data.template
28637 .replace('{x}', coord[0])
28638 .replace('{y}', coord[1])
28639 // TMS-flipped y coordinate
28640 .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
28641 .replace(/\{z(oom)?\}/, coord[2])
28642 .replace(/\{switch:([^}]+)\}/, function(s, r) {
28643 var subdomains = r.split(',');
28644 return subdomains[(coord[0] + coord[1]) % subdomains.length];
28646 .replace('{u}', function() {
28648 for (var zoom = coord[2]; zoom > 0; zoom--) {
28650 var mask = 1 << (zoom - 1);
28651 if ((coord[0] & mask) !== 0) b++;
28652 if ((coord[1] & mask) !== 0) b += 2;
28659 source.intersects = function(extent) {
28660 extent = extent.polygon();
28661 return !data.polygon || data.polygon.some(function(polygon) {
28662 return iD.geo.polygonIntersectsPolygon(polygon, extent, true);
28666 source.validZoom = function(z) {
28667 return source.scaleExtent[0] <= z &&
28668 (source.overzoom || source.scaleExtent[1] > z);
28671 source.isLocatorOverlay = function() {
28672 return name === 'Locator Overlay';
28675 source.copyrightNotices = function() {};
28680 iD.BackgroundSource.Bing = function(data, dispatch) {
28681 // http://msdn.microsoft.com/en-us/library/ff701716.aspx
28682 // http://msdn.microsoft.com/en-us/library/ff701701.aspx
28684 data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
28686 var bing = iD.BackgroundSource(data),
28687 key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
28688 url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
28689 key + '&jsonp={callback}',
28692 d3.jsonp(url, function(json) {
28693 providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
28695 attribution: provider.attribution,
28696 areas: provider.coverageAreas.map(function(area) {
28698 zoom: [area.zoomMin, area.zoomMax],
28699 extent: iD.geo.Extent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
28707 bing.copyrightNotices = function(zoom, extent) {
28708 zoom = Math.min(zoom, 21);
28709 return providers.filter(function(provider) {
28710 return _.any(provider.areas, function(area) {
28711 return extent.intersects(area.extent) &&
28712 area.zoom[0] <= zoom &&
28713 area.zoom[1] >= zoom;
28715 }).map(function(provider) {
28716 return provider.attribution;
28720 bing.logo = 'bing_maps.png';
28721 bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
28726 iD.BackgroundSource.None = function() {
28727 var source = iD.BackgroundSource({id: 'none', template: ''});
28729 source.name = function() {
28730 return t('background.none');
28733 source.imageryUsed = function() {
28740 iD.BackgroundSource.Custom = function(template) {
28741 var source = iD.BackgroundSource({id: 'custom', template: template});
28743 source.name = function() {
28744 return t('background.custom');
28747 source.imageryUsed = function() {
28748 return 'Custom (' + template + ')';
28753 iD.Features = function(context) {
28754 var major_roads = {
28756 'motorway_link': true,
28758 'trunk_link': true,
28760 'primary_link': true,
28762 'secondary_link': true,
28764 'tertiary_link': true,
28765 'residential': true
28768 var minor_roads = {
28770 'living_street': true,
28772 'unclassified': true,
28782 'pedestrian': true,
28786 var past_futures = {
28788 'construction': true,
28790 'dismantled': true,
28793 'demolished': true,
28794 'obliterated': true
28797 var dispatch = d3.dispatch('change', 'redraw'),
28805 function update() {
28806 _hidden = features.hidden();
28811 function defineFeature(k, filter, max) {
28815 enabled: true, // whether the user wants it enabled..
28817 currentMax: (max || Infinity),
28818 defaultMax: (max || Infinity),
28819 enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
28820 disable: function() { this.enabled = false; this.currentMax = 0; },
28821 hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
28822 autoHidden: function() { return this.hidden() && this.currentMax > 0; }
28827 defineFeature('points', function isPoint(entity, resolver, geometry) {
28828 return geometry === 'point';
28831 defineFeature('major_roads', function isMajorRoad(entity) {
28832 return major_roads[entity.tags.highway];
28835 defineFeature('minor_roads', function isMinorRoad(entity) {
28836 return minor_roads[entity.tags.highway];
28839 defineFeature('paths', function isPath(entity) {
28840 return paths[entity.tags.highway];
28843 defineFeature('buildings', function isBuilding(entity) {
28845 !!entity.tags['building:part'] ||
28846 (!!entity.tags.building && entity.tags.building !== 'no') ||
28847 entity.tags.amenity === 'shelter' ||
28848 entity.tags.parking === 'multi-storey' ||
28849 entity.tags.parking === 'sheds' ||
28850 entity.tags.parking === 'carports' ||
28851 entity.tags.parking === 'garage_boxes'
28855 defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
28856 return geometry === 'area' &&
28857 !_features.buildings.filter(entity) &&
28858 !_features.water.filter(entity);
28861 defineFeature('boundaries', function isBoundary(entity) {
28862 return !!entity.tags.boundary;
28865 defineFeature('water', function isWater(entity) {
28867 !!entity.tags.waterway ||
28868 entity.tags.natural === 'water' ||
28869 entity.tags.natural === 'coastline' ||
28870 entity.tags.natural === 'bay' ||
28871 entity.tags.landuse === 'pond' ||
28872 entity.tags.landuse === 'basin' ||
28873 entity.tags.landuse === 'reservoir' ||
28874 entity.tags.landuse === 'salt_pond'
28878 defineFeature('rail', function isRail(entity) {
28880 !!entity.tags.railway ||
28881 entity.tags.landuse === 'railway'
28883 major_roads[entity.tags.highway] ||
28884 minor_roads[entity.tags.highway] ||
28885 paths[entity.tags.highway]
28889 defineFeature('power', function isPower(entity) {
28890 return !!entity.tags.power;
28893 // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
28894 defineFeature('past_future', function isPastFuture(entity) {
28896 major_roads[entity.tags.highway] ||
28897 minor_roads[entity.tags.highway] ||
28898 paths[entity.tags.highway]
28899 ) { return false; }
28901 var strings = Object.keys(entity.tags);
28903 for (var i = 0; i < strings.length; i++) {
28904 var s = strings[i];
28905 if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
28910 // Lines or areas that don't match another feature filter.
28911 // IMPORTANT: The 'others' feature must be the last one defined,
28912 // so that code in getMatches can skip this test if `hasMatch = true`
28913 defineFeature('others', function isOther(entity, resolver, geometry) {
28914 return (geometry === 'line' || geometry === 'area');
28918 function features() {}
28920 features.features = function() {
28924 features.keys = function() {
28928 features.enabled = function(k) {
28929 if (!arguments.length) {
28930 return _.filter(_keys, function(k) { return _features[k].enabled; });
28932 return _features[k] && _features[k].enabled;
28935 features.disabled = function(k) {
28936 if (!arguments.length) {
28937 return _.reject(_keys, function(k) { return _features[k].enabled; });
28939 return _features[k] && !_features[k].enabled;
28942 features.hidden = function(k) {
28943 if (!arguments.length) {
28944 return _.filter(_keys, function(k) { return _features[k].hidden(); });
28946 return _features[k] && _features[k].hidden();
28949 features.autoHidden = function(k) {
28950 if (!arguments.length) {
28951 return _.filter(_keys, function(k) { return _features[k].autoHidden(); });
28953 return _features[k] && _features[k].autoHidden();
28956 features.enable = function(k) {
28957 if (_features[k] && !_features[k].enabled) {
28958 _features[k].enable();
28963 features.disable = function(k) {
28964 if (_features[k] && _features[k].enabled) {
28965 _features[k].disable();
28970 features.toggle = function(k) {
28971 if (_features[k]) {
28972 (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
28977 features.resetStats = function() {
28978 _.each(_features, function(f) { f.count = 0; });
28982 features.gatherStats = function(d, resolver, dimensions) {
28983 var needsRedraw = false,
28984 type = _.groupBy(d, function(ent) { return ent.type; }),
28985 entities = [].concat(type.relation || [], type.way || [], type.node || []),
28986 currHidden, geometry, matches;
28988 _.each(_features, function(f) { f.count = 0; });
28990 // adjust the threshold for point/building culling based on viewport size..
28991 // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
28992 _cullFactor = dimensions[0] * dimensions[1] / 1000000;
28994 for (var i = 0; i < entities.length; i++) {
28995 geometry = entities[i].geometry(resolver);
28996 if (!(geometry === 'vertex' || geometry === 'relation')) {
28997 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
28998 for (var j = 0; j < matches.length; j++) {
28999 _features[matches[j]].count++;
29004 currHidden = features.hidden();
29005 if (currHidden !== _hidden) {
29006 _hidden = currHidden;
29007 needsRedraw = true;
29011 return needsRedraw;
29014 features.stats = function() {
29015 _.each(_keys, function(k) { _stats[k] = _features[k].count; });
29019 features.clear = function(d) {
29020 for (var i = 0; i < d.length; i++) {
29021 features.clearEntity(d[i]);
29025 features.clearEntity = function(entity) {
29026 delete _cache[iD.Entity.key(entity)];
29029 features.reset = function() {
29033 features.getMatches = function(entity, resolver, geometry) {
29034 if (geometry === 'vertex' || geometry === 'relation') return {};
29036 var ent = iD.Entity.key(entity);
29037 if (!_cache[ent]) {
29041 if (!_cache[ent].matches) {
29045 for (var i = 0; i < _keys.length; i++) {
29046 if (_keys[i] === 'others') {
29047 if (hasMatch) continue;
29049 // Multipolygon members:
29051 // 1. is a way that hasn't matched other "interesting" feature rules,
29052 // 2. and it belongs to a single parent multipolygon relation
29053 // ...then match whatever feature rules the parent multipolygon has matched.
29054 // see #2548, #2887
29057 // For this to work, getMatches must be called on relations before ways.
29059 if (entity.type === 'way') {
29060 var parents = features.getParents(entity, resolver, geometry);
29061 if (parents.length === 1 && parents[0].isMultipolygon()) {
29062 var pkey = iD.Entity.key(parents[0]);
29063 if (_cache[pkey] && _cache[pkey].matches) {
29064 matches = _.clone(_cache[pkey].matches);
29071 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
29072 matches[_keys[i]] = hasMatch = true;
29075 _cache[ent].matches = matches;
29078 return _cache[ent].matches;
29081 features.getParents = function(entity, resolver, geometry) {
29082 if (geometry === 'point') return [];
29084 var ent = iD.Entity.key(entity);
29085 if (!_cache[ent]) {
29089 if (!_cache[ent].parents) {
29091 if (geometry === 'vertex') {
29092 parents = resolver.parentWays(entity);
29093 } else { // 'line', 'area', 'relation'
29094 parents = resolver.parentRelations(entity);
29096 _cache[ent].parents = parents;
29098 return _cache[ent].parents;
29101 features.isHiddenFeature = function(entity, resolver, geometry) {
29102 if (!_hidden.length) return false;
29103 if (!entity.version) return false;
29105 var matches = features.getMatches(entity, resolver, geometry);
29107 for (var i = 0; i < _hidden.length; i++) {
29108 if (matches[_hidden[i]]) return true;
29113 features.isHiddenChild = function(entity, resolver, geometry) {
29114 if (!_hidden.length) return false;
29115 if (!entity.version || geometry === 'point') return false;
29117 var parents = features.getParents(entity, resolver, geometry);
29118 if (!parents.length) return false;
29120 for (var i = 0; i < parents.length; i++) {
29121 if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
29128 features.hasHiddenConnections = function(entity, resolver) {
29129 if (!_hidden.length) return false;
29130 var childNodes, connections;
29132 if (entity.type === 'midpoint') {
29133 childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
29136 childNodes = entity.nodes ? resolver.childNodes(entity) : [];
29137 connections = features.getParents(entity, resolver, entity.geometry(resolver));
29140 // gather ways connected to child nodes..
29141 connections = _.reduce(childNodes, function(result, e) {
29142 return resolver.isShared(e) ? _.union(result, resolver.parentWays(e)) : result;
29145 return connections.length ? _.any(connections, function(e) {
29146 return features.isHidden(e, resolver, e.geometry(resolver));
29150 features.isHidden = function(entity, resolver, geometry) {
29151 if (!_hidden.length) return false;
29152 if (!entity.version) return false;
29154 var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
29155 return fn(entity, resolver, geometry);
29158 features.filter = function(d, resolver) {
29159 if (!_hidden.length) return d;
29162 for (var i = 0; i < d.length; i++) {
29164 if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
29165 result.push(entity);
29171 return d3.rebind(features, dispatch, 'on');
29173 iD.Map = function(context) {
29174 var dimensions = [1, 1],
29175 dispatch = d3.dispatch('move', 'drawn'),
29176 projection = context.projection,
29177 zoom = d3.behavior.zoom()
29178 .translate(projection.translate())
29179 .scale(projection.scale() * 2 * Math.PI)
29180 .scaleExtent([1024, 256 * Math.pow(2, 24)])
29181 .on('zoom', zoomPan),
29182 dblclickEnabled = true,
29183 redrawEnabled = true,
29185 transformed = false,
29187 drawLayers = iD.svg.Layers(projection, context),
29188 drawPoints = iD.svg.Points(projection, context),
29189 drawVertices = iD.svg.Vertices(projection, context),
29190 drawLines = iD.svg.Lines(projection),
29191 drawAreas = iD.svg.Areas(projection),
29192 drawMidpoints = iD.svg.Midpoints(projection, context),
29193 drawLabels = iD.svg.Labels(projection, context),
29200 function map(selection) {
29202 .on('change.map', redraw);
29203 context.background()
29204 .on('change.map', redraw);
29206 .on('redraw.map', redraw);
29209 .on('dblclick.map', dblClick)
29212 supersurface = selection.append('div')
29213 .attr('id', 'supersurface')
29214 .call(iD.util.setTransform, 0, 0);
29216 // Need a wrapper div because Opera can't cope with an absolutely positioned
29217 // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
29218 wrapper = supersurface
29220 .attr('class', 'layer layer-data');
29222 map.surface = surface = wrapper
29224 .selectAll('.surface')
29225 .attr('id', 'surface');
29228 .on('mousedown.zoom', function() {
29229 if (d3.event.button === 2) {
29230 d3.event.stopPropagation();
29233 .on('mouseup.zoom', function() {
29234 if (resetTransform()) redraw();
29236 .on('mousemove.map', function() {
29237 mousemove = d3.event;
29239 .on('mouseover.vertices', function() {
29240 if (map.editable() && !transformed) {
29241 var hover = d3.event.target.__data__;
29242 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
29243 dispatch.drawn({full: false});
29246 .on('mouseout.vertices', function() {
29247 if (map.editable() && !transformed) {
29248 var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__;
29249 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
29250 dispatch.drawn({full: false});
29256 .call(context.background());
29259 context.on('enter.map', function() {
29260 if (map.editable() && !transformed) {
29261 var all = context.intersects(map.extent()),
29262 filter = d3.functor(true),
29263 graph = context.graph();
29265 all = context.features().filter(all, graph);
29267 .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
29268 .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
29269 dispatch.drawn({full: false});
29273 map.dimensions(selection.dimensions());
29275 drawLabels.supersurface(supersurface);
29278 function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }
29280 function drawVector(difference, extent) {
29281 var graph = context.graph(),
29282 features = context.features(),
29283 all = context.intersects(map.extent()),
29287 var complete = difference.complete(map.extent());
29288 data = _.compact(_.values(complete));
29289 filter = function(d) { return d.id in complete; };
29290 features.clear(data);
29293 // force a full redraw if gatherStats detects that a feature
29294 // should be auto-hidden (e.g. points or buildings)..
29295 if (features.gatherStats(all, graph, dimensions)) {
29296 extent = undefined;
29300 data = context.intersects(map.extent().intersection(extent));
29301 var set = d3.set(_.pluck(data, 'id'));
29302 filter = function(d) { return set.has(d.id); };
29306 filter = d3.functor(true);
29310 data = features.filter(data, graph);
29313 .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
29314 .call(drawLines, graph, data, filter)
29315 .call(drawAreas, graph, data, filter)
29316 .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
29317 .call(drawLabels, graph, data, filter, dimensions, !difference && !extent)
29318 .call(drawPoints, graph, data, filter);
29320 dispatch.drawn({full: true});
29323 function editOff() {
29324 context.features().resetStats();
29325 surface.selectAll('.layer-osm *').remove();
29326 dispatch.drawn({full: true});
29329 function dblClick() {
29330 if (!dblclickEnabled) {
29331 d3.event.preventDefault();
29332 d3.event.stopImmediatePropagation();
29336 function zoomPan() {
29337 if (Math.log(d3.event.scale) / Math.LN2 - 8 < minzoom) {
29338 surface.interrupt();
29339 iD.ui.flash(context.container())
29340 .select('.content')
29341 .text(t('cannot_zoom'));
29342 setZoom(context.minEditableZoom(), true);
29344 dispatch.move(map);
29349 .translate(d3.event.translate)
29350 .scale(d3.event.scale / (2 * Math.PI));
29352 var scale = d3.event.scale / transformStart[0],
29353 tX = (d3.event.translate[0] / scale - transformStart[1][0]) * scale,
29354 tY = (d3.event.translate[1] / scale - transformStart[1][1]) * scale;
29356 transformed = true;
29357 iD.util.setTransform(supersurface, tX, tY, scale);
29360 dispatch.move(map);
29363 function resetTransform() {
29364 if (!transformed) return false;
29366 surface.selectAll('.radial-menu').interrupt().remove();
29367 iD.util.setTransform(supersurface, 0, 0);
29368 transformed = false;
29372 function redraw(difference, extent) {
29373 if (!surface || !redrawEnabled) return;
29375 clearTimeout(timeoutId);
29377 // If we are in the middle of a zoom/pan, we can't do differenced redraws.
29378 // It would result in artifacts where differenced entities are redrawn with
29379 // one transform and unchanged entities with another.
29380 if (resetTransform()) {
29381 difference = extent = undefined;
29384 var zoom = String(~~map.zoom());
29385 if (surface.attr('data-zoom') !== zoom) {
29386 surface.attr('data-zoom', zoom)
29387 .classed('low-zoom', zoom <= 16);
29391 supersurface.call(context.background());
29395 if (map.editable()) {
29396 context.loadTiles(projection, dimensions);
29397 drawVector(difference, extent);
29406 projection.scale() * 2 * Math.PI,
29407 projection.translate().slice()];
29413 function queueRedraw() {
29414 clearTimeout(timeoutId);
29415 timeoutId = setTimeout(function() { redraw(); }, 300);
29418 function pointLocation(p) {
29419 var translate = projection.translate(),
29420 scale = projection.scale() * 2 * Math.PI;
29421 return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
29424 function locationPoint(l) {
29425 var translate = projection.translate(),
29426 scale = projection.scale() * 2 * Math.PI;
29427 return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
29430 map.mouse = function() {
29431 var e = mousemove || d3.event, s;
29432 while ((s = e.sourceEvent)) e = s;
29436 map.mouseCoordinates = function() {
29437 return projection.invert(map.mouse());
29440 map.dblclickEnable = function(_) {
29441 if (!arguments.length) return dblclickEnabled;
29442 dblclickEnabled = _;
29446 map.redrawEnable = function(_) {
29447 if (!arguments.length) return redrawEnabled;
29452 function interpolateZoom(_) {
29453 var k = projection.scale(),
29454 t = projection.translate();
29456 surface.node().__chart__ = {
29463 projection.scale(k).translate(t); // undo setZoom projection changes
29465 zoom.event(surface.transition());
29468 function setZoom(_, force) {
29469 if (_ === map.zoom() && !force)
29471 var scale = 256 * Math.pow(2, _),
29472 center = pxCenter(),
29473 l = pointLocation(center);
29474 scale = Math.max(1024, Math.min(256 * Math.pow(2, 24), scale));
29475 projection.scale(scale / (2 * Math.PI));
29477 var t = projection.translate();
29478 l = locationPoint(l);
29479 t[0] += center[0] - l[0];
29480 t[1] += center[1] - l[1];
29481 projection.translate(t);
29482 zoom.translate(projection.translate());
29486 function setCenter(_) {
29487 var c = map.center();
29488 if (_[0] === c[0] && _[1] === c[1])
29490 var t = projection.translate(),
29492 ll = projection(_);
29493 projection.translate([
29494 t[0] - ll[0] + pxC[0],
29495 t[1] - ll[1] + pxC[1]]);
29496 zoom.translate(projection.translate());
29500 map.pan = function(d) {
29501 var t = projection.translate();
29504 projection.translate(t);
29505 zoom.translate(projection.translate());
29506 dispatch.move(map);
29510 map.dimensions = function(_) {
29511 if (!arguments.length) return dimensions;
29512 var center = map.center();
29514 drawLayers.dimensions(dimensions);
29515 context.background().dimensions(dimensions);
29516 projection.clipExtent([[0, 0], dimensions]);
29517 mouse = iD.util.fastMouse(supersurface.node());
29522 function zoomIn(integer) {
29523 interpolateZoom(~~map.zoom() + integer);
29526 function zoomOut(integer) {
29527 interpolateZoom(~~map.zoom() - integer);
29530 map.zoomIn = function() { zoomIn(1); };
29531 map.zoomInFurther = function() { zoomIn(4); };
29533 map.zoomOut = function() { zoomOut(1); };
29534 map.zoomOutFurther = function() { zoomOut(4); };
29536 map.center = function(loc) {
29537 if (!arguments.length) {
29538 return projection.invert(pxCenter());
29541 if (setCenter(loc)) {
29542 dispatch.move(map);
29548 map.zoom = function(z) {
29549 if (!arguments.length) {
29550 return Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8, 0);
29554 surface.interrupt();
29555 iD.ui.flash(context.container())
29556 .select('.content')
29557 .text(t('cannot_zoom'));
29558 z = context.minEditableZoom();
29562 dispatch.move(map);
29568 map.zoomTo = function(entity, zoomLimits) {
29569 var extent = entity.extent(context.graph());
29570 if (!isFinite(extent.area())) return;
29572 var zoom = map.trimmedExtentZoom(extent);
29573 zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
29574 map.centerZoom(extent.center(), Math.min(Math.max(zoom, zoomLimits[0]), zoomLimits[1]));
29577 map.centerZoom = function(loc, z) {
29578 var centered = setCenter(loc),
29579 zoomed = setZoom(z);
29581 if (centered || zoomed) {
29582 dispatch.move(map);
29588 map.centerEase = function(loc) {
29589 var from = map.center().slice(),
29593 surface.one('mousedown.ease', function() {
29597 d3.timer(function() {
29598 if (stop) return true;
29599 map.center(iD.geo.interp(from, loc, (t += 1) / 10));
29605 map.extent = function(_) {
29606 if (!arguments.length) {
29607 return new iD.geo.Extent(projection.invert([0, dimensions[1]]),
29608 projection.invert([dimensions[0], 0]));
29610 var extent = iD.geo.Extent(_);
29611 map.centerZoom(extent.center(), map.extentZoom(extent));
29615 map.trimmedExtent = function(_) {
29616 if (!arguments.length) {
29617 var headerY = 60, footerY = 30, pad = 10;
29618 return new iD.geo.Extent(projection.invert([pad, dimensions[1] - footerY - pad]),
29619 projection.invert([dimensions[0] - pad, headerY + pad]));
29621 var extent = iD.geo.Extent(_);
29622 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
29626 function calcZoom(extent, dim) {
29627 var tl = projection([extent[0][0], extent[1][1]]),
29628 br = projection([extent[1][0], extent[0][1]]);
29630 // Calculate maximum zoom that fits extent
29631 var hFactor = (br[0] - tl[0]) / dim[0],
29632 vFactor = (br[1] - tl[1]) / dim[1],
29633 hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
29634 vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
29635 newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
29640 map.extentZoom = function(_) {
29641 return calcZoom(iD.geo.Extent(_), dimensions);
29644 map.trimmedExtentZoom = function(_) {
29645 var trimY = 120, trimX = 40,
29646 trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
29647 return calcZoom(iD.geo.Extent(_), trimmed);
29650 map.editable = function() {
29651 return map.zoom() >= context.minEditableZoom();
29654 map.minzoom = function(_) {
29655 if (!arguments.length) return minzoom;
29660 map.layers = drawLayers;
29662 return d3.rebind(map, dispatch, 'on');
29664 iD.TileLayer = function() {
29665 var tileSize = 256,
29666 tile = d3.geo.tile(),
29671 transformProp = iD.util.prefixCSSProperty('Transform'),
29672 source = d3.functor('');
29674 function tileSizeAtZoom(d, z) {
29675 return (tileSize * Math.pow(2, z - d[2])) / tileSize;
29678 function atZoom(t, distance) {
29679 var power = Math.pow(2, distance);
29681 Math.floor(t[0] * power),
29682 Math.floor(t[1] * power),
29686 function lookUp(d) {
29687 for (var up = -1; up > -d[2]; up--) {
29688 var tile = atZoom(d, up);
29689 if (cache[source.url(tile)] !== false) {
29695 function uniqueBy(a, n) {
29696 var o = [], seen = {};
29697 for (var i = 0; i < a.length; i++) {
29698 if (seen[a[i][n]] === undefined) {
29700 seen[a[i][n]] = true;
29706 function addSource(d) {
29707 d.push(source.url(d));
29711 // Update tiles based on current state of `projection`.
29712 function background(selection) {
29713 tile.scale(projection.scale() * 2 * Math.PI)
29714 .translate(projection.translate());
29717 projection.scale() * Math.PI - projection.translate()[0],
29718 projection.scale() * Math.PI - projection.translate()[1]];
29720 z = Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
29725 // Derive the tiles onscreen, remove those offscreen and position them.
29726 // Important that this part not depend on `projection` because it's
29727 // rentered when tiles load/error (see #644).
29728 function render(selection) {
29731 if (source.validZoom(z)) {
29732 tile().forEach(function(d) {
29734 if (d[3] === '') return;
29735 if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
29737 if (cache[d[3]] === false && lookUp(d)) {
29738 requests.push(addSource(lookUp(d)));
29742 requests = uniqueBy(requests, 3).filter(function(r) {
29743 // don't re-request tiles which have failed in the past
29744 return cache[r[3]] !== false;
29748 var pixelOffset = [
29749 source.offset()[0] * Math.pow(2, z),
29750 source.offset()[1] * Math.pow(2, z)
29754 cache[d[3]] = true;
29758 .classed('tile-loaded', true);
29762 function error(d) {
29763 cache[d[3]] = false;
29771 function imageTransform(d) {
29772 var _ts = tileSize * Math.pow(2, z - d[2]);
29773 var scale = tileSizeAtZoom(d, z);
29774 return 'translate(' +
29775 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
29776 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
29777 'scale(' + scale + ',' + scale + ')';
29780 var image = selection
29782 .data(requests, function(d) { return d[3]; });
29785 .style(transformProp, imageTransform)
29786 .classed('tile-removing', true)
29788 var tile = d3.select(this);
29789 window.setTimeout(function() {
29790 if (tile.classed('tile-removing')) {
29796 image.enter().append('img')
29797 .attr('class', 'tile')
29798 .attr('src', function(d) { return d[3]; })
29799 .on('error', error)
29803 .style(transformProp, imageTransform)
29804 .classed('tile-removing', false);
29807 background.projection = function(_) {
29808 if (!arguments.length) return projection;
29813 background.dimensions = function(_) {
29814 if (!arguments.length) return tile.size();
29819 background.source = function(_) {
29820 if (!arguments.length) return source;
29823 tile.scaleExtent(source.scaleExtent);
29830 PointTransform: function(projection) {
29831 return function(entity) {
29832 // http://jsperf.com/short-array-join
29833 var pt = projection(entity.loc);
29834 return 'translate(' + pt[0] + ',' + pt[1] + ')';
29838 Path: function(projection, graph, polygon) {
29840 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
29841 project = projection.stream,
29842 path = d3.geo.path()
29843 .projection({stream: function(output) { return polygon ? project(output) : project(clip(output)); }});
29845 return function(entity) {
29846 if (entity.id in cache) {
29847 return cache[entity.id];
29849 return cache[entity.id] = path(entity.asGeoJSON(graph));
29854 OneWaySegments: function(projection, graph, dt) {
29855 return function(entity) {
29861 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
29862 coordinates = graph.childNodes(entity).map(function(n) {
29866 if (entity.tags.oneway === '-1') coordinates.reverse();
29869 type: 'LineString',
29870 coordinates: coordinates
29871 }, projection.stream(clip({
29872 lineStart: function() {},
29873 lineEnd: function() {
29876 point: function(x, y) {
29880 var span = iD.geo.euclideanDistance(a, b) - offset;
29883 var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
29884 dx = dt * Math.cos(angle),
29885 dy = dt * Math.sin(angle),
29886 p = [a[0] + offset * Math.cos(angle),
29887 a[1] + offset * Math.sin(angle)];
29889 var segment = 'M' + a[0] + ',' + a[1] +
29890 'L' + p[0] + ',' + p[1];
29892 for (span -= dt; span >= 0; span -= dt) {
29895 segment += 'L' + p[0] + ',' + p[1];
29898 segment += 'L' + b[0] + ',' + b[1];
29899 segments.push({id: entity.id, index: i, d: segment});
29914 RelationMemberTags: function(graph) {
29915 return function(entity) {
29916 var tags = entity.tags;
29917 graph.parentRelations(entity).forEach(function(relation) {
29918 var type = relation.tags.type;
29919 if (type === 'multipolygon' || type === 'boundary') {
29920 tags = _.extend({}, relation.tags, tags);
29927 iD.svg.Areas = function(projection) {
29928 // Patterns only work in Firefox when set directly on element.
29929 // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
29931 wetland: 'wetland',
29934 construction: 'construction',
29935 military: 'construction',
29936 cemetery: 'cemetery',
29937 grave_yard: 'cemetery',
29940 farmland: 'farmland',
29944 var patternKeys = ['landuse', 'natural', 'amenity'];
29946 function setPattern(d) {
29947 for (var i = 0; i < patternKeys.length; i++) {
29948 if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
29949 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
29953 this.style.fill = this.style.stroke = '';
29956 return function drawAreas(surface, graph, entities, filter) {
29957 var path = iD.svg.Path(projection, graph, true),
29961 for (var i = 0; i < entities.length; i++) {
29962 var entity = entities[i];
29963 if (entity.geometry(graph) !== 'area') continue;
29965 multipolygon = iD.geo.isSimpleMultipolygonOuterMember(entity, graph);
29966 if (multipolygon) {
29967 areas[multipolygon.id] = {
29968 entity: multipolygon.mergeTags(entity.tags),
29969 area: Math.abs(entity.area(graph))
29971 } else if (!areas[entity.id]) {
29972 areas[entity.id] = {
29974 area: Math.abs(entity.area(graph))
29979 areas = d3.values(areas).filter(function hasPath(a) { return path(a.entity); });
29980 areas.sort(function areaSort(a, b) { return b.area - a.area; });
29981 areas = _.pluck(areas, 'entity');
29983 var strokes = areas.filter(function(area) {
29984 return area.type === 'way';
29994 var clipPaths = surface.selectAll('defs').selectAll('.clipPath')
29996 .data(data.clip, iD.Entity.key);
29999 .append('clipPath')
30000 .attr('class', 'clipPath')
30001 .attr('id', function(entity) { return entity.id + '-clippath'; })
30004 clipPaths.selectAll('path')
30010 var areagroup = surface
30011 .selectAll('.layer-areas')
30012 .selectAll('g.areagroup')
30013 .data(['fill', 'shadow', 'stroke']);
30017 .attr('class', function(d) { return 'layer areagroup area-' + d; });
30019 var paths = areagroup
30022 .data(function(layer) { return data[layer]; }, iD.Entity.key);
30024 // Remove exiting areas first, so they aren't included in the `fills`
30025 // array used for sorting below (https://github.com/openstreetmap/iD/issues/1903).
30029 var fills = surface.selectAll('.area-fill path.area')[0];
30031 var bisect = d3.bisector(function(node) {
30032 return -node.__data__.area(graph);
30035 function sortedByArea(entity) {
30036 if (this.__data__ === 'fill') {
30037 return fills[bisect(fills, -entity.area(graph))];
30042 .insert('path', sortedByArea)
30043 .each(function(entity) {
30044 var layer = this.parentNode.__data__;
30046 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
30048 if (layer === 'fill') {
30049 this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
30050 setPattern.apply(this, arguments);
30053 .call(iD.svg.TagClasses());
30060 A standalone SVG element that contains only a `defs` sub-element. To be
30061 used once globally, since defs IDs must be unique within a document.
30063 iD.svg.Defs = function(context) {
30065 function SVGSpriteDefinition(id, href) {
30066 return function(defs) {
30067 d3.xml(href, 'image/svg+xml', function(err, svg) {
30069 defs.node().appendChild(
30070 d3.select(svg.documentElement).attr('id', id).node()
30076 return function drawDefs(selection) {
30077 var defs = selection.append('defs');
30080 defs.append('marker')
30082 id: 'oneway-marker',
30083 viewBox: '0 0 10 10',
30088 markerUnits: 'strokeWidth',
30092 .attr('class', 'oneway')
30093 .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')
30094 .attr('stroke', 'none')
30095 .attr('fill', '#000')
30096 .attr('opacity', '0.5');
30099 var patterns = defs.selectAll('pattern')
30101 // pattern name, pattern image name
30102 ['wetland', 'wetland'],
30103 ['construction', 'construction'],
30104 ['cemetery', 'cemetery'],
30105 ['orchard', 'orchard'],
30106 ['farmland', 'farmland'],
30115 return 'pattern-' + d[0];
30119 patternUnits: 'userSpaceOnUse'
30122 patterns.append('rect')
30128 'class': function (d) {
30129 return 'pattern-color-' + d[0];
30133 patterns.append('image')
30140 .attr('xlink:href', function (d) {
30141 return context.imagePath('pattern/' + d[1] + '.png');
30146 .data([12, 18, 20, 32, 45])
30147 .enter().append('clipPath')
30148 .attr('id', function (d) {
30149 return 'clip-square-' + d;
30154 .attr('width', function (d) {
30157 .attr('height', function (d) {
30161 defs.call(SVGSpriteDefinition(
30163 context.imagePath('iD-sprite.svg')));
30165 defs.call(SVGSpriteDefinition(
30167 context.imagePath('maki-sprite.svg')));
30170 iD.svg.Gpx = function(projection, context) {
30171 var showLabels = true,
30175 if (iD.svg.Gpx.initialized) return; // run once
30177 iD.svg.Gpx.geojson = {};
30178 iD.svg.Gpx.enabled = true;
30181 d3.event.stopPropagation();
30182 d3.event.preventDefault();
30183 d3.event.dataTransfer.dropEffect = 'copy';
30187 .attr('dropzone', 'copy')
30188 .on('drop.localgpx', function() {
30189 d3.event.stopPropagation();
30190 d3.event.preventDefault();
30191 if (!iD.detect().filedrop) return;
30192 drawGpx.files(d3.event.dataTransfer.files);
30194 .on('dragenter.localgpx', over)
30195 .on('dragexit.localgpx', over)
30196 .on('dragover.localgpx', over);
30198 iD.svg.Gpx.initialized = true;
30202 function drawGpx(surface) {
30203 var geojson = iD.svg.Gpx.geojson,
30204 enabled = iD.svg.Gpx.enabled;
30206 layer = surface.selectAll('.layer-gpx')
30207 .data(enabled ? [0] : []);
30211 .attr('class', 'layer-gpx');
30223 .attr('class', 'gpx');
30228 var path = d3.geo.path()
30229 .projection(projection);
30235 var labels = layer.selectAll('text')
30236 .data(showLabels && geojson.features ? geojson.features : []);
30240 .attr('class', 'gpx')
30241 .text(function(d) {
30242 return d.properties.desc || d.properties.name;
30249 .attr('x', function(d) {
30250 var centroid = path.centroid(d);
30251 return centroid[0] + 7;
30253 .attr('y', function(d) {
30254 var centroid = path.centroid(d);
30255 return centroid[1];
30260 function toDom(x) {
30261 return (new DOMParser()).parseFromString(x, 'text/xml');
30264 function redraw() {
30265 context.pan([0,0]);
30268 drawGpx.showLabels = function(_) {
30269 if (!arguments.length) return showLabels;
30274 drawGpx.enabled = function(_) {
30275 if (!arguments.length) return iD.svg.Gpx.enabled;
30276 iD.svg.Gpx.enabled = _;
30280 drawGpx.hasGpx = function() {
30281 var geojson = iD.svg.Gpx.geojson;
30282 return (!(_.isEmpty(geojson) || _.isEmpty(geojson.features)));
30285 drawGpx.geojson = function(gj) {
30286 if (!arguments.length) return iD.svg.Gpx.geojson;
30287 if (_.isEmpty(gj) || _.isEmpty(gj.features)) return this;
30288 iD.svg.Gpx.geojson = gj;
30292 drawGpx.url = function(url) {
30293 d3.text(url, function(err, data) {
30295 drawGpx.geojson(toGeoJSON.gpx(toDom(data)));
30302 drawGpx.files = function(fileList) {
30303 var f = fileList[0],
30304 reader = new FileReader();
30306 reader.onload = function(e) {
30307 drawGpx.geojson(toGeoJSON.gpx(toDom(e.target.result))).fitZoom();
30311 reader.readAsText(f);
30315 drawGpx.fitZoom = function() {
30316 if (!this.hasGpx()) return this;
30317 var geojson = iD.svg.Gpx.geojson;
30319 var map = context.map(),
30320 viewport = map.trimmedExtent().polygon(),
30321 coords = _.reduce(geojson.features, function(coords, feature) {
30322 var c = feature.geometry.coordinates;
30323 return _.union(coords, feature.geometry.type === 'Point' ? [c] : c);
30326 if (!iD.geo.polygonIntersectsPolygon(viewport, coords, true)) {
30327 var extent = iD.geo.Extent(d3.geo.bounds(geojson));
30328 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
30337 iD.svg.Icon = function(name, svgklass, useklass) {
30338 return function drawIcon(selection) {
30339 selection.selectAll('svg')
30343 .attr('class', 'icon ' + (svgklass || ''))
30345 .attr('xlink:href', name)
30346 .attr('class', useklass);
30349 iD.svg.Labels = function(projection, context) {
30350 var path = d3.geo.path().projection(projection);
30352 // Replace with dict and iterate over entities tags instead?
30353 var label_stack = [
30354 ['line', 'aeroway'],
30355 ['line', 'highway'],
30356 ['line', 'railway'],
30357 ['line', 'waterway'],
30358 ['area', 'aeroway'],
30359 ['area', 'amenity'],
30360 ['area', 'building'],
30361 ['area', 'historic'],
30362 ['area', 'leisure'],
30363 ['area', 'man_made'],
30364 ['area', 'natural'],
30366 ['area', 'tourism'],
30367 ['point', 'aeroway'],
30368 ['point', 'amenity'],
30369 ['point', 'building'],
30370 ['point', 'historic'],
30371 ['point', 'leisure'],
30372 ['point', 'man_made'],
30373 ['point', 'natural'],
30375 ['point', 'tourism'],
30381 var default_size = 12;
30383 var font_sizes = label_stack.map(function(d) {
30384 var style = iD.util.getStyle('text.' + d[0] + '.tag-' + d[1]),
30385 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
30386 if (m) return parseInt(m[1], 10);
30388 style = iD.util.getStyle('text.' + d[0]);
30389 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
30390 if (m) return parseInt(m[1], 10);
30392 return default_size;
30397 var pointOffsets = [
30398 [15, -11, 'start'], // right
30399 [10, -11, 'start'], // unused right now
30403 var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25,
30404 75, 20, 80, 15, 95, 10, 90, 5, 95];
30407 var noIcons = ['building', 'landuse', 'natural'];
30408 function blacklisted(preset) {
30409 return _.any(noIcons, function(s) {
30410 return preset.id.indexOf(s) >= 0;
30414 function get(array, prop) {
30415 return function(d, i) { return array[i][prop]; };
30418 var textWidthCache = {};
30420 function textWidth(text, size, elem) {
30421 var c = textWidthCache[size];
30422 if (!c) c = textWidthCache[size] = {};
30428 c[text] = elem.getComputedTextLength();
30432 var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
30433 if (str === null) {
30434 return size / 3 * 2 * text.length;
30436 return size / 3 * (2 * text.length + str.length);
30441 function drawLineLabels(group, entities, filter, classes, labels) {
30442 var texts = group.selectAll('text.' + classes)
30444 .data(entities, iD.Entity.key);
30448 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
30449 .append('textPath')
30450 .attr('class', 'textpath');
30453 texts.selectAll('.textpath')
30455 .data(entities, iD.Entity.key)
30457 'startOffset': '50%',
30458 'xlink:href': function(d) { return '#labelpath-' + d.id; }
30460 .text(iD.util.displayName);
30462 texts.exit().remove();
30465 function drawLinePaths(group, entities, filter, classes, labels) {
30466 var halos = group.selectAll('path')
30468 .data(entities, iD.Entity.key);
30472 .style('stroke-width', get(labels, 'font-size'))
30473 .attr('id', function(d) { return 'labelpath-' + d.id; })
30474 .attr('class', classes);
30476 halos.attr('d', get(labels, 'lineString'));
30478 halos.exit().remove();
30481 function drawPointLabels(group, entities, filter, classes, labels) {
30482 var texts = group.selectAll('text.' + classes)
30484 .data(entities, iD.Entity.key);
30488 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; });
30490 texts.attr('x', get(labels, 'x'))
30491 .attr('y', get(labels, 'y'))
30492 .style('text-anchor', get(labels, 'textAnchor'))
30493 .text(iD.util.displayName)
30494 .each(function(d, i) { textWidth(iD.util.displayName(d), labels[i].height, this); });
30496 texts.exit().remove();
30500 function drawAreaLabels(group, entities, filter, classes, labels) {
30501 entities = entities.filter(hasText);
30502 labels = labels.filter(hasText);
30503 return drawPointLabels(group, entities, filter, classes, labels);
30505 function hasText(d, i) {
30506 return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
30510 function drawAreaIcons(group, entities, filter, classes, labels) {
30511 var icons = group.selectAll('use')
30513 .data(entities, iD.Entity.key);
30517 .attr('class', 'icon areaicon')
30518 .attr('width', '18px')
30519 .attr('height', '18px');
30521 icons.attr('transform', get(labels, 'transform'))
30522 .attr('xlink:href', function(d) {
30523 var icon = context.presets().match(d, context.graph()).icon;
30524 return '#' + icon + (icon === 'hairdresser' ? '-24': '-18'); // workaround: maki hairdresser-18 broken?
30528 icons.exit().remove();
30531 function reverse(p) {
30532 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
30533 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
30536 function lineString(nodes) {
30537 return 'M' + nodes.join('L');
30540 function subpath(nodes, from, to) {
30541 function segmentLength(i) {
30542 var dx = nodes[i][0] - nodes[i + 1][0];
30543 var dy = nodes[i][1] - nodes[i + 1][1];
30544 return Math.sqrt(dx * dx + dy * dy);
30548 start, end, i0, i1;
30549 for (var i = 0; i < nodes.length - 1; i++) {
30550 var current = segmentLength(i);
30552 if (!start && sofar + current >= from) {
30553 portion = (from - sofar) / current;
30555 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
30556 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
30560 if (!end && sofar + current >= to) {
30561 portion = (to - sofar) / current;
30563 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
30564 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
30571 var ret = nodes.slice(i0, i1);
30572 ret.unshift(start);
30578 function hideOnMouseover() {
30579 var layers = d3.select(this)
30580 .selectAll('.layer-label, .layer-halo');
30582 layers.selectAll('.proximate')
30583 .classed('proximate', false);
30585 var mouse = context.mouse(),
30587 rect = [mouse[0] - pad, mouse[1] - pad, mouse[0] + pad, mouse[1] + pad],
30588 ids = _.pluck(rtree.search(rect), 'id');
30590 if (!ids.length) return;
30591 layers.selectAll('.' + ids.join(', .'))
30592 .classed('proximate', true);
30595 var rtree = rbush(),
30598 function drawLabels(surface, graph, entities, filter, dimensions, fullRedraw) {
30599 var hidePoints = !surface.selectAll('.node.point').node();
30601 var labelable = [], i, k, entity;
30602 for (i = 0; i < label_stack.length; i++) labelable.push([]);
30608 for (i = 0; i < entities.length; i++) {
30609 rtree.remove(rectangles[entities[i].id]);
30613 // Split entities into groups specified by label_stack
30614 for (i = 0; i < entities.length; i++) {
30615 entity = entities[i];
30616 var geometry = entity.geometry(graph);
30618 if (geometry === 'vertex')
30620 if (hidePoints && geometry === 'point')
30623 var preset = geometry === 'area' && context.presets().match(entity, graph),
30624 icon = preset && !blacklisted(preset) && preset.icon;
30626 if (!icon && !iD.util.displayName(entity))
30629 for (k = 0; k < label_stack.length; k++) {
30630 if (geometry === label_stack[k][0] && entity.tags[label_stack[k][1]]) {
30631 labelable[k].push(entity);
30649 // Try and find a valid label for labellable entities
30650 for (k = 0; k < labelable.length; k++) {
30651 var font_size = font_sizes[k];
30652 for (i = 0; i < labelable[k].length; i++) {
30653 entity = labelable[k][i];
30654 var name = iD.util.displayName(entity),
30655 width = name && textWidth(name, font_size),
30657 if (entity.geometry(graph) === 'point') {
30658 p = getPointLabel(entity, width, font_size);
30659 } else if (entity.geometry(graph) === 'line') {
30660 p = getLineLabel(entity, width, font_size);
30661 } else if (entity.geometry(graph) === 'area') {
30662 p = getAreaLabel(entity, width, font_size);
30665 p.classes = entity.geometry(graph) + ' tag-' + label_stack[k][1];
30666 positions[entity.geometry(graph)].push(p);
30667 labelled[entity.geometry(graph)].push(entity);
30672 function getPointLabel(entity, width, height) {
30673 var coord = projection(entity.loc),
30675 offset = pointOffsets[0],
30679 x: coord[0] + offset[0],
30680 y: coord[1] + offset[1],
30681 textAnchor: offset[2]
30683 var rect = [p.x - m, p.y - m, p.x + width + m, p.y + height + m];
30684 if (tryInsert(rect, entity.id)) return p;
30688 function getLineLabel(entity, width, height) {
30689 var nodes = _.pluck(graph.childNodes(entity), 'loc').map(projection),
30690 length = iD.geo.pathLength(nodes);
30691 if (length < width + 20) return;
30693 for (var i = 0; i < lineOffsets.length; i++) {
30694 var offset = lineOffsets[i],
30695 middle = offset / 100 * length,
30696 start = middle - width/2;
30697 if (start < 0 || start + width > length) continue;
30698 var sub = subpath(nodes, start, start + width),
30699 rev = reverse(sub),
30701 Math.min(sub[0][0], sub[sub.length - 1][0]) - 10,
30702 Math.min(sub[0][1], sub[sub.length - 1][1]) - 10,
30703 Math.max(sub[0][0], sub[sub.length - 1][0]) + 20,
30704 Math.max(sub[0][1], sub[sub.length - 1][1]) + 30
30706 if (rev) sub = sub.reverse();
30707 if (tryInsert(rect, entity.id)) return {
30708 'font-size': height + 2,
30709 lineString: lineString(sub),
30710 startOffset: offset + '%'
30715 function getAreaLabel(entity, width, height) {
30716 var centroid = path.centroid(entity.asGeoJSON(graph, true)),
30717 extent = entity.extent(graph),
30718 entitywidth = projection(extent[1])[0] - projection(extent[0])[0],
30721 if (isNaN(centroid[0]) || entitywidth < 20) return;
30723 var iconX = centroid[0] - (iconSize/2),
30724 iconY = centroid[1] - (iconSize/2),
30725 textOffset = iconSize + 5;
30728 transform: 'translate(' + iconX + ',' + iconY + ')'
30731 if (width && entitywidth >= width + 20) {
30733 p.y = centroid[1] + textOffset;
30734 p.textAnchor = 'middle';
30736 rect = [p.x - width/2, p.y, p.x + width/2, p.y + height + textOffset];
30738 rect = [iconX, iconY, iconX + iconSize, iconY + iconSize];
30741 if (tryInsert(rect, entity.id)) return p;
30745 function tryInsert(rect, id) {
30746 // Check that label is visible
30747 if (rect[0] < 0 || rect[1] < 0 || rect[2] > dimensions[0] ||
30748 rect[3] > dimensions[1]) return false;
30749 var v = rtree.search(rect).length === 0;
30752 rtree.insert(rect);
30753 rectangles[id] = rect;
30758 var label = surface.selectAll('.layer-label'),
30759 halo = surface.selectAll('.layer-halo');
30762 drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
30763 drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
30766 drawLinePaths(halo, labelled.line, filter, '', positions.line);
30767 drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
30768 drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
30771 drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
30772 drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
30773 drawAreaIcons(label, labelled.area, filter, 'arealabel-icon', positions.area);
30776 drawLabels.supersurface = function(supersurface) {
30778 .on('mousemove.hidelabels', hideOnMouseover)
30779 .on('mousedown.hidelabels', function () {
30780 supersurface.on('mousemove.hidelabels', null);
30782 .on('mouseup.hidelabels', function () {
30783 supersurface.on('mousemove.hidelabels', hideOnMouseover);
30789 iD.svg.Layers = function(projection, context) {
30790 var svg = d3.select(null),
30792 { id: 'osm', layer: iD.svg.Osm(projection, context) },
30793 { id: 'gpx', layer: iD.svg.Gpx(projection, context) },
30794 { id: 'mapillary-images', layer: iD.svg.MapillaryImages(projection, context) },
30795 { id: 'mapillary-signs', layer: iD.svg.MapillarySigns(projection, context) }
30799 function drawLayers(selection) {
30800 svg = selection.selectAll('.surface')
30805 .attr('class', 'surface')
30808 var groups = svg.selectAll('.data-layer')
30813 .attr('class', function(d) { return 'data-layer data-layer-' + d.id; });
30816 .each(function(d) { d3.select(this).call(d.layer); });
30822 drawLayers.all = function() {
30826 drawLayers.layer = function(id) {
30827 var obj = _.find(layers, 'id', id);
30828 return obj && obj.layer;
30831 drawLayers.only = function(what) {
30832 var arr = [].concat(what);
30833 drawLayers.remove(_.difference(_.pluck(layers, 'id'), arr));
30837 drawLayers.remove = function(what) {
30838 var arr = [].concat(what);
30839 arr.forEach(function(id) {
30840 layers = _.reject(layers, 'id', id);
30845 drawLayers.add = function(what) {
30846 var arr = [].concat(what);
30847 arr.forEach(function(obj) {
30848 if ('id' in obj && 'layer' in obj) {
30855 drawLayers.dimensions = function(_) {
30856 if (!arguments.length) return svg.dimensions();
30858 layers.forEach(function(obj) {
30859 if (obj.layer.dimensions) {
30860 obj.layer.dimensions(_);
30869 iD.svg.Lines = function(projection) {
30871 var highway_stack = {
30886 function waystack(a, b) {
30887 var as = 0, bs = 0;
30889 if (a.tags.highway) { as -= highway_stack[a.tags.highway]; }
30890 if (b.tags.highway) { bs -= highway_stack[b.tags.highway]; }
30894 return function drawLines(surface, graph, entities, filter) {
30895 var ways = [], pathdata = {}, onewaydata = {},
30896 getPath = iD.svg.Path(projection, graph);
30898 for (var i = 0; i < entities.length; i++) {
30899 var entity = entities[i],
30900 outer = iD.geo.simpleMultipolygonOuterMember(entity, graph);
30902 ways.push(entity.mergeTags(outer.tags));
30903 } else if (entity.geometry(graph) === 'line') {
30908 ways = ways.filter(getPath);
30910 pathdata = _.groupBy(ways, function(way) { return way.layer(); });
30912 _.forOwn(pathdata, function(v, k) {
30913 onewaydata[k] = _(v)
30914 .filter(function(d) { return d.isOneWay(); })
30915 .map(iD.svg.OneWaySegments(projection, graph, 35))
30920 var layergroup = surface
30921 .selectAll('.layer-lines')
30922 .selectAll('g.layergroup')
30923 .data(d3.range(-10, 11));
30927 .attr('class', function(d) { return 'layer layergroup layer' + String(d); });
30930 var linegroup = layergroup
30931 .selectAll('g.linegroup')
30932 .data(['shadow', 'casing', 'stroke']);
30936 .attr('class', function(d) { return 'layer linegroup line-' + d; });
30939 var lines = linegroup
30943 function() { return pathdata[this.parentNode.parentNode.__data__] || []; },
30947 // Optimization: call simple TagClasses only on enter selection. This
30948 // works because iD.Entity.key is defined to include the entity v attribute.
30951 .attr('class', function(d) { return 'way line ' + this.parentNode.__data__ + ' ' + d.id; })
30952 .call(iD.svg.TagClasses());
30956 .attr('d', getPath)
30957 .call(iD.svg.TagClasses().tags(iD.svg.RelationMemberTags(graph)));
30963 var onewaygroup = layergroup
30964 .selectAll('g.onewaygroup')
30967 onewaygroup.enter()
30969 .attr('class', 'layer onewaygroup');
30972 var oneways = onewaygroup
30976 function() { return onewaydata[this.parentNode.parentNode.__data__] || []; },
30977 function(d) { return [d.id, d.index]; }
30982 .attr('class', 'oneway')
30983 .attr('marker-mid', 'url(#oneway-marker)');
30986 .attr('d', function(d) { return d.d; });
30988 if (iD.detect().ie) {
30989 oneways.each(function() { this.parentNode.insertBefore(this, this); });
30997 iD.svg.MapillaryImages = function(projection, context) {
30998 var debouncedRedraw = _.debounce(function () { context.pan([0,0]); }, 1000),
31000 layer = d3.select(null),
31005 if (iD.svg.MapillaryImages.initialized) return; // run once
31006 iD.svg.MapillaryImages.enabled = false;
31007 iD.svg.MapillaryImages.initialized = true;
31010 function getMapillary() {
31011 if (iD.services.mapillary && !_mapillary) {
31012 _mapillary = iD.services.mapillary().on('loadedImages', debouncedRedraw);
31013 } else if (!iD.services.mapillary && _mapillary) {
31019 function showThumbnail(image) {
31020 var mapillary = getMapillary();
31021 if (!mapillary) return;
31023 var thumb = mapillary.selectedThumbnail(),
31024 posX = projection(image.loc)[0],
31025 width = layer.dimensions()[0],
31026 position = (posX < width / 2) ? 'right' : 'left';
31029 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31030 .classed('selected', function(d) { return d.key === thumb.key; });
31033 mapillary.showThumbnail(image.key, position);
31036 function hideThumbnail() {
31037 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31038 .classed('selected', false);
31040 var mapillary = getMapillary();
31042 mapillary.hideThumbnail();
31046 function showLayer() {
31049 .style('opacity', 0)
31052 .style('opacity', 1)
31053 .each('end', debouncedRedraw);
31056 function hideLayer() {
31057 debouncedRedraw.cancel();
31062 .style('opacity', 0)
31063 .each('end', editOff);
31066 function editOn() {
31067 layer.style('display', 'block');
31070 function editOff() {
31071 layer.selectAll('.viewfield-group').remove();
31072 layer.style('display', 'none');
31075 function transform(d) {
31076 var t = iD.svg.PointTransform(projection)(d);
31077 if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
31081 function update() {
31082 var mapillary = getMapillary(),
31083 data = (mapillary ? mapillary.images(projection, layer.dimensions()) : []);
31085 var markers = layer.selectAll('.viewfield-group')
31086 .data(data, function(d) { return d.key; });
31089 var enter = markers.enter()
31091 .attr('class', 'viewfield-group');
31093 enter.append('path')
31094 .attr('class', 'viewfield')
31095 .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
31096 .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');
31098 enter.append('circle')
31109 .attr('transform', transform);
31112 function drawImages(selection) {
31113 var enabled = iD.svg.MapillaryImages.enabled,
31114 mapillary = getMapillary();
31116 layer = selection.selectAll('.layer-mapillary-images')
31117 .data(mapillary ? [0] : []);
31121 .attr('class', 'layer-mapillary-images')
31122 .style('display', enabled ? 'block' : 'none')
31123 .on('click', function() { // deselect/select
31124 var mapillary = getMapillary();
31125 if (!mapillary) return;
31126 var d = d3.event.target.__data__,
31127 thumb = mapillary.selectedThumbnail();
31128 if (thumb && thumb.key === d.key) {
31131 mapillary.selectedThumbnail(d);
31132 context.map().centerEase(d.loc);
31136 .on('mouseover', function() {
31137 var mapillary = getMapillary();
31138 if (!mapillary) return;
31139 showThumbnail(d3.event.target.__data__);
31141 .on('mouseout', function() {
31142 var mapillary = getMapillary();
31143 if (!mapillary) return;
31144 var thumb = mapillary.selectedThumbnail();
31146 showThumbnail(thumb);
31156 if (mapillary && ~~context.map().zoom() >= minZoom) {
31159 mapillary.loadImages(projection, layer.dimensions());
31166 drawImages.enabled = function(_) {
31167 if (!arguments.length) return iD.svg.MapillaryImages.enabled;
31168 iD.svg.MapillaryImages.enabled = _;
31169 if (iD.svg.MapillaryImages.enabled) {
31177 drawImages.supported = function() {
31178 return !!getMapillary();
31181 drawImages.dimensions = function(_) {
31182 if (!arguments.length) return layer.dimensions();
31183 layer.dimensions(_);
31190 iD.svg.MapillarySigns = function(projection, context) {
31191 var debouncedRedraw = _.debounce(function () { context.pan([0,0]); }, 1000),
31193 layer = d3.select(null),
31198 if (iD.svg.MapillarySigns.initialized) return; // run once
31199 iD.svg.MapillarySigns.enabled = false;
31200 iD.svg.MapillarySigns.initialized = true;
31203 function getMapillary() {
31204 if (iD.services.mapillary && !_mapillary) {
31205 _mapillary = iD.services.mapillary().on('loadedSigns', debouncedRedraw);
31206 } else if (!iD.services.mapillary && _mapillary) {
31212 function showThumbnail(image) {
31213 var mapillary = getMapillary();
31214 if (!mapillary) return;
31216 var thumb = mapillary.selectedThumbnail(),
31217 posX = projection(image.loc)[0],
31218 width = layer.dimensions()[0],
31219 position = (posX < width / 2) ? 'right' : 'left';
31222 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31223 .classed('selected', function(d) { return d.key === thumb.key; });
31226 mapillary.showThumbnail(image.key, position);
31229 function hideThumbnail() {
31230 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31231 .classed('selected', false);
31233 var mapillary = getMapillary();
31235 mapillary.hideThumbnail();
31239 function showLayer() {
31244 function hideLayer() {
31245 debouncedRedraw.cancel();
31250 function editOn() {
31251 layer.style('display', 'block');
31254 function editOff() {
31255 layer.selectAll('.icon-sign').remove();
31256 layer.style('display', 'none');
31259 function update() {
31260 var mapillary = getMapillary(),
31261 data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []);
31263 var signs = layer.selectAll('.icon-sign')
31264 .data(data, function(d) { return d.key; });
31267 var enter = signs.enter()
31268 .append('foreignObject')
31269 .attr('class', 'icon-sign')
31270 .attr('width', '32px') // for Firefox
31271 .attr('height', '32px'); // for Firefox
31274 .append('xhtml:body')
31275 .html(mapillary.signHTML);
31278 .on('click', function(d) { // deselect/select
31279 var mapillary = getMapillary();
31280 if (!mapillary) return;
31281 var thumb = mapillary.selectedThumbnail();
31282 if (thumb && thumb.key === d.key) {
31285 mapillary.selectedThumbnail(d);
31286 context.map().centerEase(d.loc);
31290 .on('mouseover', showThumbnail)
31291 .on('mouseout', function() {
31292 var mapillary = getMapillary();
31293 if (!mapillary) return;
31294 var thumb = mapillary.selectedThumbnail();
31296 showThumbnail(thumb);
31308 .attr('transform', iD.svg.PointTransform(projection));
31311 function drawSigns(selection) {
31312 var enabled = iD.svg.MapillarySigns.enabled,
31313 mapillary = getMapillary();
31315 layer = selection.selectAll('.layer-mapillary-signs')
31316 .data(mapillary ? [0] : []);
31320 .attr('class', 'layer-mapillary-signs')
31321 .style('display', enabled ? 'block' : 'none')
31322 .attr('transform', 'translate(-16, -16)'); // center signs on loc
31328 if (mapillary && ~~context.map().zoom() >= minZoom) {
31331 mapillary.loadSigns(context, projection, layer.dimensions());
31338 drawSigns.enabled = function(_) {
31339 if (!arguments.length) return iD.svg.MapillarySigns.enabled;
31340 iD.svg.MapillarySigns.enabled = _;
31341 if (iD.svg.MapillarySigns.enabled) {
31349 drawSigns.supported = function() {
31350 var mapillary = getMapillary();
31351 return (mapillary && mapillary.signsSupported());
31354 drawSigns.dimensions = function(_) {
31355 if (!arguments.length) return layer.dimensions();
31356 layer.dimensions(_);
31363 iD.svg.Midpoints = function(projection, context) {
31364 return function drawMidpoints(surface, graph, entities, filter, extent) {
31365 var poly = extent.polygon(),
31368 for (var i = 0; i < entities.length; i++) {
31369 var entity = entities[i];
31371 if (entity.type !== 'way')
31373 if (!filter(entity))
31375 if (context.selectedIDs().indexOf(entity.id) < 0)
31378 var nodes = graph.childNodes(entity);
31379 for (var j = 0; j < nodes.length - 1; j++) {
31383 id = [a.id, b.id].sort().join('-');
31385 if (midpoints[id]) {
31386 midpoints[id].parents.push(entity);
31388 if (iD.geo.euclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
31389 var point = iD.geo.interp(a.loc, b.loc, 0.5),
31392 if (extent.intersects(point)) {
31395 for (var k = 0; k < 4; k++) {
31396 point = iD.geo.lineIntersection([a.loc, b.loc], [poly[k], poly[k+1]]);
31398 iD.geo.euclideanDistance(projection(a.loc), projection(point)) > 20 &&
31399 iD.geo.euclideanDistance(projection(b.loc), projection(point)) > 20)
31412 edge: [a.id, b.id],
31421 function midpointFilter(d) {
31422 if (midpoints[d.id])
31425 for (var i = 0; i < d.parents.length; i++)
31426 if (filter(d.parents[i]))
31432 var groups = surface.selectAll('.layer-hit').selectAll('g.midpoint')
31433 .filter(midpointFilter)
31434 .data(_.values(midpoints), function(d) { return d.id; });
31436 var enter = groups.enter()
31437 .insert('g', ':first-child')
31438 .attr('class', 'midpoint');
31440 enter.append('polygon')
31441 .attr('points', '-6,8 10,0 -6,-8')
31442 .attr('class', 'shadow');
31444 enter.append('polygon')
31445 .attr('points', '-3,4 5,0 -3,-4')
31446 .attr('class', 'fill');
31449 .attr('transform', function(d) {
31450 var translate = iD.svg.PointTransform(projection),
31451 a = context.entity(d.edge[0]),
31452 b = context.entity(d.edge[1]),
31453 angle = Math.round(iD.geo.angle(a, b, projection) * (180 / Math.PI));
31454 return translate(d) + ' rotate(' + angle + ')';
31456 .call(iD.svg.TagClasses().tags(
31457 function(d) { return d.parents[0].tags; }
31460 // Propagate data bindings.
31461 groups.select('polygon.shadow');
31462 groups.select('polygon.fill');
31468 iD.svg.Osm = function() {
31469 return function drawOsm(selection) {
31470 var layers = selection.selectAll('.layer-osm')
31471 .data(['areas', 'lines', 'hit', 'halo', 'label']);
31473 layers.enter().append('g')
31474 .attr('class', function(d) { return 'layer-osm layer-' + d; });
31477 iD.svg.Points = function(projection, context) {
31478 function markerPath(selection, klass) {
31480 .attr('class', klass)
31481 .attr('transform', 'translate(-8, -23)')
31482 .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');
31485 function sortY(a, b) {
31486 return b.loc[1] - a.loc[1];
31489 return function drawPoints(surface, graph, entities, filter) {
31490 var wireframe = surface.classed('fill-wireframe'),
31491 points = wireframe ? [] : _.filter(entities, function(e) {
31492 return e.geometry(graph) === 'point';
31495 points.sort(sortY);
31497 var groups = surface.selectAll('.layer-hit').selectAll('g.point')
31499 .data(points, iD.Entity.key);
31501 var group = groups.enter()
31503 .attr('class', function(d) { return 'node point ' + d.id; })
31506 group.append('path')
31507 .call(markerPath, 'shadow');
31509 group.append('path')
31510 .call(markerPath, 'stroke');
31512 group.append('use')
31513 .attr('transform', 'translate(-6, -20)')
31514 .attr('class', 'icon')
31515 .attr('width', '12px')
31516 .attr('height', '12px');
31518 groups.attr('transform', iD.svg.PointTransform(projection))
31519 .call(iD.svg.TagClasses());
31521 // Selecting the following implicitly
31522 // sets the data (point entity) on the element
31523 groups.select('.shadow');
31524 groups.select('.stroke');
31525 groups.select('.icon')
31526 .attr('xlink:href', function(entity) {
31527 var preset = context.presets().match(entity, graph);
31528 return preset.icon ? '#' + preset.icon + '-12' : '';
31535 iD.svg.TagClasses = function() {
31537 'building', 'highway', 'railway', 'waterway', 'aeroway',
31538 'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
31542 'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
31543 'razed', 'demolished', 'obliterated'
31546 'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
31547 'surface', 'tracktype', 'crossing'
31549 tagClassRe = /^tag-/,
31550 tags = function(entity) { return entity.tags; };
31553 var tagClasses = function(selection) {
31554 selection.each(function tagClassesEach(entity) {
31555 var value = this.className,
31556 classes, primary, status;
31558 if (value.baseVal !== undefined) value = value.baseVal;
31560 classes = value.trim().split(/\s+/).filter(function(name) {
31561 return name.length && !tagClassRe.test(name);
31564 var t = tags(entity), i, k, v;
31566 // pick at most one primary classification tag..
31567 for (i = 0; i < primaries.length; i++) {
31570 if (!v || v === 'no') continue;
31573 if (statuses.indexOf(v) !== -1) { // e.g. `railway=abandoned`
31575 classes += ' tag-' + k;
31577 classes += ' tag-' + k + ' tag-' + k + '-' + v;
31583 // add at most one status tag, only if relates to primary tag..
31585 for (i = 0; i < statuses.length; i++) {
31588 if (!v || v === 'no') continue;
31590 if (v === 'yes') { // e.g. `railway=rail + abandoned=yes`
31593 else if (primary && primary === v) { // e.g. `railway=rail + abandoned=railway`
31595 } else if (!primary && primaries.indexOf(v) !== -1) { // e.g. `abandoned=railway`
31598 classes += ' tag-' + v;
31599 } // else ignore e.g. `highway=path + abandoned=railway`
31606 classes += ' tag-status tag-status-' + status;
31609 // add any secondary (structure) tags
31610 for (i = 0; i < secondaries.length; i++) {
31611 k = secondaries[i];
31613 if (!v || v === 'no') continue;
31614 classes += ' tag-' + k + ' tag-' + k + '-' + v;
31617 // For highways, look for surface tagging..
31618 if (primary === 'highway') {
31619 var paved = (t.highway !== 'track');
31622 if (k in iD.pavedTags) {
31623 paved = !!iD.pavedTags[k][v];
31628 classes += ' tag-unpaved';
31632 classes = classes.trim();
31634 if (classes !== value) {
31635 d3.select(this).attr('class', classes);
31640 tagClasses.tags = function(_) {
31641 if (!arguments.length) return tags;
31648 iD.svg.Turns = function(projection) {
31649 return function drawTurns(surface, graph, turns) {
31650 function key(turn) {
31651 return [turn.from.node + turn.via.node + turn.to.node].join('-');
31654 function icon(turn) {
31655 var u = turn.u ? '-u' : '';
31656 if (!turn.restriction)
31657 return '#turn-yes' + u;
31658 var restriction = graph.entity(turn.restriction).tags.restriction;
31660 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
31663 var groups = surface.selectAll('.layer-hit').selectAll('g.turn')
31667 var enter = groups.enter().append('g')
31668 .attr('class', 'turn');
31670 var nEnter = enter.filter(function (turn) { return !turn.u; });
31672 nEnter.append('rect')
31673 .attr('transform', 'translate(-22, -12)')
31674 .attr('width', '44')
31675 .attr('height', '24');
31677 nEnter.append('use')
31678 .attr('transform', 'translate(-22, -12)')
31679 .attr('width', '44')
31680 .attr('height', '24');
31683 var uEnter = enter.filter(function (turn) { return turn.u; });
31685 uEnter.append('circle')
31688 uEnter.append('use')
31689 .attr('transform', 'translate(-16, -16)')
31690 .attr('width', '32')
31691 .attr('height', '32');
31696 .attr('transform', function (turn) {
31697 var v = graph.entity(turn.via.node),
31698 t = graph.entity(turn.to.node),
31699 a = iD.geo.angle(v, t, projection),
31700 p = projection(v.loc),
31701 r = turn.u ? 0 : 60;
31703 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
31704 'rotate(' + a * 180 / Math.PI + ')';
31707 groups.select('use')
31708 .attr('xlink:href', icon);
31710 groups.select('rect');
31711 groups.select('circle');
31721 iD.svg.Vertices = function(projection, context) {
31723 // z16-, z17, z18+, tagged
31724 shadow: [6, 7.5, 7.5, 11.5],
31725 stroke: [2.5, 3.5, 3.5, 7],
31726 fill: [1, 1.5, 1.5, 1.5]
31731 function siblingAndChildVertices(ids, graph, extent) {
31734 function addChildVertices(entity) {
31735 if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
31737 if (entity.type === 'way') {
31738 for (i = 0; i < entity.nodes.length; i++) {
31739 addChildVertices(graph.entity(entity.nodes[i]));
31741 } else if (entity.type === 'relation') {
31742 for (i = 0; i < entity.members.length; i++) {
31743 var member = context.hasEntity(entity.members[i].id);
31745 addChildVertices(member);
31748 } else if (entity.intersects(extent, graph)) {
31749 vertices[entity.id] = entity;
31754 ids.forEach(function(id) {
31755 var entity = context.hasEntity(id);
31756 if (entity && entity.type === 'node') {
31757 vertices[entity.id] = entity;
31758 context.graph().parentWays(entity).forEach(function(entity) {
31759 addChildVertices(entity);
31761 } else if (entity) {
31762 addChildVertices(entity);
31769 function draw(selection, vertices, klass, graph, zoom) {
31771 z = (zoom < 17 ? 0 : zoom < 18 ? 1 : 2);
31773 var groups = selection
31774 .data(vertices, iD.Entity.key);
31776 function icon(entity) {
31777 if (entity.id in icons) return icons[entity.id];
31779 entity.hasInterestingTags() &&
31780 context.presets().match(entity, graph).icon;
31781 return icons[entity.id];
31784 function setClass(klass) {
31785 return function(entity) {
31786 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
31790 function setAttributes(selection) {
31791 ['shadow','stroke','fill'].forEach(function(klass) {
31792 var rads = radiuses[klass];
31793 selection.selectAll('.' + klass)
31794 .each(function(entity) {
31795 var i = z && icon(entity),
31797 r = rads[i ? 3 : z];
31798 this.setAttribute('cx', c);
31799 this.setAttribute('cy', -c);
31800 this.setAttribute('r', r);
31801 if (i && klass === 'fill') {
31802 this.setAttribute('visibility', 'hidden');
31804 this.removeAttribute('visibility');
31809 selection.selectAll('use')
31812 this.removeAttribute('visibility');
31814 this.setAttribute('visibility', 'hidden');
31819 var enter = groups.enter()
31821 .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
31823 enter.append('circle')
31824 .each(setClass('shadow'));
31826 enter.append('circle')
31827 .each(setClass('stroke'));
31829 // Vertices with icons get a `use`.
31830 enter.filter(function(d) { return icon(d); })
31832 .attr('transform', 'translate(-6, -6)')
31833 .attr('xlink:href', function(d) { return '#' + icon(d) + '-12'; })
31834 .attr('width', '12px')
31835 .attr('height', '12px')
31836 .each(setClass('icon'));
31838 // Vertices with tags get a fill.
31839 enter.filter(function(d) { return d.hasInterestingTags(); })
31841 .each(setClass('fill'));
31844 .attr('transform', iD.svg.PointTransform(projection))
31845 .classed('shared', function(entity) { return graph.isShared(entity); })
31846 .call(setAttributes);
31852 function drawVertices(surface, graph, entities, filter, extent, zoom) {
31853 var selected = siblingAndChildVertices(context.selectedIDs(), graph, extent),
31854 wireframe = surface.classed('fill-wireframe'),
31857 for (var i = 0; i < entities.length; i++) {
31858 var entity = entities[i],
31859 geometry = entity.geometry(graph);
31861 if (wireframe && geometry === 'point') {
31862 vertices.push(entity);
31866 if (geometry !== 'vertex')
31869 if (entity.id in selected ||
31870 entity.hasInterestingTags() ||
31871 entity.isIntersection(graph)) {
31872 vertices.push(entity);
31876 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-persistent')
31878 .call(draw, vertices, 'vertex-persistent', graph, zoom);
31880 drawHover(surface, graph, extent, zoom);
31883 function drawHover(surface, graph, extent, zoom) {
31884 var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent) : {};
31886 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-hover')
31887 .call(draw, d3.values(hovered), 'vertex-hover', graph, zoom);
31890 drawVertices.drawHover = function(surface, graph, target, extent, zoom) {
31891 if (target === hover) return;
31893 drawHover(surface, graph, extent, zoom);
31896 return drawVertices;
31898 iD.ui = function(context) {
31899 function render(container) {
31900 var map = context.map();
31902 if (iD.detect().opera) container.classed('opera', true);
31904 var hash = iD.behavior.Hash(context);
31908 if (!hash.hadHash) {
31909 map.centerZoom([0, 0], 2);
31912 container.append('svg')
31913 .attr('id', 'defs')
31914 .call(iD.svg.Defs(context));
31916 container.append('div')
31917 .attr('id', 'sidebar')
31918 .attr('class', 'col4')
31921 var content = container.append('div')
31922 .attr('id', 'content');
31924 var bar = content.append('div')
31926 .attr('class', 'fillD');
31928 content.append('div')
31933 .call(iD.ui.MapInMap(context));
31935 content.append('div')
31936 .call(iD.ui.Info(context));
31939 .attr('class', 'spacer col4');
31941 var limiter = bar.append('div')
31942 .attr('class', 'limiter');
31944 limiter.append('div')
31945 .attr('class', 'button-wrap joined col3')
31946 .call(iD.ui.Modes(context), limiter);
31948 limiter.append('div')
31949 .attr('class', 'button-wrap joined col1')
31950 .call(iD.ui.UndoRedo(context));
31952 limiter.append('div')
31953 .attr('class', 'button-wrap col1')
31954 .call(iD.ui.Save(context));
31957 .attr('class', 'full-screen')
31958 .call(iD.ui.FullScreen(context));
31961 .attr('class', 'spinner')
31962 .call(iD.ui.Spinner(context));
31964 var controls = bar.append('div')
31965 .attr('class', 'map-controls');
31967 controls.append('div')
31968 .attr('class', 'map-control zoombuttons')
31969 .call(iD.ui.Zoom(context));
31971 controls.append('div')
31972 .attr('class', 'map-control geolocate-control')
31973 .call(iD.ui.Geolocate(map));
31975 controls.append('div')
31976 .attr('class', 'map-control background-control')
31977 .call(iD.ui.Background(context));
31979 controls.append('div')
31980 .attr('class', 'map-control map-data-control')
31981 .call(iD.ui.MapData(context));
31983 controls.append('div')
31984 .attr('class', 'map-control help-control')
31985 .call(iD.ui.Help(context));
31987 var about = content.append('div')
31988 .attr('id', 'about');
31990 about.append('div')
31991 .attr('id', 'attrib')
31992 .call(iD.ui.Attribution(context));
31994 var footer = about.append('div')
31995 .attr('id', 'footer')
31996 .attr('class', 'fillD');
31998 footer.append('div')
31999 .attr('class', 'api-status')
32000 .call(iD.ui.Status(context));
32002 footer.append('div')
32003 .attr('id', 'scale-block')
32004 .call(iD.ui.Scale(context));
32006 var aboutList = footer.append('div')
32007 .attr('id', 'info-block')
32009 .attr('id', 'about-list');
32011 if (!context.embed()) {
32012 aboutList.call(iD.ui.Account(context));
32015 aboutList.append('li')
32017 .attr('target', '_blank')
32018 .attr('tabindex', -1)
32019 .attr('href', 'https://github.com/openstreetmap/iD')
32022 var issueLinks = aboutList.append('li');
32024 issueLinks.append('a')
32025 .attr('target', '_blank')
32026 .attr('tabindex', -1)
32027 .attr('href', 'https://github.com/openstreetmap/iD/issues')
32028 .call(iD.svg.Icon('#icon-bug', 'light'))
32029 .call(bootstrap.tooltip()
32030 .title(t('report_a_bug'))
32034 issueLinks.append('a')
32035 .attr('target', '_blank')
32036 .attr('tabindex', -1)
32037 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
32038 .call(iD.svg.Icon('#icon-translate', 'light'))
32039 .call(bootstrap.tooltip()
32040 .title(t('help_translate'))
32044 aboutList.append('li')
32045 .attr('class', 'feature-warning')
32046 .attr('tabindex', -1)
32047 .call(iD.ui.FeatureInfo(context));
32049 aboutList.append('li')
32050 .attr('class', 'user-list')
32051 .attr('tabindex', -1)
32052 .call(iD.ui.Contributors(context));
32054 window.onbeforeunload = function() {
32055 return context.save();
32058 window.onunload = function() {
32059 context.history().unlock();
32062 var mapDimensions = map.dimensions();
32064 d3.select(window).on('resize.editor', function() {
32065 mapDimensions = content.dimensions(null);
32066 map.dimensions(mapDimensions);
32070 return function() {
32071 d3.event.preventDefault();
32072 if (!context.inIntro()) context.pan(d);
32079 var keybinding = d3.keybinding('main')
32080 .on('⌫', function() { d3.event.preventDefault(); })
32081 .on('←', pan([pa, 0]))
32082 .on('↑', pan([0, pa]))
32083 .on('→', pan([-pa, 0]))
32084 .on('↓', pan([0, -pa]))
32085 .on('⇧←', pan([mapDimensions[0], 0]))
32086 .on('⇧↑', pan([0, mapDimensions[1]]))
32087 .on('⇧→', pan([-mapDimensions[0], 0]))
32088 .on('⇧↓', pan([0, -mapDimensions[1]]))
32089 .on(iD.ui.cmd('⌘←'), pan([mapDimensions[0], 0]))
32090 .on(iD.ui.cmd('⌘↑'), pan([0, mapDimensions[1]]))
32091 .on(iD.ui.cmd('⌘→'), pan([-mapDimensions[0], 0]))
32092 .on(iD.ui.cmd('⌘↓'), pan([0, -mapDimensions[1]]));
32094 d3.select(document)
32097 context.enter(iD.modes.Browse(context));
32099 context.container()
32100 .call(iD.ui.Splash(context))
32101 .call(iD.ui.Restore(context));
32103 var authenticating = iD.ui.Loading(context)
32104 .message(t('loading_auth'));
32106 context.connection()
32107 .on('authenticating.ui', function() {
32108 context.container()
32109 .call(authenticating);
32111 .on('authenticated.ui', function() {
32112 authenticating.close();
32116 function ui(container) {
32117 context.container(container);
32118 context.loadLocale(function() {
32123 ui.sidebar = iD.ui.Sidebar(context);
32128 iD.ui.tooltipHtml = function(text, key) {
32129 var s = '<span>' + text + '</span>';
32131 s += '<div class="keyhint-wrap">' +
32132 '<span> ' + (t('tooltip_keyhint')) + ' </span>' +
32133 '<span class="keyhint"> ' + key + '</span></div>';
32137 iD.ui.Account = function(context) {
32138 var connection = context.connection();
32140 function update(selection) {
32141 if (!connection.authenticated()) {
32142 selection.selectAll('#userLink, #logoutLink')
32143 .classed('hide', true);
32147 connection.userDetails(function(err, details) {
32148 var userLink = selection.select('#userLink'),
32149 logoutLink = selection.select('#logoutLink');
32152 logoutLink.html('');
32156 selection.selectAll('#userLink, #logoutLink')
32157 .classed('hide', false);
32160 userLink.append('a')
32161 .attr('href', connection.userURL(details.display_name))
32162 .attr('target', '_blank');
32164 // Add thumbnail or dont
32165 if (details.image_url) {
32166 userLink.append('img')
32167 .attr('class', 'icon pre-text user-icon')
32168 .attr('src', details.image_url);
32171 .call(iD.svg.Icon('#icon-avatar', 'pre-text light'));
32175 userLink.append('span')
32176 .attr('class', 'label')
32177 .text(details.display_name);
32179 logoutLink.append('a')
32180 .attr('class', 'logout')
32183 .on('click.logout', function() {
32184 d3.event.preventDefault();
32185 connection.logout();
32190 return function(selection) {
32191 selection.append('li')
32192 .attr('id', 'logoutLink')
32193 .classed('hide', true);
32195 selection.append('li')
32196 .attr('id', 'userLink')
32197 .classed('hide', true);
32199 connection.on('auth.account', function() { update(selection); });
32203 iD.ui.Attribution = function(context) {
32206 function attribution(data, klass) {
32207 var div = selection.selectAll('.' + klass)
32212 .attr('class', klass);
32214 var background = div.selectAll('.attribution')
32215 .data(data, function(d) { return d.name(); });
32219 .attr('class', 'attribution')
32220 .each(function(d) {
32221 if (d.terms_html) {
32223 .html(d.terms_html);
32227 var source = d.terms_text || d.id || d.name();
32230 source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
32236 .attr('href', d.terms_url)
32237 .attr('target', '_blank')
32248 var copyright = background.selectAll('.copyright-notice')
32249 .data(function(d) {
32250 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
32251 return notice ? [notice] : [];
32256 .attr('class', 'copyright-notice');
32258 copyright.text(String);
32264 function update() {
32265 attribution([context.background().baseLayerSource()], 'base-layer-attribution');
32266 attribution(context.background().overlayLayerSources().filter(function (s) {
32267 return s.validZoom(context.map().zoom());
32268 }), 'overlay-layer-attribution');
32271 return function(select) {
32272 selection = select;
32274 context.background()
32275 .on('change.attribution', update);
32278 .on('move.attribution', _.throttle(update, 400, {leading: false}));
32283 iD.ui.Background = function(context) {
32285 opacities = [1, 0.75, 0.5, 0.25],
32289 ['right', [-1, 0]],
32290 ['bottom', [0, 1]]],
32291 opacityDefault = (context.storage('background-opacity') !== null) ?
32292 (+context.storage('background-opacity')) : 1.0,
32293 customTemplate = context.storage('background-custom-template') || '';
32295 // Can be 0 from <1.3.0 use or due to issue #1923.
32296 if (opacityDefault === 0) opacityDefault = 1.0;
32298 function background(selection) {
32300 function sortSources(a, b) {
32301 return a.best() ? -1
32303 : a.id === 'none' ? 1
32304 : b.id === 'none' ? -1
32305 : d3.ascending(a, b);
32308 function setOpacity(d) {
32309 var bg = context.container().selectAll('.layer-background')
32311 .style('opacity', d)
32312 .attr('data-opacity', d);
32314 if (!iD.detect().opera) {
32315 iD.util.setTransform(bg, 0, 0);
32318 opacityList.selectAll('li')
32319 .classed('active', function(_) { return _ === d; });
32321 context.storage('background-opacity', d);
32324 function selectLayer() {
32325 function active(d) {
32326 return context.background().showsLayer(d);
32329 content.selectAll('.layer, .custom_layer')
32330 .classed('active', active)
32331 .selectAll('input')
32332 .property('checked', active);
32335 function clickSetSource(d) {
32336 d3.event.preventDefault();
32337 context.background().baseLayerSource(d);
32341 function editCustom() {
32342 d3.event.preventDefault();
32343 var template = window.prompt(t('background.custom_prompt'), customTemplate);
32345 template.indexOf('google.com') !== -1 ||
32346 template.indexOf('googleapis.com') !== -1 ||
32347 template.indexOf('google.ru') !== -1) {
32351 setCustom(template);
32354 function setCustom(template) {
32355 context.background().baseLayerSource(iD.BackgroundSource.Custom(template));
32357 context.storage('background-custom-template', template);
32360 function clickSetOverlay(d) {
32361 d3.event.preventDefault();
32362 context.background().toggleOverlayLayer(d);
32366 function drawList(layerList, type, change, filter) {
32367 var sources = context.background()
32368 .sources(context.map().extent())
32371 var layerLinks = layerList.selectAll('li.layer')
32372 .data(sources, function(d) { return d.name(); })
32373 .sort(sortSources);
32375 var enter = layerLinks.enter()
32376 .insert('li', '.custom_layer')
32377 .attr('class', 'layer')
32378 .classed('best', function(d) { return d.best(); });
32380 // only set tooltips for layers with tooltips
32381 enter.filter(function(d) { return d.description; })
32382 .call(bootstrap.tooltip()
32383 .title(function(d) { return d.description; })
32384 .placement('top'));
32386 enter.filter(function(d) { return d.best(); })
32388 .attr('class', 'best')
32389 .call(bootstrap.tooltip()
32390 .title(t('background.best_imagery'))
32391 .placement('left'))
32395 var label = enter.append('label');
32397 label.append('input')
32398 .attr('type', type)
32399 .attr('name', 'layers')
32400 .on('change', change);
32402 label.append('span')
32403 .text(function(d) { return d.name(); });
32408 layerList.style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
32411 function update() {
32412 backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
32413 overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
32417 var source = context.background().baseLayerSource();
32418 if (source.id === 'custom') {
32419 customTemplate = source.template;
32423 function clickNudge(d) {
32424 var timeout = window.setTimeout(function() {
32425 interval = window.setInterval(nudge, 100);
32429 d3.select(this).on('mouseup', function() {
32430 window.clearInterval(interval);
32431 window.clearTimeout(timeout);
32436 var offset = context.background()
32437 .nudge(d[1], context.map().zoom())
32439 resetButton.classed('disabled', offset[0] === 0 && offset[1] === 0);
32443 function hide() { setVisible(false); }
32445 function toggle() {
32446 if (d3.event) d3.event.preventDefault();
32447 tooltip.hide(button);
32448 setVisible(!button.classed('active'));
32451 function setVisible(show) {
32452 if (show !== shown) {
32453 button.classed('active', show);
32457 selection.on('mousedown.background-inside', function() {
32458 return d3.event.stopPropagation();
32460 content.style('display', 'block')
32461 .style('right', '-300px')
32464 .style('right', '0px');
32466 content.style('display', 'block')
32467 .style('right', '0px')
32470 .style('right', '-300px')
32471 .each('end', function() {
32472 d3.select(this).style('display', 'none');
32474 selection.on('mousedown.background-inside', null);
32480 var content = selection.append('div')
32481 .attr('class', 'fillL map-overlay col3 content hide'),
32482 tooltip = bootstrap.tooltip()
32485 .title(iD.ui.tooltipHtml(t('background.description'), key)),
32486 button = selection.append('button')
32487 .attr('tabindex', -1)
32488 .on('click', toggle)
32489 .call(iD.svg.Icon('#icon-layers', 'light'))
32493 var opa = content.append('div')
32494 .attr('class', 'opacity-options-wrapper');
32497 .text(t('background.title'));
32499 var opacityList = opa.append('ul')
32500 .attr('class', 'opacity-options');
32502 opacityList.selectAll('div.opacity')
32506 .attr('data-original-title', function(d) {
32507 return t('background.percent_brightness', { opacity: (d * 100) });
32509 .on('click.set-opacity', setOpacity)
32510 .html('<div class="select-box"></div>')
32511 .call(bootstrap.tooltip()
32512 .placement('left'))
32514 .attr('class', 'opacity')
32515 .style('opacity', function(d) { return 1.25 - d; });
32517 var backgroundList = content.append('ul')
32518 .attr('class', 'layer-list');
32520 var custom = backgroundList.append('li')
32521 .attr('class', 'custom_layer')
32522 .datum(iD.BackgroundSource.Custom());
32524 custom.append('button')
32525 .attr('class', 'layer-browse')
32526 .call(bootstrap.tooltip()
32527 .title(t('background.custom_button'))
32528 .placement('left'))
32529 .on('click', editCustom)
32530 .call(iD.svg.Icon('#icon-search'));
32532 var label = custom.append('label');
32534 label.append('input')
32535 .attr('type', 'radio')
32536 .attr('name', 'layers')
32537 .on('change', function () {
32538 if (customTemplate) {
32539 setCustom(customTemplate);
32545 label.append('span')
32546 .text(t('background.custom'));
32548 content.append('div')
32549 .attr('class', 'imagery-faq')
32551 .attr('target', '_blank')
32552 .attr('tabindex', -1)
32553 .call(iD.svg.Icon('#icon-out-link', 'inline'))
32554 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
32556 .text(t('background.imagery_source_faq'));
32558 var overlayList = content.append('ul')
32559 .attr('class', 'layer-list');
32561 var controls = content.append('div')
32562 .attr('class', 'controls-list');
32564 var minimapLabel = controls
32566 .call(bootstrap.tooltip()
32568 .title(iD.ui.tooltipHtml(t('background.minimap.tooltip'), '/'))
32572 minimapLabel.classed('minimap-toggle', true)
32574 .attr('type', 'checkbox')
32575 .on('change', function() {
32576 iD.ui.MapInMap.toggle();
32577 d3.event.preventDefault();
32580 minimapLabel.append('span')
32581 .text(t('background.minimap.description'));
32583 var adjustments = content.append('div')
32584 .attr('class', 'adjustments');
32586 adjustments.append('a')
32587 .text(t('background.fix_misalignment'))
32589 .classed('hide-toggle', true)
32590 .classed('expanded', false)
32591 .on('click', function() {
32592 var exp = d3.select(this).classed('expanded');
32593 nudgeContainer.style('display', exp ? 'none' : 'block');
32594 d3.select(this).classed('expanded', !exp);
32595 d3.event.preventDefault();
32598 var nudgeContainer = adjustments.append('div')
32599 .attr('class', 'nudge-container cf')
32600 .style('display', 'none');
32602 nudgeContainer.selectAll('button')
32603 .data(directions).enter()
32605 .attr('class', function(d) { return d[0] + ' nudge'; })
32606 .on('mousedown', clickNudge);
32608 var resetButton = nudgeContainer
32610 .attr('class', 'reset disabled')
32611 .on('click', function () {
32612 context.background().offset([0, 0]);
32613 resetButton.classed('disabled', true);
32615 .call(iD.svg.Icon('#icon-undo'));
32618 .on('move.background-update', _.debounce(update, 1000));
32620 context.background()
32621 .on('change.background-update', update);
32624 setOpacity(opacityDefault);
32626 var keybinding = d3.keybinding('background')
32631 d3.select(document)
32634 context.surface().on('mousedown.background-outside', hide);
32635 context.container().on('mousedown.background-outside', hide);
32640 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
32641 // For example, ⌘Z -> Ctrl+Z
32642 iD.ui.cmd = function(code) {
32643 if (iD.detect().os === 'mac') {
32647 if (iD.detect().os === 'win') {
32648 if (code === '⌘⇧Z') return 'Ctrl+Y';
32660 for (var i = 0; i < code.length; i++) {
32661 if (code[i] in replacements) {
32662 result += replacements[code[i]] + '+';
32670 iD.ui.Commit = function(context) {
32671 var dispatch = d3.dispatch('cancel', 'save');
32673 function commit(selection) {
32674 var changes = context.history().changes(),
32675 summary = context.history().difference().summary();
32677 function zoomToEntity(change) {
32678 var entity = change.entity;
32679 if (change.changeType !== 'deleted' &&
32680 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
32681 context.map().zoomTo(entity);
32682 context.surface().selectAll(
32683 iD.util.entityOrMemberSelector([entity.id], context.graph()))
32684 .classed('hover', true);
32688 var header = selection.append('div')
32689 .attr('class', 'header fillL');
32691 header.append('h3')
32692 .text(t('commit.title'));
32694 var body = selection.append('div')
32695 .attr('class', 'body');
32699 var commentSection = body.append('div')
32700 .attr('class', 'modal-section form-field commit-form');
32702 commentSection.append('label')
32703 .attr('class', 'form-label')
32704 .text(t('commit.message_label'));
32706 var commentField = commentSection.append('textarea')
32707 .attr('placeholder', t('commit.description_placeholder'))
32708 .attr('maxlength', 255)
32709 .property('value', context.storage('comment') || '')
32710 .on('input.save', enableDisableSaveButton)
32711 .on('change.save', enableDisableSaveButton)
32712 .on('blur.save', function() {
32713 context.storage('comment', this.value);
32716 function enableDisableSaveButton() {
32717 d3.selectAll('.save-section .save-button')
32718 .attr('disabled', (this.value.length ? null : true));
32721 commentField.node().select();
32723 context.connection().userChangesets(function (err, changesets) {
32728 for (var i = 0; i < changesets.length; i++) {
32729 if (changesets[i].tags.comment) {
32731 title: changesets[i].tags.comment,
32732 value: changesets[i].tags.comment
32737 commentField.call(d3.combobox().data(comments));
32740 var changeSetInfo = commentSection.append('div')
32741 .attr('class', 'changeset-info');
32743 changeSetInfo.append('a')
32744 .attr('target', '_blank')
32745 .attr('tabindex', -1)
32746 .call(iD.svg.Icon('#icon-out-link', 'inline'))
32747 .attr('href', t('commit.about_changeset_comments_link'))
32749 .text(t('commit.about_changeset_comments'));
32752 var warnings = body.selectAll('div.warning-section')
32753 .data([context.history().validate(changes)])
32756 .attr('class', 'modal-section warning-section fillL2')
32757 .style('display', function(d) { return _.isEmpty(d) ? 'none' : null; })
32758 .style('background', '#ffb');
32760 warnings.append('h3')
32761 .text(t('commit.warnings'));
32763 var warningLi = warnings.append('ul')
32764 .attr('class', 'changeset-list')
32766 .data(function(d) { return d; })
32770 .on('mouseover', mouseover)
32771 .on('mouseout', mouseout)
32772 .on('click', warningClick);
32775 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
32778 .append('strong').text(function(d) {
32782 warningLi.filter(function(d) { return d.tooltip; })
32783 .call(bootstrap.tooltip()
32784 .title(function(d) { return d.tooltip; })
32789 // Upload Explanation
32790 var saveSection = body.append('div')
32791 .attr('class','modal-section save-section fillL cf');
32793 var prose = saveSection.append('p')
32794 .attr('class', 'commit-info')
32795 .html(t('commit.upload_explanation'));
32797 context.connection().userDetails(function(err, user) {
32800 var userLink = d3.select(document.createElement('div'));
32802 if (user.image_url) {
32803 userLink.append('img')
32804 .attr('src', user.image_url)
32805 .attr('class', 'icon pre-text user-icon');
32808 userLink.append('a')
32809 .attr('class','user-info')
32810 .text(user.display_name)
32811 .attr('href', context.connection().userURL(user.display_name))
32812 .attr('tabindex', -1)
32813 .attr('target', '_blank');
32815 prose.html(t('commit.upload_explanation_with_user', {user: userLink.html()}));
32820 var buttonSection = saveSection.append('div')
32821 .attr('class','buttons fillL cf');
32823 var saveButton = buttonSection.append('button')
32824 .attr('class', 'action col5 button save-button')
32825 .attr('disabled', function() {
32826 var n = d3.select('.commit-form textarea').node();
32827 return (n && n.value.length) ? null : true;
32829 .on('click.save', function() {
32831 comment: commentField.node().value
32835 saveButton.append('span')
32836 .attr('class', 'label')
32837 .text(t('commit.save'));
32839 var cancelButton = buttonSection.append('button')
32840 .attr('class', 'action col5 button cancel-button')
32841 .on('click.cancel', function() { dispatch.cancel(); });
32843 cancelButton.append('span')
32844 .attr('class', 'label')
32845 .text(t('commit.cancel'));
32849 var changeSection = body.selectAll('div.commit-section')
32853 .attr('class', 'commit-section modal-section fillL2');
32855 changeSection.append('h3')
32856 .text(t('commit.changes', {count: summary.length}));
32858 var li = changeSection.append('ul')
32859 .attr('class', 'changeset-list')
32864 .on('mouseover', mouseover)
32865 .on('mouseout', mouseout)
32866 .on('click', zoomToEntity);
32868 li.each(function(d) {
32870 .call(iD.svg.Icon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
32874 .attr('class', 'change-type')
32875 .text(function(d) {
32876 return t('commit.' + d.changeType) + ' ';
32879 li.append('strong')
32880 .attr('class', 'entity-type')
32881 .text(function(d) {
32882 return context.presets().match(d.entity, d.graph).name();
32886 .attr('class', 'entity-name')
32887 .text(function(d) {
32888 var name = iD.util.displayName(d.entity) || '',
32890 if (name !== '') string += ':';
32891 return string += ' ' + name;
32894 li.style('opacity', 0)
32896 .style('opacity', 1);
32898 li.style('opacity', 0)
32900 .style('opacity', 1);
32902 function mouseover(d) {
32904 context.surface().selectAll(
32905 iD.util.entityOrMemberSelector([d.entity.id], context.graph())
32906 ).classed('hover', true);
32910 function mouseout() {
32911 context.surface().selectAll('.hover')
32912 .classed('hover', false);
32915 function warningClick(d) {
32917 context.map().zoomTo(d.entity);
32919 iD.modes.Select(context, [d.entity.id])
32920 .suppressMenu(true));
32925 return d3.rebind(commit, dispatch, 'on');
32927 iD.ui.confirm = function(selection) {
32928 var modal = iD.ui.modal(selection);
32930 modal.select('.modal')
32931 .classed('modal-alert', true);
32933 var section = modal.select('.content');
32935 section.append('div')
32936 .attr('class', 'modal-section header');
32938 section.append('div')
32939 .attr('class', 'modal-section message-text');
32941 var buttons = section.append('div')
32942 .attr('class', 'modal-section buttons cf');
32944 modal.okButton = function() {
32947 .attr('class', 'action col4')
32948 .on('click.confirm', function() {
32951 .text(t('confirm.okay'));
32958 iD.ui.Conflicts = function(context) {
32959 var dispatch = d3.dispatch('download', 'cancel', 'save'),
32962 function conflicts(selection) {
32963 var header = selection
32965 .attr('class', 'header fillL');
32969 .attr('class', 'fr')
32970 .on('click', function() { dispatch.cancel(); })
32971 .call(iD.svg.Icon('#icon-close'));
32975 .text(t('save.conflict.header'));
32977 var body = selection
32979 .attr('class', 'body fillL');
32983 .attr('class', 'conflicts-help')
32984 .text(t('save.conflict.help'))
32986 .attr('class', 'conflicts-download')
32987 .text(t('save.conflict.download_changes'))
32988 .on('click.download', function() { dispatch.download(); });
32992 .attr('class', 'conflict-container fillL3')
32993 .call(showConflict, 0);
32997 .attr('class', 'conflicts-done')
32998 .attr('opacity', 0)
32999 .style('display', 'none')
33000 .text(t('save.conflict.done'));
33004 .attr('class','buttons col12 joined conflicts-buttons');
33008 .attr('disabled', list.length > 1)
33009 .attr('class', 'action conflicts-button col6')
33010 .text(t('save.title'))
33011 .on('click.try_again', function() { dispatch.save(); });
33015 .attr('class', 'secondary-action conflicts-button col6')
33016 .text(t('confirm.cancel'))
33017 .on('click.cancel', function() { dispatch.cancel(); });
33021 function showConflict(selection, index) {
33022 if (index < 0 || index >= list.length) return;
33024 var parent = d3.select(selection.node().parentNode);
33026 // enable save button if this is the last conflict being reviewed..
33027 if (index === list.length - 1) {
33028 window.setTimeout(function() {
33029 parent.select('.conflicts-button')
33030 .attr('disabled', null);
33032 parent.select('.conflicts-done')
33034 .attr('opacity', 1)
33035 .style('display', 'block');
33039 var item = selection
33040 .selectAll('.conflict')
33041 .data([list[index]]);
33043 var enter = item.enter()
33045 .attr('class', 'conflict');
33049 .attr('class', 'conflict-count')
33050 .text(t('save.conflict.count', { num: index + 1, total: list.length }));
33054 .attr('class', 'conflict-description')
33056 .text(function(d) { return d.name; })
33057 .on('click', function(d) {
33058 zoomToEntity(d.id);
33059 d3.event.preventDefault();
33062 var details = enter
33064 .attr('class', 'conflict-detail-container');
33068 .attr('class', 'conflict-detail-list')
33070 .data(function(d) { return d.details || []; })
33073 .attr('class', 'conflict-detail-item')
33074 .html(function(d) { return d; });
33078 .attr('class', 'conflict-choices')
33083 .attr('class', 'conflict-nav-buttons joined cf')
33084 .selectAll('button')
33085 .data(['previous', 'next'])
33088 .text(function(d) { return t('save.conflict.' + d); })
33089 .attr('class', 'conflict-nav-button action col6')
33090 .attr('disabled', function(d, i) {
33091 return (i === 0 && index === 0) ||
33092 (i === 1 && index === list.length - 1) || null;
33094 .on('click', function(d, i) {
33095 var container = parent.select('.conflict-container'),
33096 sign = (i === 0 ? -1 : 1);
33099 .selectAll('.conflict')
33103 .call(showConflict, index + sign);
33105 d3.event.preventDefault();
33113 function addChoices(selection) {
33114 var choices = selection
33116 .attr('class', 'layer-list')
33118 .data(function(d) { return d.choices || []; });
33120 var enter = choices.enter()
33122 .attr('class', 'layer');
33129 .attr('type', 'radio')
33130 .attr('name', function(d) { return d.id; })
33131 .on('change', function(d, i) {
33132 var ul = this.parentNode.parentNode.parentNode;
33133 ul.__data__.chosen = i;
33139 .text(function(d) { return d.text; });
33142 .each(function(d, i) {
33143 var ul = this.parentNode;
33144 if (ul.__data__.chosen === i) choose(ul, d);
33148 function choose(ul, datum) {
33149 if (d3.event) d3.event.preventDefault();
33153 .classed('active', function(d) { return d === datum; })
33154 .selectAll('input')
33155 .property('checked', function(d) { return d === datum; });
33157 var extent = iD.geo.Extent(),
33160 entity = context.graph().hasEntity(datum.id);
33161 if (entity) extent._extend(entity.extent(context.graph()));
33165 entity = context.graph().hasEntity(datum.id);
33166 if (entity) extent._extend(entity.extent(context.graph()));
33168 zoomToEntity(datum.id, extent);
33171 function zoomToEntity(id, extent) {
33172 context.surface().selectAll('.hover')
33173 .classed('hover', false);
33175 var entity = context.graph().hasEntity(id);
33178 context.map().trimmedExtent(extent);
33180 context.map().zoomTo(entity);
33182 context.surface().selectAll(
33183 iD.util.entityOrMemberSelector([entity.id], context.graph()))
33184 .classed('hover', true);
33189 // The conflict list should be an array of objects like:
33192 // name: entityName(local),
33193 // details: merge.conflicts(),
33196 // choice(id, keepMine, forceLocal),
33197 // choice(id, keepTheirs, forceRemote)
33200 conflicts.list = function(_) {
33201 if (!arguments.length) return list;
33206 return d3.rebind(conflicts, dispatch, 'on');
33208 iD.ui.Contributors = function(context) {
33209 var debouncedUpdate = _.debounce(function() { update(); }, 1000),
33212 wrap = d3.select(null);
33214 function update() {
33216 entities = context.intersects(context.map().extent());
33218 entities.forEach(function(entity) {
33219 if (entity && entity.user) users[entity.user] = true;
33222 var u = Object.keys(users),
33223 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
33226 .call(iD.svg.Icon('#icon-nearby', 'pre-text light'));
33228 var userList = d3.select(document.createElement('span'));
33230 userList.selectAll()
33234 .attr('class', 'user-link')
33235 .attr('href', function(d) { return context.connection().userURL(d); })
33236 .attr('target', '_blank')
33237 .attr('tabindex', -1)
33240 if (u.length > limit) {
33241 var count = d3.select(document.createElement('span'));
33244 .attr('target', '_blank')
33245 .attr('tabindex', -1)
33246 .attr('href', function() {
33247 return context.connection().changesetsURL(context.map().center(), context.map().zoom());
33249 .text(u.length - limit + 1);
33251 wrap.append('span')
33252 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
33255 wrap.append('span')
33256 .html(t('contributors.list', { users: userList.html() }));
33263 .style('opacity', 0);
33265 } else if (hidden) {
33268 .style('opacity', 1);
33272 return function(selection) {
33276 context.connection().on('loaded.contributors', debouncedUpdate);
33277 context.map().on('move.contributors', debouncedUpdate);
33280 iD.ui.Disclosure = function() {
33281 var dispatch = d3.dispatch('toggled'),
33284 content = function () {};
33286 var disclosure = function(selection) {
33287 var $link = selection.selectAll('.hide-toggle')
33290 $link.enter().append('a')
33292 .attr('class', 'hide-toggle');
33295 .on('click', toggle)
33296 .classed('expanded', expanded);
33298 var $body = selection.selectAll('div')
33301 $body.enter().append('div');
33303 $body.classed('hide', !expanded)
33306 function toggle() {
33307 expanded = !expanded;
33308 $link.classed('expanded', expanded);
33309 $body.call(iD.ui.Toggle(expanded));
33310 dispatch.toggled(expanded);
33314 disclosure.title = function(_) {
33315 if (!arguments.length) return title;
33320 disclosure.expanded = function(_) {
33321 if (!arguments.length) return expanded;
33326 disclosure.content = function(_) {
33327 if (!arguments.length) return content;
33332 return d3.rebind(disclosure, dispatch, 'on');
33334 iD.ui.EntityEditor = function(context) {
33335 var dispatch = d3.dispatch('choose'),
33337 coalesceChanges = false,
33344 var presetEditor = iD.ui.preset(context)
33345 .on('change', changeTags);
33346 var rawTagEditor = iD.ui.RawTagEditor(context)
33347 .on('change', changeTags);
33349 function entityEditor(selection) {
33350 var entity = context.entity(id),
33351 tags = _.clone(entity.tags);
33353 var $header = selection.selectAll('.header')
33357 var $enter = $header.enter().append('div')
33358 .attr('class', 'header fillL cf');
33360 $enter.append('button')
33361 .attr('class', 'fl preset-reset preset-choose')
33365 $enter.append('button')
33366 .attr('class', 'fr preset-close')
33367 .call(iD.svg.Icon(modified ? '#icon-apply' : '#icon-close'));
33369 $enter.append('h3');
33372 $header.select('h3')
33373 .text(t('inspector.edit'));
33375 $header.select('.preset-close')
33376 .on('click', function() {
33377 context.enter(iD.modes.Browse(context));
33380 var $body = selection.selectAll('.inspector-body')
33384 $enter = $body.enter().append('div')
33385 .attr('class', 'inspector-body');
33387 $enter.append('div')
33388 .attr('class', 'preset-list-item inspector-inner')
33390 .attr('class', 'preset-list-button-wrap')
33392 .attr('class', 'preset-list-button preset-reset')
33393 .call(bootstrap.tooltip()
33394 .title(t('inspector.back_tooltip'))
33395 .placement('bottom'))
33397 .attr('class', 'label');
33399 $body.select('.preset-list-button-wrap')
33400 .call(reference.button);
33402 $body.select('.preset-list-item')
33403 .call(reference.body);
33405 $enter.append('div')
33406 .attr('class', 'inspector-border inspector-preset');
33408 $enter.append('div')
33409 .attr('class', 'inspector-border raw-tag-editor inspector-inner');
33411 $enter.append('div')
33412 .attr('class', 'inspector-border raw-member-editor inspector-inner');
33414 $enter.append('div')
33415 .attr('class', 'raw-membership-editor inspector-inner');
33417 selection.selectAll('.preset-reset')
33418 .on('click', function() {
33419 dispatch.choose(preset);
33423 $body.select('.preset-list-item button')
33424 .call(iD.ui.PresetIcon()
33425 .geometry(context.geometry(id))
33428 $body.select('.preset-list-item .label')
33429 .text(preset.name());
33431 $body.select('.inspector-preset')
33438 $body.select('.raw-tag-editor')
33445 if (entity.type === 'relation') {
33446 $body.select('.raw-member-editor')
33447 .style('display', 'block')
33448 .call(iD.ui.RawMemberEditor(context)
33451 $body.select('.raw-member-editor')
33452 .style('display', 'none');
33455 $body.select('.raw-membership-editor')
33456 .call(iD.ui.RawMembershipEditor(context)
33459 function historyChanged() {
33460 if (state === 'hide') return;
33462 var entity = context.hasEntity(id),
33463 graph = context.graph();
33464 if (!entity) return;
33466 entityEditor.preset(context.presets().match(entity, graph));
33467 entityEditor.modified(base !== graph);
33468 entityEditor(selection);
33472 .on('change.entity-editor', historyChanged);
33475 function clean(o) {
33477 function cleanVal(k, v) {
33478 function keepSpaces(k) {
33479 var whitelist = ['opening_hours', 'service_times', 'collection_times',
33480 'operating_times', 'smoking_hours', 'happy_hours'];
33481 return _.any(whitelist, function(s) { return k.indexOf(s) !== -1; });
33484 var blacklist = ['description', 'note', 'fixme'];
33485 if (_.any(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
33487 var cleaned = v.split(';')
33488 .map(function(s) { return s.trim(); })
33489 .join(keepSpaces(k) ? '; ' : ';');
33491 // The code below is not intended to validate websites and emails.
33492 // It is only intended to prevent obvious copy-paste errors. (#2323)
33494 // clean website- and email-like tags
33495 if (k.indexOf('website') !== -1 ||
33496 k.indexOf('email') !== -1 ||
33497 cleaned.indexOf('http') === 0) {
33499 .replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
33506 var out = {}, k, v;
33508 if (k && (v = o[k]) !== undefined) {
33509 out[k] = cleanVal(k, v);
33515 // Tag changes that fire on input can all get coalesced into a single
33516 // history operation when the user leaves the field. #2342
33517 function changeTags(changed, onInput) {
33518 var entity = context.entity(id),
33519 annotation = t('operations.change_tags.annotation'),
33520 tags = clean(_.extend({}, entity.tags, changed));
33522 if (!_.isEqual(entity.tags, tags)) {
33523 if (coalesceChanges) {
33524 context.overwrite(iD.actions.ChangeTags(id, tags), annotation);
33526 context.perform(iD.actions.ChangeTags(id, tags), annotation);
33530 coalesceChanges = !!onInput;
33533 entityEditor.modified = function(_) {
33534 if (!arguments.length) return modified;
33536 d3.selectAll('button.preset-close use')
33537 .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
33540 entityEditor.state = function(_) {
33541 if (!arguments.length) return state;
33543 return entityEditor;
33546 entityEditor.entityID = function(_) {
33547 if (!arguments.length) return id;
33549 base = context.graph();
33550 entityEditor.preset(context.presets().match(context.entity(id), base));
33551 entityEditor.modified(false);
33552 coalesceChanges = false;
33553 return entityEditor;
33556 entityEditor.preset = function(_) {
33557 if (!arguments.length) return preset;
33558 if (_ !== preset) {
33560 reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context)
33563 return entityEditor;
33566 return d3.rebind(entityEditor, dispatch, 'on');
33568 iD.ui.FeatureInfo = function(context) {
33569 function update(selection) {
33570 var features = context.features(),
33571 stats = features.stats(),
33573 hiddenList = _.compact(_.map(features.hidden(), function(k) {
33576 return String(stats[k]) + ' ' + t('feature.' + k + '.description');
33580 selection.html('');
33582 if (hiddenList.length) {
33583 var tooltip = bootstrap.tooltip()
33586 .title(function() {
33587 return iD.ui.tooltipHtml(hiddenList.join('<br/>'));
33590 var warning = selection.append('a')
33592 .attr('tabindex', -1)
33593 .html(t('feature_info.hidden_warning', { count: count }))
33595 .on('click', function() {
33596 tooltip.hide(warning);
33597 // open map data panel?
33598 d3.event.preventDefault();
33603 .classed('hide', !hiddenList.length);
33606 return function(selection) {
33609 context.features().on('change.feature_info', function() {
33614 iD.ui.FeatureList = function(context) {
33615 var geocodeResults;
33617 function featureList(selection) {
33618 var header = selection.append('div')
33619 .attr('class', 'header fillL cf');
33621 header.append('h3')
33622 .text(t('inspector.feature_list'));
33624 function keypress() {
33625 var q = search.property('value'),
33626 items = list.selectAll('.feature-list-item');
33627 if (d3.event.keyCode === 13 && q.length && items.size()) {
33628 click(items.datum());
33632 function inputevent() {
33633 geocodeResults = undefined;
33637 var searchWrap = selection.append('div')
33638 .attr('class', 'search-header');
33640 var search = searchWrap.append('input')
33641 .attr('placeholder', t('inspector.search'))
33642 .attr('type', 'search')
33643 .on('keypress', keypress)
33644 .on('input', inputevent);
33647 .call(iD.svg.Icon('#icon-search', 'pre-text'));
33649 var listWrap = selection.append('div')
33650 .attr('class', 'inspector-body');
33652 var list = listWrap.append('div')
33653 .attr('class', 'feature-list cf');
33656 .on('exit.feature-list', clearSearch);
33658 .on('drawn.feature-list', mapDrawn);
33660 function clearSearch() {
33661 search.property('value', '');
33665 function mapDrawn(e) {
33671 function features() {
33674 graph = context.graph(),
33675 q = search.property('value').toLowerCase();
33677 if (!q) return result;
33679 var idMatch = q.match(/^([nwr])([0-9]+)$/);
33684 geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
33685 type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
33690 var locationMatch = sexagesimal.pair(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
33692 if (locationMatch) {
33693 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
33697 type: t('inspector.location'),
33698 name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
33703 function addEntity(entity) {
33704 if (entity.id in entities || result.length > 200)
33707 entities[entity.id] = true;
33709 var name = iD.util.displayName(entity) || '';
33710 if (name.toLowerCase().indexOf(q) >= 0) {
33714 geometry: context.geometry(entity.id),
33715 type: context.presets().match(entity, graph).name(),
33720 graph.parentRelations(entity).forEach(function(parent) {
33725 var visible = context.surface().selectAll('.point, .line, .area')[0];
33726 for (var i = 0; i < visible.length && result.length <= 200; i++) {
33727 addEntity(visible[i].__data__);
33730 (geocodeResults || []).forEach(function(d) {
33731 // https://github.com/openstreetmap/iD/issues/1890
33732 if (d.osm_type && d.osm_id) {
33734 id: iD.Entity.id.fromOSM(d.osm_type, d.osm_id),
33735 geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
33736 type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
33737 : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
33738 name: d.display_name,
33739 extent: new iD.geo.Extent(
33740 [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
33741 [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
33749 function drawList() {
33750 var value = search.property('value'),
33751 results = features();
33753 list.classed('filtered', value.length);
33755 var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
33757 var resultsIndicator = list.selectAll('.no-results-item')
33759 .enter().append('button')
33760 .property('disabled', true)
33761 .attr('class', 'no-results-item')
33762 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
33764 resultsIndicator.append('span')
33765 .attr('class', 'entity-name');
33767 list.selectAll('.no-results-item .entity-name')
33768 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
33770 list.selectAll('.geocode-item')
33772 .enter().append('button')
33773 .attr('class', 'geocode-item')
33774 .on('click', geocode)
33776 .attr('class', 'label')
33778 .attr('class', 'entity-name')
33779 .text(t('geocoder.search'));
33781 list.selectAll('.no-results-item')
33782 .style('display', (value.length && !results.length) ? 'block' : 'none');
33784 list.selectAll('.geocode-item')
33785 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
33787 list.selectAll('.feature-list-item')
33791 var items = list.selectAll('.feature-list-item')
33792 .data(results, function(d) { return d.id; });
33794 var enter = items.enter()
33795 .insert('button', '.geocode-item')
33796 .attr('class', 'feature-list-item')
33797 .on('mouseover', mouseover)
33798 .on('mouseout', mouseout)
33799 .on('click', click);
33803 .attr('class', 'label');
33805 label.each(function(d) {
33807 .call(iD.svg.Icon('#icon-' + d.geometry, 'pre-text'));
33810 label.append('span')
33811 .attr('class', 'entity-type')
33812 .text(function(d) { return d.type; });
33814 label.append('span')
33815 .attr('class', 'entity-name')
33816 .text(function(d) { return d.name; });
33818 enter.style('opacity', 0)
33820 .style('opacity', 1);
33828 function mouseover(d) {
33829 if (d.id === -1) return;
33831 context.surface().selectAll(iD.util.entityOrMemberSelector([d.id], context.graph()))
33832 .classed('hover', true);
33835 function mouseout() {
33836 context.surface().selectAll('.hover')
33837 .classed('hover', false);
33840 function click(d) {
33841 d3.event.preventDefault();
33843 context.map().centerZoom([d.location[1], d.location[0]], 20);
33845 else if (d.entity) {
33846 if (d.entity.type === 'node') {
33847 context.map().center(d.entity.loc);
33848 } else if (d.entity.type === 'way') {
33849 var center = context.projection(context.map().center()),
33850 edge = iD.geo.chooseEdge(context.childNodes(d.entity), center, context.projection);
33851 context.map().center(edge.loc);
33853 context.enter(iD.modes.Select(context, [d.entity.id]).suppressMenu(true));
33855 context.zoomToEntity(d.id);
33859 function geocode() {
33860 var searchVal = encodeURIComponent(search.property('value'));
33861 d3.json('https://nominatim.openstreetmap.org/search/' + searchVal + '?limit=10&format=json', function(err, resp) {
33862 geocodeResults = resp || [];
33868 return featureList;
33870 iD.ui.flash = function(selection) {
33871 var modal = iD.ui.modal(selection);
33873 modal.select('.modal').classed('modal-flash', true);
33875 modal.select('.content')
33876 .classed('modal-section', true)
33878 .attr('class', 'description');
33880 modal.on('click.flash', function() { modal.remove(); });
33882 setTimeout(function() {
33889 iD.ui.FullScreen = function(context) {
33890 var element = context.container().node(),
33891 keybinding = d3.keybinding('full-screen');
33894 function getFullScreenFn() {
33895 if (element.requestFullscreen) {
33896 return element.requestFullscreen;
33897 } else if (element.msRequestFullscreen) {
33898 return element.msRequestFullscreen;
33899 } else if (element.mozRequestFullScreen) {
33900 return element.mozRequestFullScreen;
33901 } else if (element.webkitRequestFullscreen) {
33902 return element.webkitRequestFullscreen;
33906 function getExitFullScreenFn() {
33907 if (document.exitFullscreen) {
33908 return document.exitFullscreen;
33909 } else if (document.msExitFullscreen) {
33910 return document.msExitFullscreen;
33911 } else if (document.mozCancelFullScreen) {
33912 return document.mozCancelFullScreen;
33913 } else if (document.webkitExitFullscreen) {
33914 return document.webkitExitFullscreen;
33918 function isFullScreen() {
33919 return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement ||
33920 document.msFullscreenElement;
33923 function isSupported() {
33924 return !!getFullScreenFn();
33927 function fullScreen() {
33928 d3.event.preventDefault();
33929 if (!isFullScreen()) {
33930 // button.classed('active', true);
33931 getFullScreenFn().apply(element);
33933 // button.classed('active', false);
33934 getExitFullScreenFn().apply(document);
33938 return function() { // selection) {
33939 if (!isSupported())
33942 // var tooltip = bootstrap.tooltip()
33943 // .placement('left');
33945 // button = selection.append('button')
33946 // .attr('title', t('full_screen'))
33947 // .attr('tabindex', -1)
33948 // .on('click', fullScreen)
33951 // button.append('span')
33952 // .attr('class', 'icon full-screen');
33955 .on('f11', fullScreen)
33956 .on(iD.ui.cmd('⌘⇧F'), fullScreen);
33958 d3.select(document)
33962 iD.ui.Geolocate = function(map) {
33964 navigator.geolocation.getCurrentPosition(
33968 function success(position) {
33969 var extent = iD.geo.Extent([position.coords.longitude, position.coords.latitude])
33970 .padByMeters(position.coords.accuracy);
33972 map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
33975 function error() { }
33977 return function(selection) {
33978 if (!navigator.geolocation) return;
33980 selection.append('button')
33981 .attr('tabindex', -1)
33982 .attr('title', t('geolocate.title'))
33983 .on('click', click)
33984 .call(iD.svg.Icon('#icon-geolocate', 'light'))
33985 .call(bootstrap.tooltip()
33986 .placement('left'));
33989 iD.ui.Help = function(context) {
33994 'help.editing_saving',
34003 var docs = docKeys.map(function(key) {
34006 title: text.split('\n')[0].replace('#', '').trim(),
34007 html: marked(text.split('\n').slice(1).join('\n'))
34011 function help(selection) {
34017 function toggle() {
34018 if (d3.event) d3.event.preventDefault();
34019 tooltip.hide(button);
34020 setVisible(!button.classed('active'));
34023 function setVisible(show) {
34024 if (show !== shown) {
34025 button.classed('active', show);
34029 selection.on('mousedown.help-inside', function() {
34030 return d3.event.stopPropagation();
34032 pane.style('display', 'block')
34033 .style('right', '-500px')
34036 .style('right', '0px');
34038 pane.style('right', '0px')
34041 .style('right', '-500px')
34042 .each('end', function() {
34043 d3.select(this).style('display', 'none');
34045 selection.on('mousedown.help-inside', null);
34050 function clickHelp(d, i) {
34051 pane.property('scrollTop', 0);
34052 doctitle.html(d.title);
34054 body.selectAll('a')
34055 .attr('target', '_blank');
34056 menuItems.classed('selected', function(m) {
34057 return m.title === d.title;
34063 var prevLink = nav.append('a')
34064 .attr('class', 'previous')
34065 .on('click', function() {
34066 clickHelp(docs[i - 1], i - 1);
34068 prevLink.append('span').html('◄ ' + docs[i - 1].title);
34070 if (i < docs.length - 1) {
34071 var nextLink = nav.append('a')
34072 .attr('class', 'next')
34073 .on('click', function() {
34074 clickHelp(docs[i + 1], i + 1);
34076 nextLink.append('span').html(docs[i + 1].title + ' ►');
34080 function clickWalkthrough() {
34081 d3.select(document.body).call(iD.ui.intro(context));
34086 var pane = selection.append('div')
34087 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
34088 tooltip = bootstrap.tooltip()
34091 .title(iD.ui.tooltipHtml(t('help.title'), key)),
34092 button = selection.append('button')
34093 .attr('tabindex', -1)
34094 .on('click', toggle)
34095 .call(iD.svg.Icon('#icon-help', 'light'))
34100 var toc = pane.append('ul')
34101 .attr('class', 'toc');
34103 var menuItems = toc.selectAll('li')
34108 .html(function(d) { return d.title; })
34109 .on('click', clickHelp);
34112 .attr('class','walkthrough')
34114 .text(t('splash.walkthrough'))
34115 .on('click', clickWalkthrough);
34117 var content = pane.append('div')
34118 .attr('class', 'left-content');
34120 var doctitle = content.append('h2')
34121 .text(t('help.title'));
34123 var body = content.append('div')
34124 .attr('class', 'body');
34126 var nav = content.append('div')
34127 .attr('class', 'nav');
34129 clickHelp(docs[0], 0);
34131 var keybinding = d3.keybinding('help')
34136 d3.select(document)
34139 context.surface().on('mousedown.help-outside', hide);
34140 context.container().on('mousedown.help-outside', hide);
34145 iD.ui.Info = function(context) {
34146 var key = iD.ui.cmd('⌘I'),
34147 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
34150 function info(selection) {
34151 function radiansToMeters(r) {
34152 // using WGS84 authalic radius (6371007.1809 m)
34153 return r * 6371007.1809;
34156 function steradiansToSqmeters(r) {
34157 // http://gis.stackexchange.com/a/124857/40446
34158 return r / 12.56637 * 510065621724000;
34161 function toLineString(feature) {
34162 if (feature.type === 'LineString') return feature;
34164 var result = { type: 'LineString', coordinates: [] };
34165 if (feature.type === 'Polygon') {
34166 result.coordinates = feature.coordinates[0];
34167 } else if (feature.type === 'MultiPolygon') {
34168 result.coordinates = feature.coordinates[0][0];
34174 function displayLength(m) {
34175 var d = m * (imperial ? 3.28084 : 1),
34194 // drop unnecessary precision
34195 p = d > 1000 ? 0 : d > 100 ? 1 : 2;
34197 return String(d.toFixed(p)) + ' ' + unit;
34200 function displayArea(m2) {
34201 var d = m2 * (imperial ? 10.7639111056 : 1),
34202 d1, d2, p1, p2, unit1, unit2;
34205 if (d >= 6969600) { // > 0.25mi² show mi²
34213 if (d > 4356 && d < 43560000) { // 0.1 - 1000 acres
34219 if (d >= 250000) { // > 0.25km² show km²
34227 if (d > 1000 && d < 10000000) { // 0.1 - 1000 hectares
34233 // drop unnecessary precision
34234 p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
34235 p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
34237 return String(d1.toFixed(p1)) + ' ' + unit1 +
34238 (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
34242 function redraw() {
34243 if (hidden) return;
34245 var resolver = context.graph(),
34246 selected = _.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
34247 singular = selected.length === 1 ? selected[0] : null,
34248 extent = iD.geo.Extent(),
34253 .attr('class', 'infobox-heading fillD')
34254 .text(singular || t('infobox.selected', { n: selected.length }));
34256 if (!selected.length) return;
34259 for (var i = 0; i < selected.length; i++) {
34260 entity = context.entity(selected[i]);
34261 extent._extend(entity.extent(resolver));
34263 center = extent.center();
34266 var list = wrap.append('ul');
34268 // multiple wrap, just display extent center..
34271 .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
34275 // single wrap, display details..
34276 if (!entity) return;
34277 var geometry = entity.geometry(resolver);
34279 if (geometry === 'line' || geometry === 'area') {
34280 var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
34281 feature = entity.asGeoJSON(resolver),
34282 length = radiansToMeters(d3.geo.length(toLineString(feature))),
34283 lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')),
34284 centroid = d3.geo.centroid(feature);
34287 .text(t('infobox.geometry') + ': ' +
34288 (closed ? t('infobox.closed') + ' ' : '') + t('geometry.' + geometry) );
34291 var area = steradiansToSqmeters(entity.area(resolver));
34293 .text(t('infobox.area') + ': ' + displayArea(area));
34297 .text(lengthLabel + ': ' + displayLength(length));
34300 .text(t('infobox.centroid') + ': ' + centroid[0].toFixed(5) + ', ' + centroid[1].toFixed(5));
34303 var toggle = imperial ? 'imperial' : 'metric';
34305 .text(t('infobox.' + toggle))
34307 .attr('class', 'button')
34308 .on('click', function() {
34309 d3.event.preventDefault();
34310 imperial = !imperial;
34315 var centerLabel = t('infobox.' + (entity.type === 'node' ? 'location' : 'center'));
34318 .text(t('infobox.geometry') + ': ' + t('geometry.' + geometry));
34321 .text(centerLabel + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
34326 function toggle() {
34327 if (d3.event) d3.event.preventDefault();
34333 .style('display', 'block')
34334 .style('opacity', 1)
34337 .style('opacity', 0)
34338 .each('end', function() {
34339 d3.select(this).style('display', 'none');
34343 .style('display', 'block')
34344 .style('opacity', 0)
34347 .style('opacity', 1);
34354 var wrap = selection.selectAll('.infobox')
34359 .attr('class', 'infobox fillD2')
34360 .style('display', (hidden ? 'none' : 'block'));
34363 .on('drawn.info', redraw);
34367 var keybinding = d3.keybinding('info')
34370 d3.select(document)
34376 iD.ui.Inspector = function(context) {
34377 var presetList = iD.ui.PresetList(context),
34378 entityEditor = iD.ui.EntityEditor(context),
34381 newFeature = false;
34383 function inspector(selection) {
34385 .entityID(entityID)
34386 .autofocus(newFeature)
34387 .on('choose', setPreset);
34391 .entityID(entityID)
34392 .on('choose', showList);
34394 var $wrap = selection.selectAll('.panewrap')
34397 var $enter = $wrap.enter().append('div')
34398 .attr('class', 'panewrap');
34400 $enter.append('div')
34401 .attr('class', 'preset-list-pane pane');
34403 $enter.append('div')
34404 .attr('class', 'entity-editor-pane pane');
34406 var $presetPane = $wrap.select('.preset-list-pane');
34407 var $editorPane = $wrap.select('.entity-editor-pane');
34409 var graph = context.graph(),
34410 entity = context.entity(entityID),
34411 showEditor = state === 'hover' ||
34412 entity.isUsed(graph) ||
34413 entity.isHighwayIntersection(graph);
34416 $wrap.style('right', '0%');
34417 $editorPane.call(entityEditor);
34419 $wrap.style('right', '-100%');
34420 $presetPane.call(presetList);
34423 var $footer = selection.selectAll('.footer')
34426 $footer.enter().append('div')
34427 .attr('class', 'footer');
34429 selection.select('.footer')
34430 .call(iD.ui.ViewOnOSM(context)
34431 .entityID(entityID));
34433 function showList(preset) {
34435 .styleTween('right', function() { return d3.interpolate('0%', '-100%'); });
34437 $presetPane.call(presetList
34442 function setPreset(preset) {
34444 .styleTween('right', function() { return d3.interpolate('-100%', '0%'); });
34446 $editorPane.call(entityEditor
34451 inspector.state = function(_) {
34452 if (!arguments.length) return state;
34454 entityEditor.state(state);
34458 inspector.entityID = function(_) {
34459 if (!arguments.length) return entityID;
34464 inspector.newFeature = function(_) {
34465 if (!arguments.length) return newFeature;
34472 iD.ui.intro = function(context) {
34475 function intro(selection) {
34477 function localizedName(id) {
34479 n2140018997: 'city_hall',
34480 n367813436: 'fire_department',
34481 w203988286: 'memory_isle_park',
34482 w203972937: 'riverwalk_trail',
34483 w203972938: 'riverwalk_trail',
34484 w203972940: 'riverwalk_trail',
34485 w41785752: 'w_michigan_ave',
34486 w134150789: 'w_michigan_ave',
34487 w134150795: 'w_michigan_ave',
34488 w134150800: 'w_michigan_ave',
34489 w134150811: 'w_michigan_ave',
34490 w134150802: 'e_michigan_ave',
34491 w134150836: 'e_michigan_ave',
34492 w41074896: 'e_michigan_ave',
34493 w17965834: 'spring_st',
34494 w203986457: 'scidmore_park',
34495 w203049587: 'petting_zoo',
34496 w17967397: 'n_andrews_st',
34497 w17967315: 's_andrews_st',
34498 w17967326: 'n_constantine_st',
34499 w17966400: 's_constantine_st',
34500 w170848823: 'rocky_river',
34501 w170848824: 'rocky_river',
34502 w170848331: 'rocky_river',
34503 w17967752: 'railroad_dr',
34504 w17965998: 'conrail_rr',
34505 w134150845: 'conrail_rr',
34506 w170989131: 'st_joseph_river',
34507 w143497377: 'n_main_st',
34508 w134150801: 's_main_st',
34509 w134150830: 's_main_st',
34510 w17966462: 's_main_st',
34511 w17967734: 'water_st',
34512 w17964996: 'foster_st',
34513 w170848330: 'portage_river',
34514 w17965351: 'flower_st',
34515 w17965502: 'elm_st',
34516 w17965402: 'walnut_st',
34517 w17964793: 'morris_ave',
34518 w17967444: 'east_st',
34519 w17966984: 'portage_ave'
34521 return features[id] && t('intro.graph.' + features[id]);
34524 context.enter(iD.modes.Browse(context));
34526 // Save current map state
34527 var history = context.history().toJSON(),
34528 hash = window.location.hash,
34529 center = context.map().center(),
34530 zoom = context.map().zoom(),
34531 background = context.background().baseLayerSource(),
34532 opacity = d3.select('.background-layer').style('opacity'),
34533 loadedTiles = context.connection().loadedTiles(),
34534 baseEntities = context.history().graph().base().entities,
34538 context.inIntro(true);
34540 // Load semi-real data used in intro
34541 context.connection().toggle(false).flush();
34542 context.history().reset();
34544 introGraph = JSON.parse(iD.introGraph);
34545 for (var key in introGraph) {
34546 introGraph[key] = iD.Entity(introGraph[key]);
34547 name = localizedName(key);
34549 introGraph[key].tags.name = name;
34552 context.history().merge(d3.values(iD.Graph().load(introGraph).entities));
34553 context.background().bing();
34555 d3.select('.background-layer').style('opacity', 1);
34557 var curtain = d3.curtain();
34558 selection.call(curtain);
34560 function reveal(box, text, options) {
34561 options = options || {};
34562 if (text) curtain.reveal(box, text, options.tooltipClass, options.duration);
34563 else curtain.reveal(box, '', '', options.duration);
34566 var steps = ['navigation', 'point', 'area', 'line', 'startEditing'].map(function(step, i) {
34567 var s = iD.ui.intro[step](context, reveal)
34568 .on('done', function() {
34569 entered.filter(function(d) {
34570 return d.title === s.title;
34571 }).classed('finished', true);
34572 enter(steps[i + 1]);
34577 steps[steps.length - 1].on('startEditing', function() {
34580 d3.select('.background-layer').style('opacity', opacity);
34581 context.connection().toggle(true).flush().loadedTiles(loadedTiles);
34582 context.history().reset().merge(d3.values(baseEntities));
34583 context.background().baseLayerSource(background);
34584 if (history) context.history().fromJSON(history, false);
34585 context.map().centerZoom(center, zoom);
34586 window.location.replace(hash);
34587 context.inIntro(false);
34590 var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
34592 var buttonwrap = navwrap.append('div')
34593 .attr('class', 'joined')
34594 .selectAll('button.step');
34596 var entered = buttonwrap
34600 .attr('class', 'step')
34601 .on('click', enter);
34604 .call(iD.svg.Icon('#icon-apply', 'pre-text'));
34608 .text(function(d) { return t(d.title); });
34612 function enter (newStep) {
34613 if (step) { step.exit(); }
34615 context.enter(iD.modes.Browse(context));
34620 entered.classed('active', function(d) {
34621 return d.title === step.title;
34629 iD.ui.intro.pointBox = function(point, context) {
34630 var rect = context.surfaceRect();
34631 point = context.projection(point);
34633 left: point[0] + rect.left - 30,
34634 top: point[1] + rect.top - 50,
34640 iD.ui.intro.pad = function(box, padding, context) {
34641 if (box instanceof Array) {
34642 var rect = context.surfaceRect();
34643 box = context.projection(box);
34645 left: box[0] + rect.left,
34646 top: box[1] + rect.top
34650 left: box.left - padding,
34651 top: box.top - padding,
34652 width: (box.width || 0) + 2 * padding,
34653 height: (box.width || 0) + 2 * padding
34657 iD.ui.intro.icon = function(name, svgklass) {
34658 return '<svg class="icon ' + (svgklass || '') + '">' +
34659 '<use xlink:href="' + name + '"></use></svg>';
34661 iD.ui.Lasso = function(context) {
34667 function lasso(selection) {
34669 context.container().classed('lasso', true);
34671 group = selection.append('g')
34672 .attr('class', 'lasso hide');
34674 box = group.append('rect')
34675 .attr('class', 'lasso-box');
34677 group.call(iD.ui.Toggle(true));
34682 function topLeft(d) {
34683 return 'translate(' + Math.min(d[0][0], d[1][0]) + ',' + Math.min(d[0][1], d[1][1]) + ')';
34686 function width(d) { return Math.abs(d[0][0] - d[1][0]); }
34687 function height(d) { return Math.abs(d[0][1] - d[1][1]); }
34692 .attr('transform', topLeft)
34693 .attr('width', width)
34694 .attr('height', height);
34698 lasso.a = function(_) {
34699 if (!arguments.length) return a;
34705 lasso.b = function(_) {
34706 if (!arguments.length) return b;
34712 lasso.close = function() {
34714 group.call(iD.ui.Toggle(false, function() {
34715 d3.select(this).remove();
34718 context.container().classed('lasso', false);
34723 iD.ui.Loading = function(context) {
34728 var loading = function(selection) {
34729 modal = iD.ui.modal(selection, blocking);
34731 var loadertext = modal.select('.content')
34732 .classed('loading-modal', true)
34734 .attr('class', 'modal-section fillL');
34736 loadertext.append('img')
34737 .attr('class', 'loader')
34738 .attr('src', context.imagePath('loader-white.gif'));
34740 loadertext.append('h3')
34743 modal.select('button.close')
34744 .attr('class', 'hide');
34749 loading.message = function(_) {
34750 if (!arguments.length) return message;
34755 loading.blocking = function(_) {
34756 if (!arguments.length) return blocking;
34761 loading.close = function() {
34767 iD.ui.MapData = function(context) {
34769 features = context.features().keys(),
34770 layers = context.layers(),
34771 fills = ['wireframe', 'partial', 'full'],
34772 fillDefault = context.storage('area-fill') || 'partial',
34773 fillSelected = fillDefault;
34776 function map_data(selection) {
34778 function showsFeature(d) {
34779 return context.features().enabled(d);
34782 function autoHiddenFeature(d) {
34783 return context.features().autoHidden(d);
34786 function clickFeature(d) {
34787 context.features().toggle(d);
34791 function showsFill(d) {
34792 return fillSelected === d;
34795 function setFill(d) {
34796 _.each(fills, function(opt) {
34797 context.surface().classed('fill-' + opt, Boolean(opt === d));
34801 if (d !== 'wireframe') {
34803 context.storage('area-fill', d);
34808 function toggleLayer(which) {
34809 var layer = layers.layer(which);
34811 layer.enabled(!layer.enabled());
34816 function clickGpx() {
34817 toggleLayer('gpx');
34820 function clickMapillaryImages() {
34821 toggleLayer('mapillary-images');
34824 function clickMapillarySigns() {
34825 toggleLayer('mapillary-signs');
34829 function drawMapillaryItems(selection) {
34830 var mapillaryImages = layers.layer('mapillary-images'),
34831 mapillarySigns = layers.layer('mapillary-signs'),
34832 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
34833 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
34834 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
34835 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
34837 var mapillaryList = selection
34838 .selectAll('.layer-list-mapillary')
34845 .attr('class', 'layer-list layer-list-mapillary');
34847 var mapillaryImageLayerItem = mapillaryList
34848 .selectAll('.list-item-mapillary-images')
34849 .data(supportsMapillaryImages ? [0] : []);
34851 var enterImages = mapillaryImageLayerItem.enter()
34853 .attr('class', 'list-item-mapillary-images');
34855 var labelImages = enterImages.append('label')
34856 .call(bootstrap.tooltip()
34857 .title(t('mapillary_images.tooltip'))
34858 .placement('top'));
34860 labelImages.append('input')
34861 .attr('type', 'checkbox')
34862 .on('change', clickMapillaryImages);
34864 labelImages.append('span')
34865 .text(t('mapillary_images.title'));
34868 var mapillarySignLayerItem = mapillaryList
34869 .selectAll('.list-item-mapillary-signs')
34870 .data(supportsMapillarySigns ? [0] : []);
34872 var enterSigns = mapillarySignLayerItem.enter()
34874 .attr('class', 'list-item-mapillary-signs');
34876 var labelSigns = enterSigns.append('label')
34877 .call(bootstrap.tooltip()
34878 .title(t('mapillary_signs.tooltip'))
34879 .placement('top'));
34881 labelSigns.append('input')
34882 .attr('type', 'checkbox')
34883 .on('change', clickMapillarySigns);
34885 labelSigns.append('span')
34886 .text(t('mapillary_signs.title'));
34889 mapillaryImageLayerItem
34890 .classed('active', showsMapillaryImages)
34891 .selectAll('input')
34892 .property('checked', showsMapillaryImages);
34894 mapillarySignLayerItem
34895 .classed('active', showsMapillarySigns)
34896 .selectAll('input')
34897 .property('checked', showsMapillarySigns);
34900 mapillaryImageLayerItem.exit()
34902 mapillarySignLayerItem.exit()
34907 function drawGpxItem(selection) {
34908 var gpx = layers.layer('gpx'),
34909 hasGpx = gpx && gpx.hasGpx(),
34910 showsGpx = hasGpx && gpx.enabled();
34912 var gpxLayerItem = selection
34913 .selectAll('.layer-list-gpx')
34914 .data(gpx ? [0] : []);
34917 var enter = gpxLayerItem.enter()
34919 .attr('class', 'layer-list layer-list-gpx')
34921 .classed('list-item-gpx', true);
34923 enter.append('button')
34924 .attr('class', 'list-item-gpx-extent')
34925 .call(bootstrap.tooltip()
34926 .title(t('gpx.zoom'))
34927 .placement('left'))
34928 .on('click', function() {
34929 d3.event.preventDefault();
34930 d3.event.stopPropagation();
34933 .call(iD.svg.Icon('#icon-search'));
34935 enter.append('button')
34936 .attr('class', 'list-item-gpx-browse')
34937 .call(bootstrap.tooltip()
34938 .title(t('gpx.browse'))
34939 .placement('left'))
34940 .on('click', function() {
34941 d3.select(document.createElement('input'))
34942 .attr('type', 'file')
34943 .on('change', function() {
34944 gpx.files(d3.event.target.files);
34948 .call(iD.svg.Icon('#icon-geolocate'));
34950 var labelGpx = enter.append('label')
34951 .call(bootstrap.tooltip()
34952 .title(t('gpx.drag_drop'))
34953 .placement('top'));
34955 labelGpx.append('input')
34956 .attr('type', 'checkbox')
34957 .on('change', clickGpx);
34959 labelGpx.append('span')
34960 .text(t('gpx.local_layer'));
34964 .classed('active', showsGpx)
34965 .selectAll('input')
34966 .property('disabled', !hasGpx)
34967 .property('checked', showsGpx);
34970 gpxLayerItem.exit()
34975 function drawList(selection, data, type, name, change, active) {
34976 var items = selection.selectAll('li')
34980 var enter = items.enter()
34982 .attr('class', 'layer')
34983 .call(bootstrap.tooltip()
34985 .title(function(d) {
34986 var tip = t(name + '.' + d + '.tooltip'),
34987 key = (d === 'wireframe' ? 'W' : null);
34989 if (name === 'feature' && autoHiddenFeature(d)) {
34990 tip += '<div>' + t('map_data.autohidden') + '</div>';
34992 return iD.ui.tooltipHtml(tip, key);
34997 var label = enter.append('label');
34999 label.append('input')
35000 .attr('type', type)
35001 .attr('name', name)
35002 .on('change', change);
35004 label.append('span')
35005 .text(function(d) { return t(name + '.' + d + '.description'); });
35009 .classed('active', active)
35010 .selectAll('input')
35011 .property('checked', active)
35012 .property('indeterminate', function(d) {
35013 return (name === 'feature' && autoHiddenFeature(d));
35022 function update() {
35023 dataLayerContainer.call(drawMapillaryItems);
35024 dataLayerContainer.call(drawGpxItem);
35026 fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
35028 featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
35031 function hidePanel() {
35035 function togglePanel() {
35036 if (d3.event) d3.event.preventDefault();
35037 tooltip.hide(button);
35038 setVisible(!button.classed('active'));
35041 function toggleWireframe() {
35043 d3.event.preventDefault();
35044 d3.event.stopPropagation();
35046 setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
35047 context.map().pan([0,0]); // trigger a redraw
35050 function setVisible(show) {
35051 if (show !== shown) {
35052 button.classed('active', show);
35057 selection.on('mousedown.map_data-inside', function() {
35058 return d3.event.stopPropagation();
35060 content.style('display', 'block')
35061 .style('right', '-300px')
35064 .style('right', '0px');
35066 content.style('display', 'block')
35067 .style('right', '0px')
35070 .style('right', '-300px')
35071 .each('end', function() {
35072 d3.select(this).style('display', 'none');
35074 selection.on('mousedown.map_data-inside', null);
35080 var content = selection.append('div')
35081 .attr('class', 'fillL map-overlay col3 content hide'),
35082 tooltip = bootstrap.tooltip()
35085 .title(iD.ui.tooltipHtml(t('map_data.description'), key)),
35086 button = selection.append('button')
35087 .attr('tabindex', -1)
35088 .on('click', togglePanel)
35089 .call(iD.svg.Icon('#icon-data', 'light'))
35093 content.append('h4')
35094 .text(t('map_data.title'));
35098 content.append('a')
35099 .text(t('map_data.data_layers'))
35101 .classed('hide-toggle', true)
35102 .classed('expanded', true)
35103 .on('click', function() {
35104 var exp = d3.select(this).classed('expanded');
35105 dataLayerContainer.style('display', exp ? 'none' : 'block');
35106 d3.select(this).classed('expanded', !exp);
35107 d3.event.preventDefault();
35110 var dataLayerContainer = content.append('div')
35111 .attr('class', 'data-data-layers')
35112 .style('display', 'block');
35116 content.append('a')
35117 .text(t('map_data.fill_area'))
35119 .classed('hide-toggle', true)
35120 .classed('expanded', false)
35121 .on('click', function() {
35122 var exp = d3.select(this).classed('expanded');
35123 fillContainer.style('display', exp ? 'none' : 'block');
35124 d3.select(this).classed('expanded', !exp);
35125 d3.event.preventDefault();
35128 var fillContainer = content.append('div')
35129 .attr('class', 'data-area-fills')
35130 .style('display', 'none');
35132 var fillList = fillContainer.append('ul')
35133 .attr('class', 'layer-list layer-fill-list');
35137 content.append('a')
35138 .text(t('map_data.map_features'))
35140 .classed('hide-toggle', true)
35141 .classed('expanded', false)
35142 .on('click', function() {
35143 var exp = d3.select(this).classed('expanded');
35144 featureContainer.style('display', exp ? 'none' : 'block');
35145 d3.select(this).classed('expanded', !exp);
35146 d3.event.preventDefault();
35149 var featureContainer = content.append('div')
35150 .attr('class', 'data-feature-filters')
35151 .style('display', 'none');
35153 var featureList = featureContainer.append('ul')
35154 .attr('class', 'layer-list layer-feature-list');
35158 .on('change.map_data-update', update);
35160 setFill(fillDefault);
35162 var keybinding = d3.keybinding('features')
35163 .on(key, togglePanel)
35164 .on('W', toggleWireframe)
35165 .on('B', hidePanel)
35166 .on('H', hidePanel);
35168 d3.select(document)
35171 context.surface().on('mousedown.map_data-outside', hidePanel);
35172 context.container().on('mousedown.map_data-outside', hidePanel);
35177 iD.ui.MapInMap = function(context) {
35180 function map_in_map(selection) {
35181 var backgroundLayer = iD.TileLayer(),
35182 overlayLayers = {},
35183 projection = iD.geo.RawMercator(),
35184 gpxLayer = iD.svg.Gpx(projection, context).showLabels(false),
35185 zoom = d3.behavior.zoom()
35186 .scaleExtent([ztok(0.5), ztok(24)])
35187 .on('zoom', zoomPan),
35188 transformed = false,
35191 zDiff = 6, // by default, minimap renders at (main zoom - 6)
35192 tStart, tLast, tCurr, kLast, kCurr, tiles, svg, timeoutId;
35194 function ztok(z) { return 256 * Math.pow(2, z); }
35195 function ktoz(k) { return Math.log(k) / Math.LN2 - 8; }
35198 function startMouse() {
35199 context.surface().on('mouseup.map-in-map-outside', endMouse);
35200 context.container().on('mouseup.map-in-map-outside', endMouse);
35202 tStart = tLast = tCurr = projection.translate();
35207 function zoomPan() {
35208 var e = d3.event.sourceEvent,
35209 t = d3.event.translate,
35210 k = d3.event.scale,
35211 zMain = ktoz(context.projection.scale() * 2 * Math.PI),
35214 // restrict minimap zoom to < (main zoom - 3)
35215 if (zMini > zMain - 3) {
35217 zoom.scale(kCurr).translate(tCurr); // restore last good values
35223 zDiff = zMain - zMini;
35225 var scale = kCurr / kLast,
35226 tX = (tCurr[0] / scale - tLast[0]) * scale,
35227 tY = (tCurr[1] / scale - tLast[1]) * scale;
35229 iD.util.setTransform(tiles, tX, tY, scale);
35230 iD.util.setTransform(svg, 0, 0, scale);
35231 transformed = true;
35235 e.preventDefault();
35236 e.stopPropagation();
35240 function endMouse() {
35241 context.surface().on('mouseup.map-in-map-outside', null);
35242 context.container().on('mouseup.map-in-map-outside', null);
35244 updateProjection();
35247 if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) {
35248 var dMini = wrap.dimensions(),
35249 cMini = [ dMini[0] / 2, dMini[1] / 2 ];
35251 context.map().center(projection.invert(cMini));
35256 function updateProjection() {
35257 var loc = context.map().center(),
35258 dMini = wrap.dimensions(),
35259 cMini = [ dMini[0] / 2, dMini[1] / 2 ],
35260 tMain = context.projection.translate(),
35261 kMain = context.projection.scale(),
35262 zMain = ktoz(kMain * 2 * Math.PI),
35263 zMini = Math.max(zMain - zDiff, 0.5),
35264 kMini = ztok(zMini);
35268 .scale(kMini / (2 * Math.PI));
35270 var s = projection(loc),
35271 mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0],
35273 cMini[0] - s[0] + tMain[0] + mouse[0],
35274 cMini[1] - s[1] + tMain[1] + mouse[1]
35279 .clipExtent([[0, 0], dMini]);
35286 tLast = tCurr = tMini;
35287 kLast = kCurr = kMini;
35290 iD.util.setTransform(tiles, 0, 0);
35291 iD.util.setTransform(svg, 0, 0);
35292 transformed = false;
35297 function redraw() {
35298 if (hidden) return;
35300 updateProjection();
35302 var dMini = wrap.dimensions(),
35303 zMini = ktoz(projection.scale() * 2 * Math.PI);
35305 // setup tile container
35307 .selectAll('.map-in-map-tiles')
35313 .attr('class', 'map-in-map-tiles');
35315 // redraw background
35317 .source(context.background().baseLayerSource())
35318 .projection(projection)
35319 .dimensions(dMini);
35321 var background = tiles
35322 .selectAll('.map-in-map-background')
35327 .attr('class', 'map-in-map-background');
35330 .call(backgroundLayer);
35334 var overlaySources = context.background().overlayLayerSources();
35335 var activeOverlayLayers = [];
35336 for (var i = 0; i < overlaySources.length; i++) {
35337 if (overlaySources[i].validZoom(zMini)) {
35338 if (!overlayLayers[i]) overlayLayers[i] = iD.TileLayer();
35339 activeOverlayLayers.push(overlayLayers[i]
35340 .source(overlaySources[i])
35341 .projection(projection)
35342 .dimensions(dMini));
35346 var overlay = tiles
35347 .selectAll('.map-in-map-overlay')
35352 .attr('class', 'map-in-map-overlay');
35354 var overlays = overlay
35356 .data(activeOverlayLayers, function(d) { return d.source().name(); });
35358 overlays.enter().append('div');
35359 overlays.each(function(layer) {
35360 d3.select(this).call(layer);
35368 .selectAll('.map-in-map-gpx')
35369 .data(gpxLayer.enabled() ? [0] : []);
35373 .attr('class', 'map-in-map-gpx');
35378 gpx.call(gpxLayer);
35381 // redraw bounding box
35383 var getPath = d3.geo.path().projection(projection),
35384 bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
35386 svg = wrap.selectAll('.map-in-map-svg')
35391 .attr('class', 'map-in-map-svg');
35393 var path = svg.selectAll('.map-in-map-bbox')
35398 .attr('class', 'map-in-map-bbox');
35401 .attr('d', getPath)
35402 .classed('thick', function(d) { return getPath.area(d) < 30; });
35407 function queueRedraw() {
35408 clearTimeout(timeoutId);
35409 timeoutId = setTimeout(function() { redraw(); }, 300);
35413 function toggle() {
35414 if (d3.event) d3.event.preventDefault();
35418 var label = d3.select('.minimap-toggle');
35419 label.classed('active', !hidden)
35420 .select('input').property('checked', !hidden);
35424 .style('display', 'block')
35425 .style('opacity', 1)
35428 .style('opacity', 0)
35429 .each('end', function() {
35430 d3.select(this).style('display', 'none');
35434 .style('display', 'block')
35435 .style('opacity', 0)
35438 .style('opacity', 1);
35444 iD.ui.MapInMap.toggle = toggle;
35446 var wrap = selection.selectAll('.map-in-map')
35451 .attr('class', 'map-in-map')
35452 .style('display', (hidden ? 'none' : 'block'))
35453 .on('mousedown.map-in-map', startMouse)
35454 .on('mouseup.map-in-map', endMouse)
35456 .on('dblclick.zoom', null);
35459 .on('drawn.map-in-map', function(drawn) {
35460 if (drawn.full === true) redraw();
35465 var keybinding = d3.keybinding('map-in-map')
35468 d3.select(document)
35474 iD.ui.modal = function(selection, blocking) {
35476 var previous = selection.select('div.modal');
35477 var animate = previous.empty();
35479 previous.transition()
35481 .style('opacity', 0)
35484 var shaded = selection
35486 .attr('class', 'shaded')
35487 .style('opacity', 0);
35489 shaded.close = function() {
35493 .style('opacity',0)
35498 .style('top','0px');
35502 var keybinding = d3.keybinding('modal')
35503 .on('⌫', shaded.close)
35504 .on('⎋', shaded.close);
35506 d3.select(document).call(keybinding);
35508 var modal = shaded.append('div')
35509 .attr('class', 'modal fillL col6');
35511 shaded.on('click.remove-modal', function() {
35512 if (d3.event.target === this && !blocking) shaded.close();
35515 modal.append('button')
35516 .attr('class', 'close')
35517 .on('click', function() {
35518 if (!blocking) shaded.close();
35521 .attr('class','icon close');
35523 modal.append('div')
35524 .attr('class', 'content');
35527 shaded.transition().style('opacity', 1);
35529 shaded.style('opacity', 1);
35534 iD.ui.Modes = function(context) {
35536 iD.modes.AddPoint(context),
35537 iD.modes.AddLine(context),
35538 iD.modes.AddArea(context)];
35540 function editable() {
35541 return context.editable() && context.mode().id !== 'save';
35544 return function(selection) {
35545 var buttons = selection.selectAll('button.add-button')
35548 buttons.enter().append('button')
35549 .attr('tabindex', -1)
35550 .attr('class', function(mode) { return mode.id + ' add-button col4'; })
35551 .on('click.mode-buttons', function(mode) {
35552 if (mode.id === context.mode().id) {
35553 context.enter(iD.modes.Browse(context));
35555 context.enter(mode);
35558 .call(bootstrap.tooltip()
35559 .placement('bottom')
35561 .title(function(mode) {
35562 return iD.ui.tooltipHtml(mode.description, mode.key);
35566 .on('move.modes', _.debounce(update, 500));
35569 .on('enter.modes', update);
35571 buttons.each(function(d) {
35573 .call(iD.svg.Icon('#icon-' + d.button, 'pre-text'));
35576 buttons.append('span')
35577 .attr('class', 'label')
35578 .text(function(mode) { return mode.title; });
35580 context.on('enter.editor', function(entered) {
35581 buttons.classed('active', function(mode) { return entered.button === mode.button; });
35582 context.container()
35583 .classed('mode-' + entered.id, true);
35586 context.on('exit.editor', function(exited) {
35587 context.container()
35588 .classed('mode-' + exited.id, false);
35591 var keybinding = d3.keybinding('mode-buttons');
35593 modes.forEach(function(m) {
35594 keybinding.on(m.key, function() { if (editable()) context.enter(m); });
35597 d3.select(document)
35600 function update() {
35601 buttons.property('disabled', !editable());
35605 iD.ui.Notice = function(context) {
35606 return function(selection) {
35607 var div = selection.append('div')
35608 .attr('class', 'notice');
35610 var button = div.append('button')
35611 .attr('class', 'zoom-to notice')
35612 .on('click', function() { context.map().zoom(context.minEditableZoom()); });
35615 .call(iD.svg.Icon('#icon-plus', 'pre-text'))
35617 .attr('class', 'label')
35618 .text(t('zoom_in_edit'));
35620 function disableTooHigh() {
35621 div.style('display', context.editable() ? 'none' : 'block');
35625 .on('move.notice', _.debounce(disableTooHigh, 500));
35630 iD.ui.preset = function(context) {
35631 var event = d3.dispatch('change'),
35638 function UIField(field, entity, show) {
35639 field = _.clone(field);
35641 field.input = iD.ui.preset[field.type](field, context)
35642 .on('change', event.change);
35644 if (field.input.entity) field.input.entity(entity);
35646 field.keys = field.keys || [field.key];
35650 field.shown = function() {
35651 return field.id === 'name' || field.show || _.any(field.keys, function(key) { return !!tags[key]; });
35654 field.modified = function() {
35655 var original = context.graph().base().entities[entity.id];
35656 return _.any(field.keys, function(key) {
35657 return original ? tags[key] !== original.tags[key] : tags[key];
35661 field.revert = function() {
35662 var original = context.graph().base().entities[entity.id],
35664 field.keys.forEach(function(key) {
35665 t[key] = original ? original.tags[key] : undefined;
35670 field.present = function() {
35671 return _.any(field.keys, function(key) {
35676 field.remove = function() {
35678 field.keys.forEach(function(key) {
35679 t[key] = undefined;
35687 function fieldKey(field) {
35691 function presets(selection) {
35692 selection.call(iD.ui.Disclosure()
35693 .title(t('inspector.all_fields'))
35694 .expanded(context.storage('preset_fields.expanded') !== 'false')
35695 .on('toggled', toggled)
35696 .content(content));
35698 function toggled(expanded) {
35699 context.storage('preset_fields.expanded', expanded);
35703 function content(selection) {
35705 var entity = context.entity(id),
35706 geometry = context.geometry(id);
35708 fields = [UIField(context.presets().field('name'), entity)];
35710 preset.fields.forEach(function(field) {
35711 if (field.matchGeometry(geometry)) {
35712 fields.push(UIField(field, entity, true));
35716 if (entity.isHighwayIntersection(context.graph())) {
35717 fields.push(UIField(context.presets().field('restrictions'), entity, true));
35720 context.presets().universal().forEach(function(field) {
35721 if (preset.fields.indexOf(field) < 0) {
35722 fields.push(UIField(field, entity));
35727 var shown = fields.filter(function(field) { return field.shown(); }),
35728 notShown = fields.filter(function(field) { return !field.shown(); });
35730 var $form = selection.selectAll('.preset-form')
35733 $form.enter().append('div')
35734 .attr('class', 'preset-form inspector-inner fillL3');
35736 var $fields = $form.selectAll('.form-field')
35737 .data(shown, fieldKey);
35741 var $enter = $fields.enter()
35743 .attr('class', function(field) {
35744 return 'form-field form-field-' + field.id;
35747 var $label = $enter.append('label')
35748 .attr('class', 'form-label')
35749 .attr('for', function(field) { return 'preset-input-' + field.id; })
35750 .text(function(field) { return field.label(); });
35752 var wrap = $label.append('div')
35753 .attr('class', 'form-label-button-wrap');
35755 wrap.append('button')
35756 .attr('class', 'remove-icon')
35757 .call(iD.svg.Icon('#operation-delete'));
35759 wrap.append('button')
35760 .attr('class', 'modified-icon')
35761 .attr('tabindex', -1)
35762 .call(iD.svg.Icon('#icon-undo'));
35766 $fields.select('.form-label-button-wrap .remove-icon')
35767 .on('click', remove);
35769 $fields.select('.modified-icon')
35770 .on('click', revert);
35774 .classed('modified', function(field) {
35775 return field.modified();
35777 .classed('present', function(field) {
35778 return field.present();
35780 .each(function(field) {
35781 var reference = iD.ui.TagReference(field.reference || {key: field.key}, context);
35783 if (state === 'hover') {
35784 reference.showing(false);
35789 .selectAll('input')
35790 .on('keydown', function() {
35791 if (d3.event.keyCode === 13) { // enter
35792 context.enter(iD.modes.Browse(context));
35795 .call(reference.body)
35796 .select('.form-label-button-wrap')
35797 .call(reference.button);
35799 field.input.tags(tags);
35805 notShown = notShown.map(function(field) {
35807 title: field.label(),
35808 value: field.label(),
35813 var $more = selection.selectAll('.more-fields')
35814 .data((notShown.length > 0) ? [0] : []);
35816 $more.enter().append('div')
35817 .attr('class', 'more-fields')
35819 .text(t('inspector.add_fields'));
35821 var $input = $more.selectAll('.value')
35824 $input.enter().append('input')
35825 .attr('class', 'value')
35826 .attr('type', 'text');
35829 .attr('placeholder', function() {
35830 var placeholder = [];
35831 for (var field in notShown) {
35832 placeholder.push(notShown[field].title);
35834 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
35836 .call(d3.combobox().data(notShown)
35838 .on('accept', show));
35846 function show(field) {
35847 field = field.field;
35849 content(selection);
35850 field.input.focus();
35853 function revert(field) {
35854 d3.event.stopPropagation();
35855 d3.event.preventDefault();
35856 event.change(field.revert());
35859 function remove(field) {
35860 d3.event.stopPropagation();
35861 d3.event.preventDefault();
35862 event.change(field.remove());
35866 presets.preset = function(_) {
35867 if (!arguments.length) return preset;
35868 if (preset && preset.id === _.id) return presets;
35874 presets.state = function(_) {
35875 if (!arguments.length) return state;
35880 presets.tags = function(_) {
35881 if (!arguments.length) return tags;
35883 // Don't reset fields here.
35887 presets.entityID = function(_) {
35888 if (!arguments.length) return id;
35889 if (id === _) return presets;
35895 return d3.rebind(presets, event, 'on');
35897 iD.ui.PresetIcon = function() {
35898 var preset, geometry;
35900 function presetIcon(selection) {
35901 selection.each(render);
35904 function render() {
35905 var selection = d3.select(this),
35906 p = preset.apply(this, arguments),
35907 geom = geometry.apply(this, arguments),
35908 icon = p.icon || (geom === 'line' ? 'other-line' : 'marker-stroked'),
35909 maki = iD.data.featureIcons.hasOwnProperty(icon + '-24');
35911 if (icon === 'dentist') maki = true; // workaround for dentist icon missing in `maki-sprite.json`
35913 function tag_classes(p) {
35915 for (var i in p.tags) {
35917 if (p.tags[i] !== '*') {
35918 s += ' tag-' + i + '-' + p.tags[i];
35924 var $fill = selection.selectAll('.preset-icon-fill')
35927 $fill.enter().append('div');
35929 $fill.attr('class', function() {
35930 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
35933 var $frame = selection.selectAll('.preset-icon-frame')
35938 .call(iD.svg.Icon('#preset-icon-frame'));
35940 $frame.attr('class', function() {
35941 return 'preset-icon-frame ' + (geom === 'area' ? '' : 'hide');
35945 var $icon = selection.selectAll('.preset-icon')
35950 .attr('class', 'preset-icon')
35951 .call(iD.svg.Icon(''));
35954 .attr('class', 'preset-icon preset-icon-' + (maki ? '32' : (geom === 'area' ? '44' : '60')));
35956 $icon.selectAll('svg')
35957 .attr('class', function() {
35958 return 'icon ' + icon + tag_classes(p);
35961 $icon.selectAll('use') // workaround: maki parking-24 broken?
35962 .attr('href', '#' + icon + (maki ? ( icon === 'parking' ? '-18' : '-24') : ''));
35965 presetIcon.preset = function(_) {
35966 if (!arguments.length) return preset;
35967 preset = d3.functor(_);
35971 presetIcon.geometry = function(_) {
35972 if (!arguments.length) return geometry;
35973 geometry = d3.functor(_);
35979 iD.ui.PresetList = function(context) {
35980 var event = d3.dispatch('choose'),
35985 function presetList(selection) {
35986 var geometry = context.geometry(id),
35987 presets = context.presets().matchGeometry(geometry);
35989 selection.html('');
35991 var messagewrap = selection.append('div')
35992 .attr('class', 'header fillL cf');
35994 var message = messagewrap.append('h3')
35995 .text(t('inspector.choose'));
35997 if (context.entity(id).isUsed(context.graph())) {
35998 messagewrap.append('button')
35999 .attr('class', 'preset-choose')
36000 .on('click', function() { event.choose(currentPreset); })
36004 messagewrap.append('button')
36005 .attr('class', 'close')
36006 .on('click', function() {
36007 context.enter(iD.modes.Browse(context));
36009 .call(iD.svg.Icon('#icon-close'));
36012 function keydown() {
36013 // hack to let delete shortcut work when search is autofocused
36014 if (search.property('value').length === 0 &&
36015 (d3.event.keyCode === d3.keybinding.keyCodes['⌫'] ||
36016 d3.event.keyCode === d3.keybinding.keyCodes['⌦'])) {
36017 d3.event.preventDefault();
36018 d3.event.stopPropagation();
36019 iD.operations.Delete([id], context)();
36020 } else if (search.property('value').length === 0 &&
36021 (d3.event.ctrlKey || d3.event.metaKey) &&
36022 d3.event.keyCode === d3.keybinding.keyCodes.z) {
36023 d3.event.preventDefault();
36024 d3.event.stopPropagation();
36026 } else if (!d3.event.ctrlKey && !d3.event.metaKey) {
36027 d3.select(this).on('keydown', null);
36031 function keypress() {
36033 var value = search.property('value');
36034 if (d3.event.keyCode === 13 && value.length) {
36035 list.selectAll('.preset-list-item:first-child').datum().choose();
36039 function inputevent() {
36040 var value = search.property('value');
36041 list.classed('filtered', value.length);
36042 if (value.length) {
36043 var results = presets.search(value, geometry);
36044 message.text(t('inspector.results', {
36045 n: results.collection.length,
36048 list.call(drawList, results);
36050 list.call(drawList, context.presets().defaults(geometry, 36));
36051 message.text(t('inspector.choose'));
36055 var searchWrap = selection.append('div')
36056 .attr('class', 'search-header');
36058 var search = searchWrap.append('input')
36059 .attr('class', 'preset-search-input')
36060 .attr('placeholder', t('inspector.search'))
36061 .attr('type', 'search')
36062 .on('keydown', keydown)
36063 .on('keypress', keypress)
36064 .on('input', inputevent);
36067 .call(iD.svg.Icon('#icon-search', 'pre-text'));
36070 search.node().focus();
36073 var listWrap = selection.append('div')
36074 .attr('class', 'inspector-body');
36076 var list = listWrap.append('div')
36077 .attr('class', 'preset-list fillL cf')
36078 .call(drawList, context.presets().defaults(geometry, 36));
36081 function drawList(list, presets) {
36082 var collection = presets.collection.map(function(preset) {
36083 return preset.members ? CategoryItem(preset) : PresetItem(preset);
36086 var items = list.selectAll('.preset-list-item')
36087 .data(collection, function(d) { return d.preset.id; });
36089 items.enter().append('div')
36090 .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
36091 .classed('current', function(item) { return item.preset === currentPreset; })
36092 .each(function(item) {
36093 d3.select(this).call(item);
36095 .style('opacity', 0)
36097 .style('opacity', 1);
36105 function CategoryItem(preset) {
36106 var box, sublist, shown = false;
36108 function item(selection) {
36109 var wrap = selection.append('div')
36110 .attr('class', 'preset-list-button-wrap category col12');
36112 wrap.append('button')
36113 .attr('class', 'preset-list-button')
36114 .classed('expanded', false)
36115 .call(iD.ui.PresetIcon()
36116 .geometry(context.geometry(id))
36118 .on('click', function() {
36119 var isExpanded = d3.select(this).classed('expanded');
36120 var triangle = isExpanded ? '▶ ' : '▼ ';
36121 d3.select(this).classed('expanded', !isExpanded);
36122 d3.select(this).selectAll('.label').text(triangle + preset.name());
36126 .attr('class', 'label')
36128 return '▶ ' + preset.name();
36131 box = selection.append('div')
36132 .attr('class', 'subgrid col12')
36133 .style('max-height', '0px')
36134 .style('opacity', 0);
36137 .attr('class', 'arrow');
36139 sublist = box.append('div')
36140 .attr('class', 'preset-list fillL3 cf fl');
36143 item.choose = function() {
36144 if (!box || !sublist) return;
36150 .style('opacity', '0')
36151 .style('max-height', '0px')
36152 .style('padding-bottom', '0px');
36155 sublist.call(drawList, preset.members);
36158 .style('opacity', '1')
36159 .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
36160 .style('padding-bottom', '20px');
36164 item.preset = preset;
36169 function PresetItem(preset) {
36170 function item(selection) {
36171 var wrap = selection.append('div')
36172 .attr('class', 'preset-list-button-wrap col12');
36174 wrap.append('button')
36175 .attr('class', 'preset-list-button')
36176 .call(iD.ui.PresetIcon()
36177 .geometry(context.geometry(id))
36179 .on('click', item.choose)
36181 .attr('class', 'label')
36182 .text(preset.name());
36184 wrap.call(item.reference.button);
36185 selection.call(item.reference.body);
36188 item.choose = function() {
36189 context.presets().choose(preset);
36192 iD.actions.ChangePreset(id, currentPreset, preset),
36193 t('operations.change_tags.annotation'));
36195 event.choose(preset);
36198 item.help = function() {
36199 d3.event.stopPropagation();
36200 item.reference.toggle();
36203 item.preset = preset;
36204 item.reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context);
36209 presetList.autofocus = function(_) {
36210 if (!arguments.length) return autofocus;
36215 presetList.entityID = function(_) {
36216 if (!arguments.length) return id;
36218 presetList.preset(context.presets().match(context.entity(id), context.graph()));
36222 presetList.preset = function(_) {
36223 if (!arguments.length) return currentPreset;
36228 return d3.rebind(presetList, event, 'on');
36230 iD.ui.RadialMenu = function(context, operations) {
36235 var radialMenu = function(selection) {
36236 if (!operations.length)
36239 selection.node().parentNode.focus();
36241 function click(operation) {
36242 d3.event.stopPropagation();
36243 if (operation.disabled())
36246 radialMenu.close();
36249 menu = selection.append('g')
36250 .attr('class', 'radial-menu')
36251 .attr('transform', 'translate(' + center + ')')
36252 .attr('opacity', 0);
36255 .attr('opacity', 1);
36260 a1 = a0 + (operations.length - 1) * a;
36262 menu.append('path')
36263 .attr('class', 'radial-menu-background')
36264 .attr('d', 'M' + r * Math.sin(a0) + ',' +
36266 ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
36267 (r * Math.sin(a1) + 1e-3) + ',' +
36268 (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
36269 .attr('stroke-width', 50)
36270 .attr('stroke-linecap', 'round');
36272 var button = menu.selectAll()
36276 .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
36277 .classed('disabled', function(d) { return d.disabled(); })
36278 .attr('transform', function(d, i) {
36279 return 'translate(' + iD.geo.roundCoords([
36280 r * Math.sin(a0 + i * a),
36281 r * Math.cos(a0 + i * a)]).join(',') + ')';
36284 button.append('circle')
36286 .on('click', click)
36287 .on('mousedown', mousedown)
36288 .on('mouseover', mouseover)
36289 .on('mouseout', mouseout);
36291 button.append('use')
36292 .attr('transform', 'translate(-10,-10)')
36293 .attr('width', '20')
36294 .attr('height', '20')
36295 .attr('xlink:href', function(d) { return '#operation-' + d.id; });
36297 tooltip = d3.select(document.body)
36299 .attr('class', 'tooltip-inner radial-menu-tooltip');
36301 function mousedown() {
36302 d3.event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
36305 function mouseover(d, i) {
36306 var rect = context.surfaceRect(),
36307 angle = a0 + i * a,
36308 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
36309 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
36310 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
36311 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
36314 .style('top', null)
36315 .style('left', null)
36316 .style('bottom', null)
36317 .style('right', null)
36318 .style('display', 'block')
36319 .html(iD.ui.tooltipHtml(d.tooltip(), d.keys[0]));
36323 .style('right', right)
36324 .style('top', top);
36325 } else if (i >= 4) {
36327 .style('left', left)
36328 .style('bottom', bottom);
36331 .style('left', left)
36332 .style('top', top);
36336 function mouseout() {
36337 tooltip.style('display', 'none');
36341 radialMenu.close = function() {
36344 .style('pointer-events', 'none')
36346 .attr('opacity', 0)
36355 radialMenu.center = function(_) {
36356 if (!arguments.length) return center;
36363 iD.ui.RawMemberEditor = function(context) {
36366 function selectMember(d) {
36367 d3.event.preventDefault();
36368 context.enter(iD.modes.Select(context, [d.id]));
36371 function changeRole(d) {
36372 var role = d3.select(this).property('value');
36374 iD.actions.ChangeMember(d.relation.id, _.extend({}, d.id, {role: role}), d.index),
36375 t('operations.change_role.annotation'));
36378 function deleteMember(d) {
36380 iD.actions.DeleteMember(d.relation.id, d.index),
36381 t('operations.delete_member.annotation'));
36383 if (!context.hasEntity(d.relation.id)) {
36384 context.enter(iD.modes.Browse(context));
36388 function rawMemberEditor(selection) {
36389 var entity = context.entity(id),
36392 entity.members.forEach(function(member, index) {
36398 member: context.hasEntity(member.id)
36402 selection.call(iD.ui.Disclosure()
36403 .title(t('inspector.all_members') + ' (' + memberships.length + ')')
36405 .on('toggled', toggled)
36406 .content(content));
36408 function toggled(expanded) {
36410 selection.node().parentNode.scrollTop += 200;
36414 function content($wrap) {
36415 var $list = $wrap.selectAll('.member-list')
36418 $list.enter().append('ul')
36419 .attr('class', 'member-list');
36421 var $items = $list.selectAll('li')
36422 .data(memberships, function(d) {
36423 return iD.Entity.key(d.relation) + ',' + d.index + ',' +
36424 (d.member ? iD.Entity.key(d.member) : 'incomplete');
36427 var $enter = $items.enter().append('li')
36428 .attr('class', 'member-row form-field')
36429 .classed('member-incomplete', function(d) { return !d.member; });
36431 $enter.each(function(d) {
36433 var $label = d3.select(this).append('label')
36434 .attr('class', 'form-label')
36437 .on('click', selectMember);
36439 $label.append('span')
36440 .attr('class', 'member-entity-type')
36441 .text(function(d) { return context.presets().match(d.member, context.graph()).name(); });
36443 $label.append('span')
36444 .attr('class', 'member-entity-name')
36445 .text(function(d) { return iD.util.displayName(d.member); });
36448 d3.select(this).append('label')
36449 .attr('class', 'form-label')
36450 .text(t('inspector.incomplete'));
36454 $enter.append('input')
36455 .attr('class', 'member-role')
36456 .property('type', 'text')
36457 .attr('maxlength', 255)
36458 .attr('placeholder', t('inspector.role'))
36459 .property('value', function(d) { return d.role; })
36460 .on('change', changeRole);
36462 $enter.append('button')
36463 .attr('tabindex', -1)
36464 .attr('class', 'remove button-input-action member-delete minor')
36465 .on('click', deleteMember)
36466 .call(iD.svg.Icon('#operation-delete'));
36473 rawMemberEditor.entityID = function(_) {
36474 if (!arguments.length) return id;
36476 return rawMemberEditor;
36479 return rawMemberEditor;
36481 iD.ui.RawMembershipEditor = function(context) {
36484 function selectRelation(d) {
36485 d3.event.preventDefault();
36486 context.enter(iD.modes.Select(context, [d.relation.id]));
36489 function changeRole(d) {
36490 var role = d3.select(this).property('value');
36492 iD.actions.ChangeMember(d.relation.id, _.extend({}, d.member, {role: role}), d.index),
36493 t('operations.change_role.annotation'));
36496 function addMembership(d, role) {
36501 iD.actions.AddMember(d.relation.id, {id: id, type: context.entity(id).type, role: role}),
36502 t('operations.add_member.annotation'));
36505 var relation = iD.Relation();
36508 iD.actions.AddEntity(relation),
36509 iD.actions.AddMember(relation.id, {id: id, type: context.entity(id).type, role: role}),
36510 t('operations.add.annotation.relation'));
36512 context.enter(iD.modes.Select(context, [relation.id]));
36516 function deleteMembership(d) {
36518 iD.actions.DeleteMember(d.relation.id, d.index),
36519 t('operations.delete_member.annotation'));
36522 function relations(q) {
36523 var newRelation = {
36525 value: t('inspector.new_relation')
36528 graph = context.graph();
36530 context.intersects(context.extent()).forEach(function(entity) {
36531 if (entity.type !== 'relation' || entity.id === id)
36534 var presetName = context.presets().match(entity, graph).name(),
36535 entityName = iD.util.displayName(entity) || '';
36537 var value = presetName + ' ' + entityName;
36538 if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
36547 result.sort(function(a, b) {
36548 return iD.Relation.creationOrder(a.relation, b.relation);
36550 result.unshift(newRelation);
36555 function rawMembershipEditor(selection) {
36556 var entity = context.entity(id),
36559 context.graph().parentRelations(entity).forEach(function(relation) {
36560 relation.members.forEach(function(member, index) {
36561 if (member.id === entity.id) {
36562 memberships.push({relation: relation, member: member, index: index});
36567 selection.call(iD.ui.Disclosure()
36568 .title(t('inspector.all_relations') + ' (' + memberships.length + ')')
36570 .on('toggled', toggled)
36571 .content(content));
36573 function toggled(expanded) {
36575 selection.node().parentNode.scrollTop += 200;
36579 function content($wrap) {
36580 var $list = $wrap.selectAll('.member-list')
36583 $list.enter().append('ul')
36584 .attr('class', 'member-list');
36586 var $items = $list.selectAll('li.member-row-normal')
36587 .data(memberships, function(d) { return iD.Entity.key(d.relation) + ',' + d.index; });
36589 var $enter = $items.enter().append('li')
36590 .attr('class', 'member-row member-row-normal form-field');
36592 var $label = $enter.append('label')
36593 .attr('class', 'form-label')
36596 .on('click', selectRelation);
36598 $label.append('span')
36599 .attr('class', 'member-entity-type')
36600 .text(function(d) { return context.presets().match(d.relation, context.graph()).name(); });
36602 $label.append('span')
36603 .attr('class', 'member-entity-name')
36604 .text(function(d) { return iD.util.displayName(d.relation); });
36606 $enter.append('input')
36607 .attr('class', 'member-role')
36608 .property('type', 'text')
36609 .attr('maxlength', 255)
36610 .attr('placeholder', t('inspector.role'))
36611 .property('value', function(d) { return d.member.role; })
36612 .on('change', changeRole);
36614 $enter.append('button')
36615 .attr('tabindex', -1)
36616 .attr('class', 'remove button-input-action member-delete minor')
36617 .on('click', deleteMembership)
36618 .call(iD.svg.Icon('#operation-delete'));
36624 var $new = $list.selectAll('.member-row-new')
36627 $enter = $new.enter().append('li')
36628 .attr('class', 'member-row member-row-new form-field');
36630 $enter.append('input')
36631 .attr('type', 'text')
36632 .attr('class', 'member-entity-input')
36633 .call(d3.combobox()
36635 .fetcher(function(value, callback) {
36636 callback(relations(value));
36638 .on('accept', function(d) {
36639 addMembership(d, $new.select('.member-role').property('value'));
36642 $enter.append('input')
36643 .attr('class', 'member-role')
36644 .property('type', 'text')
36645 .attr('maxlength', 255)
36646 .attr('placeholder', t('inspector.role'))
36647 .on('change', changeRole);
36649 $enter.append('button')
36650 .attr('tabindex', -1)
36651 .attr('class', 'remove button-input-action member-delete minor')
36652 .on('click', deleteMembership)
36653 .call(iD.svg.Icon('#operation-delete'));
36656 $list.selectAll('.member-row-new')
36660 var $add = $wrap.selectAll('.add-relation')
36665 .attr('class', 'add-relation')
36666 .call(iD.svg.Icon('#icon-plus', 'light'));
36668 $wrap.selectAll('.add-relation')
36669 .on('click', function() {
36672 $list.selectAll('.member-entity-input').node().focus();
36677 rawMembershipEditor.entityID = function(_) {
36678 if (!arguments.length) return id;
36680 return rawMembershipEditor;
36683 return rawMembershipEditor;
36685 iD.ui.RawTagEditor = function(context) {
36686 var event = d3.dispatch('change'),
36693 function rawTagEditor(selection) {
36694 var count = Object.keys(tags).filter(function(d) { return d; }).length;
36696 selection.call(iD.ui.Disclosure()
36697 .title(t('inspector.all_tags') + ' (' + count + ')')
36698 .expanded(context.storage('raw_tag_editor.expanded') === 'true' || preset.isFallback())
36699 .on('toggled', toggled)
36700 .content(content));
36702 function toggled(expanded) {
36703 context.storage('raw_tag_editor.expanded', expanded);
36705 selection.node().parentNode.scrollTop += 200;
36710 function content($wrap) {
36711 var entries = d3.entries(tags);
36713 if (!entries.length || showBlank) {
36715 entries.push({key: '', value: ''});
36718 var $list = $wrap.selectAll('.tag-list')
36721 $list.enter().append('ul')
36722 .attr('class', 'tag-list');
36724 var $newTag = $wrap.selectAll('.add-tag')
36729 .attr('class', 'add-tag')
36730 .call(iD.svg.Icon('#icon-plus', 'light'));
36732 $newTag.on('click', addTag);
36734 var $items = $list.selectAll('li')
36735 .data(entries, function(d) { return d.key; });
36739 var $enter = $items.enter().append('li')
36740 .attr('class', 'tag-row cf');
36742 $enter.append('div')
36743 .attr('class', 'key-wrap')
36745 .property('type', 'text')
36746 .attr('class', 'key')
36747 .attr('maxlength', 255);
36749 $enter.append('div')
36750 .attr('class', 'input-wrap-position')
36752 .property('type', 'text')
36753 .attr('class', 'value')
36754 .attr('maxlength', 255);
36756 $enter.append('button')
36757 .attr('tabindex', -1)
36758 .attr('class', 'remove minor')
36759 .call(iD.svg.Icon('#operation-delete'));
36761 if (context.taginfo()) {
36762 $enter.each(bindTypeahead);
36769 $items.each(function(tag) {
36770 var isRelation = (context.entity(id).type === 'relation'),
36772 if (isRelation && tag.key === 'type')
36773 reference = iD.ui.TagReference({rtype: tag.value}, context);
36775 reference = iD.ui.TagReference({key: tag.key, value: tag.value}, context);
36777 if (state === 'hover') {
36778 reference.showing(false);
36782 .call(reference.button)
36783 .call(reference.body);
36786 $items.select('input.key')
36787 .value(function(d) { return d.key; })
36788 .on('blur', keyChange)
36789 .on('change', keyChange);
36791 $items.select('input.value')
36792 .value(function(d) { return d.value; })
36793 .on('blur', valueChange)
36794 .on('change', valueChange)
36795 .on('keydown.push-more', pushMore);
36797 $items.select('button.remove')
36798 .on('click', removeTag);
36804 function pushMore() {
36805 if (d3.event.keyCode === 9 && !d3.event.shiftKey &&
36806 $list.selectAll('li:last-child input.value').node() === this) {
36811 function bindTypeahead() {
36812 var row = d3.select(this),
36813 key = row.selectAll('input.key'),
36814 value = row.selectAll('input.value');
36816 function sort(value, data) {
36817 var sameletter = [],
36819 for (var i = 0; i < data.length; i++) {
36820 if (data[i].value.substring(0, value.length) === value) {
36821 sameletter.push(data[i]);
36823 other.push(data[i]);
36826 return sameletter.concat(other);
36829 key.call(d3.combobox()
36830 .fetcher(function(value, callback) {
36831 context.taginfo().keys({
36833 geometry: context.geometry(id),
36835 }, function(err, data) {
36836 if (!err) callback(sort(value, data));
36840 value.call(d3.combobox()
36841 .fetcher(function(value, callback) {
36842 context.taginfo().values({
36845 geometry: context.geometry(id),
36847 }, function(err, data) {
36848 if (!err) callback(sort(value, data));
36853 function unbind() {
36854 var row = d3.select(this);
36856 row.selectAll('input.key')
36857 .call(d3.combobox.off);
36859 row.selectAll('input.value')
36860 .call(d3.combobox.off);
36863 function keyChange(d) {
36865 kNew = this.value.trim(),
36868 if (kNew && kNew !== kOld) {
36869 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
36871 suffix = +(match[2] || 1);
36872 while (tags[kNew]) { // rename key if already in use
36873 kNew = base + '_' + suffix++;
36876 tag[kOld] = undefined;
36877 tag[kNew] = d.value;
36878 d.key = kNew; // Maintain DOM identity through the subsequent update.
36883 function valueChange(d) {
36885 tag[d.key] = this.value;
36889 function removeTag(d) {
36891 tag[d.key] = undefined;
36893 d3.select(this.parentNode).remove();
36896 function addTag() {
36897 // Wrapped in a setTimeout in case it's being called from a blur
36898 // handler. Without the setTimeout, the call to `content` would
36899 // wipe out the pending value change.
36900 setTimeout(function() {
36903 $list.selectAll('li:last-child input.key').node().focus();
36908 rawTagEditor.state = function(_) {
36909 if (!arguments.length) return state;
36911 return rawTagEditor;
36914 rawTagEditor.preset = function(_) {
36915 if (!arguments.length) return preset;
36917 return rawTagEditor;
36920 rawTagEditor.tags = function(_) {
36921 if (!arguments.length) return tags;
36923 return rawTagEditor;
36926 rawTagEditor.entityID = function(_) {
36927 if (!arguments.length) return id;
36929 return rawTagEditor;
36932 return d3.rebind(rawTagEditor, event, 'on');
36934 iD.ui.Restore = function(context) {
36935 return function(selection) {
36936 if (!context.history().lock() || !context.history().restorableChanges())
36939 var modal = iD.ui.modal(selection);
36941 modal.select('.modal')
36942 .attr('class', 'modal fillL col6');
36944 var introModal = modal.select('.content');
36946 introModal.attr('class','cf');
36948 introModal.append('div')
36949 .attr('class', 'modal-section')
36951 .text(t('restore.heading'));
36953 introModal.append('div')
36954 .attr('class','modal-section')
36956 .text(t('restore.description'));
36958 var buttonWrap = introModal.append('div')
36959 .attr('class', 'modal-actions cf');
36961 var restore = buttonWrap.append('button')
36962 .attr('class', 'restore col6')
36963 .text(t('restore.restore'))
36964 .on('click', function() {
36965 context.history().restore();
36969 buttonWrap.append('button')
36970 .attr('class', 'reset col6')
36971 .text(t('restore.reset'))
36972 .on('click', function() {
36973 context.history().clearSaved();
36977 restore.node().focus();
36980 iD.ui.Save = function(context) {
36981 var history = context.history(),
36982 key = iD.ui.cmd('⌘S');
36984 function saving() {
36985 return context.mode().id === 'save';
36989 d3.event.preventDefault();
36990 if (!context.inIntro() && !saving() && history.hasChanges()) {
36991 context.enter(iD.modes.Save(context));
36995 return function(selection) {
36996 var tooltip = bootstrap.tooltip()
36997 .placement('bottom')
36999 .title(iD.ui.tooltipHtml(t('save.no_changes'), key));
37001 var button = selection.append('button')
37002 .attr('class', 'save col12 disabled')
37003 .attr('tabindex', -1)
37007 button.append('span')
37008 .attr('class', 'label')
37009 .text(t('save.title'));
37011 button.append('span')
37012 .attr('class', 'count')
37015 var keybinding = d3.keybinding('undo-redo')
37016 .on(key, save, true);
37018 d3.select(document)
37021 var numChanges = 0;
37023 context.history().on('change.save', function() {
37024 var _ = history.difference().summary().length;
37025 if (_ === numChanges)
37029 tooltip.title(iD.ui.tooltipHtml(t(numChanges > 0 ?
37030 'save.help' : 'save.no_changes'), key));
37033 .classed('disabled', numChanges === 0)
37034 .classed('has-count', numChanges > 0);
37036 button.select('span.count')
37040 context.on('enter.save', function() {
37041 button.property('disabled', saving());
37042 if (saving()) button.call(tooltip.hide);
37046 iD.ui.Scale = function(context) {
37047 var projection = context.projection,
37051 function scaleDefs(loc1, loc2) {
37052 var lat = (loc2[1] + loc1[1]) / 2,
37053 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
37054 conversion = (imperial ? 3.28084 : 1),
37055 dist = iD.geo.lonToMeters(loc2[0] - loc1[0], lat) * conversion,
37056 scale = { dist: 0, px: 0, text: '' },
37057 buckets, i, val, dLon;
37060 buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
37062 buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
37065 // determine a user-friendly endpoint for the scale
37066 for (i = 0; i < buckets.length; i++) {
37069 scale.dist = Math.floor(dist / val) * val;
37074 dLon = iD.geo.metersToLon(scale.dist / conversion, lat);
37075 scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
37078 if (scale.dist >= 5280) {
37079 scale.dist /= 5280;
37080 scale.text = String(scale.dist) + ' mi';
37082 scale.text = String(scale.dist) + ' ft';
37085 if (scale.dist >= 1000) {
37086 scale.dist /= 1000;
37087 scale.text = String(scale.dist) + ' km';
37089 scale.text = String(scale.dist) + ' m';
37096 function update(selection) {
37097 // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
37098 var dims = context.map().dimensions(),
37099 loc1 = projection.invert([0, dims[1]]),
37100 loc2 = projection.invert([maxLength, dims[1]]),
37101 scale = scaleDefs(loc1, loc2);
37103 selection.select('#scalepath')
37104 .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
37106 selection.select('#scaletext')
37107 .attr('x', scale.px + 8)
37108 .attr('y', tickHeight)
37112 return function(selection) {
37113 var g = selection.append('svg')
37114 .attr('id', 'scale')
37116 .attr('transform', 'translate(10,11)');
37118 g.append('path').attr('id', 'scalepath');
37119 g.append('text').attr('id', 'scaletext');
37123 context.map().on('move.scale', function() {
37128 iD.ui.SelectionList = function(context, selectedIDs) {
37130 function selectEntity(entity) {
37131 context.enter(iD.modes.Select(context, [entity.id]).suppressMenu(true));
37135 function selectionList(selection) {
37136 selection.classed('selection-list-pane', true);
37138 var header = selection.append('div')
37139 .attr('class', 'header fillL cf');
37141 header.append('h3')
37142 .text(t('inspector.multiselect'));
37144 var listWrap = selection.append('div')
37145 .attr('class', 'inspector-body');
37147 var list = listWrap.append('div')
37148 .attr('class', 'feature-list cf');
37150 context.history().on('change.selection-list', drawList);
37153 function drawList() {
37154 var entities = selectedIDs
37155 .map(function(id) { return context.hasEntity(id); })
37156 .filter(function(entity) { return entity; });
37158 var items = list.selectAll('.feature-list-item')
37159 .data(entities, iD.Entity.key);
37161 var enter = items.enter().append('button')
37162 .attr('class', 'feature-list-item')
37163 .on('click', selectEntity);
37166 var label = enter.append('div')
37167 .attr('class', 'label')
37168 .call(iD.svg.Icon('', 'pre-text'));
37170 label.append('span')
37171 .attr('class', 'entity-type');
37173 label.append('span')
37174 .attr('class', 'entity-name');
37177 items.selectAll('use')
37178 .attr('href', function() {
37179 var entity = this.parentNode.parentNode.__data__;
37180 return '#icon-' + context.geometry(entity.id);
37183 items.selectAll('.entity-type')
37184 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
37186 items.selectAll('.entity-name')
37187 .text(function(entity) { return iD.util.displayName(entity); });
37195 return selectionList;
37198 iD.ui.Sidebar = function(context) {
37199 var inspector = iD.ui.Inspector(context),
37202 function sidebar(selection) {
37203 var featureListWrap = selection.append('div')
37204 .attr('class', 'feature-list-pane')
37205 .call(iD.ui.FeatureList(context));
37207 selection.call(iD.ui.Notice(context));
37209 var inspectorWrap = selection.append('div')
37210 .attr('class', 'inspector-hidden inspector-wrap fr');
37212 function hover(id) {
37213 if (!current && context.hasEntity(id)) {
37214 featureListWrap.classed('inspector-hidden', true);
37215 inspectorWrap.classed('inspector-hidden', false)
37216 .classed('inspector-hover', true);
37218 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
37223 inspectorWrap.call(inspector);
37225 } else if (!current) {
37226 featureListWrap.classed('inspector-hidden', false);
37227 inspectorWrap.classed('inspector-hidden', true);
37228 inspector.state('hide');
37232 sidebar.hover = _.throttle(hover, 200);
37234 sidebar.select = function(id, newFeature) {
37235 if (!current && id) {
37236 featureListWrap.classed('inspector-hidden', true);
37237 inspectorWrap.classed('inspector-hidden', false)
37238 .classed('inspector-hover', false);
37240 if (inspector.entityID() !== id || inspector.state() !== 'select') {
37244 .newFeature(newFeature);
37246 inspectorWrap.call(inspector);
37248 } else if (!current) {
37249 featureListWrap.classed('inspector-hidden', false);
37250 inspectorWrap.classed('inspector-hidden', true);
37251 inspector.state('hide');
37255 sidebar.show = function(component) {
37256 featureListWrap.classed('inspector-hidden', true);
37257 inspectorWrap.classed('inspector-hidden', true);
37258 if (current) current.remove();
37259 current = selection.append('div')
37260 .attr('class', 'sidebar-component')
37264 sidebar.hide = function() {
37265 featureListWrap.classed('inspector-hidden', false);
37266 inspectorWrap.classed('inspector-hidden', true);
37267 if (current) current.remove();
37272 sidebar.hover = function() {};
37273 sidebar.hover.cancel = function() {};
37274 sidebar.select = function() {};
37275 sidebar.show = function() {};
37276 sidebar.hide = function() {};
37280 iD.ui.SourceSwitch = function(context) {
37284 d3.event.preventDefault();
37286 if (context.history().hasChanges() &&
37287 !window.confirm(t('source_switch.lose_changes'))) return;
37289 var live = d3.select(this)
37292 context.connection()
37293 .switch(live ? keys[1] : keys[0]);
37295 context.enter(iD.modes.Browse(context));
37299 .text(live ? t('source_switch.dev') : t('source_switch.live'))
37300 .classed('live', !live);
37303 var sourceSwitch = function(selection) {
37304 selection.append('a')
37306 .text(t('source_switch.live'))
37307 .classed('live', true)
37308 .attr('tabindex', -1)
37309 .on('click', click);
37312 sourceSwitch.keys = function(_) {
37313 if (!arguments.length) return keys;
37315 return sourceSwitch;
37318 return sourceSwitch;
37320 iD.ui.Spinner = function(context) {
37321 var connection = context.connection();
37323 return function(selection) {
37324 var img = selection.append('img')
37325 .attr('src', context.imagePath('loader-black.gif'))
37326 .style('opacity', 0);
37328 connection.on('loading.spinner', function() {
37330 .style('opacity', 1);
37333 connection.on('loaded.spinner', function() {
37335 .style('opacity', 0);
37339 iD.ui.Splash = function(context) {
37340 return function(selection) {
37341 if (context.storage('sawSplash'))
37344 context.storage('sawSplash', true);
37346 var modal = iD.ui.modal(selection);
37348 modal.select('.modal')
37349 .attr('class', 'modal-splash modal col6');
37351 var introModal = modal.select('.content')
37353 .attr('class', 'fillL');
37355 introModal.append('div')
37356 .attr('class','modal-section cf')
37357 .append('h3').text(t('splash.welcome'));
37359 introModal.append('div')
37360 .attr('class','modal-section')
37362 .html(t('splash.text', {
37363 version: iD.version,
37364 website: '<a href="http://ideditor.com/">ideditor.com</a>',
37365 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
37368 var buttons = introModal.append('div').attr('class', 'modal-actions cf');
37370 buttons.append('button')
37371 .attr('class', 'col6 walkthrough')
37372 .text(t('splash.walkthrough'))
37373 .on('click', function() {
37374 d3.select(document.body).call(iD.ui.intro(context));
37378 buttons.append('button')
37379 .attr('class', 'col6 start')
37380 .text(t('splash.start'))
37381 .on('click', modal.close);
37383 modal.select('button.close').attr('class','hide');
37387 iD.ui.Status = function(context) {
37388 var connection = context.connection(),
37391 return function(selection) {
37393 function update() {
37395 connection.status(function(err, apiStatus) {
37397 selection.html('');
37399 if (err && errCount++ < 2) return;
37402 selection.text(t('status.error'));
37404 } else if (apiStatus === 'readonly') {
37405 selection.text(t('status.readonly'));
37407 } else if (apiStatus === 'offline') {
37408 selection.text(t('status.offline'));
37411 selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
37412 if (!err) errCount = 0;
37417 connection.on('auth', function() { update(selection); });
37418 window.setInterval(update, 90000);
37422 iD.ui.Success = function(context) {
37423 var dispatch = d3.dispatch('cancel'),
37426 function success(selection) {
37427 var message = (changeset.comment || t('success.edited_osm')).substring(0, 130) +
37428 ' ' + context.connection().changesetURL(changeset.id);
37430 var header = selection.append('div')
37431 .attr('class', 'header fillL');
37433 header.append('button')
37434 .attr('class', 'fr')
37435 .on('click', function() { dispatch.cancel(); })
37436 .call(iD.svg.Icon('#icon-close'));
37438 header.append('h3')
37439 .text(t('success.just_edited'));
37441 var body = selection.append('div')
37442 .attr('class', 'body save-success fillL');
37445 .html(t('success.help_html'));
37448 .attr('class', 'details')
37449 .attr('target', '_blank')
37450 .attr('tabindex', -1)
37451 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37452 .attr('href', t('success.help_link_url'))
37454 .text(t('success.help_link_text'));
37456 var changesetURL = context.connection().changesetURL(changeset.id);
37459 .attr('class', 'button col12 osm')
37460 .attr('target', '_blank')
37461 .attr('href', changesetURL)
37462 .text(t('success.view_on_osm'));
37465 facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
37466 twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
37467 google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
37470 body.selectAll('.button.social')
37471 .data(d3.entries(sharing))
37474 .attr('class', 'button social col4')
37475 .attr('target', '_blank')
37476 .attr('href', function(d) { return d.value; })
37477 .call(bootstrap.tooltip()
37478 .title(function(d) { return t('success.' + d.key); })
37479 .placement('bottom'))
37480 .each(function(d) { d3.select(this).call(iD.svg.Icon('#logo-' + d.key, 'social')); });
37483 success.changeset = function(_) {
37484 if (!arguments.length) return changeset;
37489 return d3.rebind(success, dispatch, 'on');
37491 iD.ui.TagReference = function(tag, context) {
37492 var tagReference = {},
37498 function findLocal(data) {
37499 var locale = iD.detect().locale.toLowerCase(),
37502 localized = _.find(data, function(d) {
37503 return d.lang.toLowerCase() === locale;
37505 if (localized) return localized;
37507 // try the non-regional version of a language, like
37508 // 'en' if the language is 'en-US'
37509 if (locale.indexOf('-') !== -1) {
37510 var first = locale.split('-')[0];
37511 localized = _.find(data, function(d) {
37512 return d.lang.toLowerCase() === first;
37514 if (localized) return localized;
37517 // finally fall back to english
37518 return _.find(data, function(d) {
37519 return d.lang.toLowerCase() === 'en';
37523 function load(param) {
37524 button.classed('tag-reference-loading', true);
37526 context.taginfo().docs(param, function show(err, data) {
37528 if (!err && data) {
37529 docs = findLocal(data);
37534 if (!docs || !docs.description) {
37535 if (param.hasOwnProperty('value')) {
37536 load(_.omit(param, 'value')); // retry with key only
37538 body.append('p').text(t('inspector.no_documentation_key'));
37544 if (docs.image && docs.image.thumb_url_prefix) {
37547 .attr('class', 'wiki-image')
37548 .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
37549 .on('load', function() { done(); })
37550 .on('error', function() { d3.select(this).remove(); done(); });
37557 .text(docs.description);
37561 .attr('target', '_blank')
37562 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
37563 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37565 .text(t('inspector.reference'));
37572 button.classed('tag-reference-loading', false);
37576 .style('max-height', '200px')
37577 .style('opacity', '1');
37582 function hide(selection) {
37583 selection = selection || body.transition().duration(200);
37586 .style('max-height', '0px')
37587 .style('opacity', '0');
37592 tagReference.button = function(selection) {
37593 button = selection.selectAll('.tag-reference-button')
37598 .attr('class', 'tag-reference-button')
37599 .attr('tabindex', -1)
37600 .call(iD.svg.Icon('#icon-inspect'));
37602 button.on('click', function () {
37603 d3.event.stopPropagation();
37604 d3.event.preventDefault();
37607 } else if (loaded) {
37610 if (context.taginfo()) {
37617 tagReference.body = function(selection) {
37618 body = selection.selectAll('.tag-reference-body')
37621 body.enter().append('div')
37622 .attr('class', 'tag-reference-body cf')
37623 .style('max-height', '0')
37624 .style('opacity', '0');
37626 if (showing === false) {
37631 tagReference.showing = function(_) {
37632 if (!arguments.length) return showing;
37634 return tagReference;
37637 return tagReference;
37639 // toggles the visibility of ui elements, using a combination of the
37640 // hide class, which sets display=none, and a d3 transition for opacity.
37641 // this will cause blinking when called repeatedly, so check that the
37642 // value actually changes between calls.
37643 iD.ui.Toggle = function(show, callback) {
37644 return function(selection) {
37646 .style('opacity', show ? 0 : 1)
37647 .classed('hide', false)
37649 .style('opacity', show ? 1 : 0)
37650 .each('end', function() {
37652 .classed('hide', !show)
37653 .style('opacity', null);
37654 if (callback) callback.apply(this);
37658 iD.ui.UndoRedo = function(context) {
37661 cmd: iD.ui.cmd('⌘Z'),
37662 action: function() { if (!(context.inIntro() || saving())) context.undo(); },
37663 annotation: function() { return context.history().undoAnnotation(); }
37666 cmd: iD.ui.cmd('⌘⇧Z'),
37667 action: function() {if (!(context.inIntro() || saving())) context.redo(); },
37668 annotation: function() { return context.history().redoAnnotation(); }
37671 function saving() {
37672 return context.mode().id === 'save';
37675 return function(selection) {
37676 var tooltip = bootstrap.tooltip()
37677 .placement('bottom')
37679 .title(function (d) {
37680 return iD.ui.tooltipHtml(d.annotation() ?
37681 t(d.id + '.tooltip', {action: d.annotation()}) :
37682 t(d.id + '.nothing'), d.cmd);
37685 var buttons = selection.selectAll('button')
37687 .enter().append('button')
37688 .attr('class', 'col6 disabled')
37689 .on('click', function(d) { return d.action(); })
37692 buttons.each(function(d) {
37694 .call(iD.svg.Icon('#icon-' + d.id));
37697 var keybinding = d3.keybinding('undo')
37698 .on(commands[0].cmd, function() { d3.event.preventDefault(); commands[0].action(); })
37699 .on(commands[1].cmd, function() { d3.event.preventDefault(); commands[1].action(); });
37701 d3.select(document)
37705 .on('change.undo_redo', update);
37708 .on('enter.undo_redo', update);
37710 function update() {
37712 .property('disabled', saving())
37713 .classed('disabled', function(d) { return !d.annotation(); })
37715 var selection = d3.select(this);
37716 if (selection.property('tooltipVisible')) {
37717 selection.call(tooltip.show);
37723 iD.ui.ViewOnOSM = function(context) {
37726 function viewOnOSM(selection) {
37727 var entity = context.entity(id);
37729 selection.style('display', entity.isNew() ? 'none' : null);
37731 var $link = selection.selectAll('.view-on-osm')
37736 .attr('class', 'view-on-osm')
37737 .attr('target', '_blank')
37738 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37740 .text(t('inspector.view_on_osm'));
37743 .attr('href', context.connection().entityURL(entity));
37746 viewOnOSM.entityID = function(_) {
37747 if (!arguments.length) return id;
37754 iD.ui.Zoom = function(context) {
37758 title: t('zoom.in'),
37759 action: context.zoomIn,
37764 title: t('zoom.out'),
37765 action: context.zoomOut,
37769 function zoomIn() {
37770 d3.event.preventDefault();
37771 if (!context.inIntro()) context.zoomIn();
37774 function zoomOut() {
37775 d3.event.preventDefault();
37776 if (!context.inIntro()) context.zoomOut();
37779 function zoomInFurther() {
37780 d3.event.preventDefault();
37781 if (!context.inIntro()) context.zoomInFurther();
37784 function zoomOutFurther() {
37785 d3.event.preventDefault();
37786 if (!context.inIntro()) context.zoomOutFurther();
37790 return function(selection) {
37791 var button = selection.selectAll('button')
37793 .enter().append('button')
37794 .attr('tabindex', -1)
37795 .attr('class', function(d) { return d.id; })
37796 .on('click.editor', function(d) { d.action(); })
37797 .call(bootstrap.tooltip()
37800 .title(function(d) {
37801 return iD.ui.tooltipHtml(d.title, d.key);
37804 button.each(function(d) {
37806 .call(iD.svg.Icon('#icon-' + d.icon, 'light'));
37809 var keybinding = d3.keybinding('zoom');
37811 _.each(['=','ffequals','plus','ffplus'], function(key) {
37812 keybinding.on(key, zoomIn);
37813 keybinding.on('⇧' + key, zoomIn);
37814 keybinding.on(iD.ui.cmd('⌘' + key), zoomInFurther);
37815 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomInFurther);
37817 _.each(['-','ffminus','_','dash'], function(key) {
37818 keybinding.on(key, zoomOut);
37819 keybinding.on('⇧' + key, zoomOut);
37820 keybinding.on(iD.ui.cmd('⌘' + key), zoomOutFurther);
37821 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomOutFurther);
37824 d3.select(document)
37828 iD.ui.preset.access = function(field) {
37829 var dispatch = d3.dispatch('change'),
37832 function access(selection) {
37833 var wrap = selection.selectAll('.preset-input-wrap')
37836 wrap.enter().append('div')
37837 .attr('class', 'cf preset-input-wrap')
37840 items = wrap.select('ul').selectAll('li')
37845 var enter = items.enter().append('li')
37846 .attr('class', function(d) { return 'cf preset-access-' + d; });
37848 enter.append('span')
37849 .attr('class', 'col6 label preset-label-access')
37850 .attr('for', function(d) { return 'preset-input-access-' + d; })
37851 .text(function(d) { return field.t('types.' + d); });
37853 enter.append('div')
37854 .attr('class', 'col6 preset-input-access-wrap')
37856 .attr('type', 'text')
37857 .attr('class', 'preset-input-access')
37858 .attr('id', function(d) { return 'preset-input-access-' + d; })
37859 .each(function(d) {
37861 .call(d3.combobox()
37862 .data(access.options(d)));
37867 wrap.selectAll('.preset-input-access')
37868 .on('change', change)
37869 .on('blur', change);
37872 function change(d) {
37874 tag[d] = d3.select(this).value() || undefined;
37875 dispatch.change(tag);
37878 access.options = function(type) {
37879 var options = ['no', 'permissive', 'private', 'destination'];
37881 if (type !== 'access') {
37882 options.unshift('yes');
37883 options.push('designated');
37885 if (type === 'bicycle') {
37886 options.push('dismount');
37890 return options.map(function(option) {
37892 title: field.t('options.' + option + '.description'),
37898 var placeholders = {
37900 foot: 'designated',
37901 motor_vehicle: 'no'
37905 motor_vehicle: 'no',
37911 motor_vehicle: 'no'
37914 motor_vehicle: 'no',
37915 bicycle: 'designated'
37918 motor_vehicle: 'no',
37919 horse: 'designated'
37923 motor_vehicle: 'no',
37929 motor_vehicle: 'yes',
37934 motor_vehicle: 'yes'
37938 motor_vehicle: 'yes',
37944 motor_vehicle: 'yes',
37950 motor_vehicle: 'yes',
37956 motor_vehicle: 'yes',
37962 motor_vehicle: 'yes',
37968 motor_vehicle: 'yes',
37974 motor_vehicle: 'yes',
37979 motor_vehicle: 'yes'
37983 motor_vehicle: 'yes',
37989 motor_vehicle: 'yes',
37995 motor_vehicle: 'yes',
38001 access.tags = function(tags) {
38002 items.selectAll('.preset-input-access')
38003 .value(function(d) { return tags[d] || ''; })
38004 .attr('placeholder', function() {
38005 return tags.access ? tags.access : field.placeholder();
38008 // items.selectAll('#preset-input-access-access')
38009 // .attr('placeholder', 'yes');
38011 _.forEach(placeholders[tags.highway], function(v, k) {
38012 items.selectAll('#preset-input-access-' + k)
38013 .attr('placeholder', function() { return (tags.access || v); });
38017 access.focus = function() {
38018 items.selectAll('.preset-input-access')
38022 return d3.rebind(access, dispatch, 'on');
38024 iD.ui.preset.address = function(field, context) {
38025 var dispatch = d3.dispatch('init', 'change'),
38038 function getStreets() {
38039 var extent = entity.extent(context.graph()),
38040 l = extent.center(),
38041 box = iD.geo.Extent(l).padByMeters(200);
38043 return context.intersects(box)
38044 .filter(isAddressable)
38046 var loc = context.projection([
38047 (extent[0][0] + extent[1][0]) / 2,
38048 (extent[0][1] + extent[1][1]) / 2]),
38049 choice = iD.geo.chooseEdge(context.childNodes(d), loc, context.projection);
38051 title: d.tags.name,
38052 value: d.tags.name,
38053 dist: choice.distance
38055 }).sort(function(a, b) {
38056 return a.dist - b.dist;
38059 function isAddressable(d) {
38060 return d.tags.highway && d.tags.name && d.type === 'way';
38064 function getCities() {
38065 var extent = entity.extent(context.graph()),
38066 l = extent.center(),
38067 box = iD.geo.Extent(l).padByMeters(200);
38069 return context.intersects(box)
38070 .filter(isAddressable)
38073 title: d.tags['addr:city'] || d.tags.name,
38074 value: d.tags['addr:city'] || d.tags.name,
38075 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
38077 }).sort(function(a, b) {
38078 return a.dist - b.dist;
38081 function isAddressable(d) {
38083 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
38086 if (d.tags.place && d.tags.name && (
38087 d.tags.place === 'city' ||
38088 d.tags.place === 'town' ||
38089 d.tags.place === 'village'))
38092 if (d.tags['addr:city']) return true;
38098 function getPostCodes() {
38099 var extent = entity.extent(context.graph()),
38100 l = extent.center(),
38101 box = iD.geo.Extent(l).padByMeters(200);
38103 return context.intersects(box)
38104 .filter(isAddressable)
38107 title: d.tags['addr:postcode'],
38108 value: d.tags['addr:postcode'],
38109 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
38111 }).sort(function(a, b) {
38112 return a.dist - b.dist;
38115 function isAddressable(d) {
38116 return d.tags['addr:postcode'];
38120 function address(selection) {
38121 isInitialized = false;
38123 wrap = selection.selectAll('.preset-input-wrap')
38130 .attr('class', 'preset-input-wrap');
38132 var center = entity.extent(context.graph()).center(),
38135 iD.services.nominatim().countryCode(center, function (err, countryCode) {
38136 addressFormat = _.find(iD.data.addressFormats, function (a) {
38137 return a && a.countryCodes && _.contains(a.countryCodes, countryCode);
38138 }) || _.first(iD.data.addressFormats);
38141 // Normalize widths.
38142 var total = _.reduce(r, function(sum, field) {
38143 return sum + (widths[field] || 0.5);
38146 return r.map(function (field) {
38149 width: (widths[field] || 0.5) / total
38154 wrap.selectAll('div')
38155 .data(addressFormat.format)
38158 .attr('class', 'addr-row')
38159 .selectAll('input')
38163 .property('type', 'text')
38164 .attr('placeholder', function (d) { return field.t('placeholders.' + d.id); })
38165 .attr('class', function (d) { return 'addr-' + d.id; })
38166 .style('width', function (d) { return d.width * 100 + '%'; });
38170 wrap.selectAll('.addr-street')
38171 .call(d3.combobox()
38172 .fetcher(function(value, callback) {
38173 callback(getStreets());
38176 wrap.selectAll('.addr-city')
38177 .call(d3.combobox()
38178 .fetcher(function(value, callback) {
38179 callback(getCities());
38182 wrap.selectAll('.addr-postcode')
38183 .call(d3.combobox()
38184 .fetcher(function(value, callback) {
38185 callback(getPostCodes());
38188 wrap.selectAll('input')
38189 .on('blur', change())
38190 .on('change', change());
38192 wrap.selectAll('input:not(.combobox-input)')
38193 .on('input', change(true));
38196 isInitialized = true;
38200 function change(onInput) {
38201 return function() {
38204 wrap.selectAll('input')
38205 .each(function (field) {
38206 tags['addr:' + field.id] = this.value || undefined;
38209 dispatch.change(tags, onInput);
38213 function updateTags(tags) {
38214 wrap.selectAll('input')
38215 .value(function (field) {
38216 return tags['addr:' + field.id] || '';
38220 address.entity = function(_) {
38221 if (!arguments.length) return entity;
38226 address.tags = function(tags) {
38227 if (isInitialized) {
38230 dispatch.on('init', function () {
38236 address.focus = function() {
38237 var node = wrap.selectAll('input').node();
38238 if (node) node.focus();
38241 return d3.rebind(address, dispatch, 'on');
38243 iD.ui.preset.check =
38244 iD.ui.preset.defaultcheck = function(field) {
38245 var dispatch = d3.dispatch('change'),
38246 options = field.strings && field.strings.options,
38249 entity, value, box, text, label;
38252 for (var k in options) {
38253 values.push(k === 'undefined' ? undefined : k);
38254 texts.push(field.t('options.' + k, { 'default': options[k] }));
38257 values = [undefined, 'yes'];
38258 texts = [t('inspector.unknown'), t('inspector.check.yes')];
38259 if (field.type === 'check') {
38261 texts.push(t('inspector.check.no'));
38265 var check = function(selection) {
38266 // hack: pretend oneway field is a oneway_yes field
38267 // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
38268 if (field.id === 'oneway') {
38269 for (var key in entity.tags) {
38270 if (key in iD.oneWayTags && (entity.tags[key] in iD.oneWayTags[key])) {
38271 texts[0] = t('presets.fields.oneway_yes.options.undefined');
38277 selection.classed('checkselect', 'true');
38279 label = selection.selectAll('.preset-input-wrap')
38282 var enter = label.enter().append('label')
38283 .attr('class', 'preset-input-wrap');
38285 enter.append('input')
38286 .property('indeterminate', field.type === 'check')
38287 .attr('type', 'checkbox')
38288 .attr('id', 'preset-input-' + field.id);
38290 enter.append('span')
38292 .attr('class', 'value');
38294 box = label.select('input')
38295 .on('click', function() {
38297 t[field.key] = values[(values.indexOf(value) + 1) % values.length];
38298 dispatch.change(t);
38299 d3.event.stopPropagation();
38302 text = label.select('span.value');
38305 check.entity = function(_) {
38306 if (!arguments.length) return entity;
38311 check.tags = function(tags) {
38312 value = tags[field.key];
38313 box.property('indeterminate', field.type === 'check' && !value);
38314 box.property('checked', value === 'yes');
38315 text.text(texts[values.indexOf(value)]);
38316 label.classed('set', !!value);
38319 check.focus = function() {
38320 box.node().focus();
38323 return d3.rebind(check, dispatch, 'on');
38325 iD.ui.preset.combo =
38326 iD.ui.preset.typeCombo = function(field, context) {
38327 var dispatch = d3.dispatch('change'),
38328 optstrings = field.strings && field.strings.options,
38329 optarray = field.options,
38330 snake_case = (field.snake_case || (field.snake_case === undefined)),
38334 function snake(s) {
38335 return s.replace(/\s+/g, '_');
38338 function unsnake(s) {
38339 return s.replace(/_+/g, ' ');
38342 function clean(s) {
38343 return s.split(';')
38344 .map(function(s) { return s.trim(); })
38348 function optString() {
38349 return _.find(_.keys(strings), function(k) {
38350 return strings[k] === input.value();
38354 function combo(selection) {
38355 var combobox = d3.combobox();
38357 input = selection.selectAll('input')
38360 var enter = input.enter()
38362 .attr('type', 'text')
38363 .attr('id', 'preset-input-' + field.id);
38365 if (optstrings) { enter.attr('readonly', 'readonly'); }
38369 .on('change', change)
38370 .on('blur', change)
38373 _.each(optstrings, function(v, k) {
38374 strings[k] = field.t('options.' + k, { 'default': v });
38377 } else if (optarray) {
38378 _.each(optarray, function(k) {
38379 strings[k] = (snake_case ? unsnake(k) : k);
38382 } else if (context.taginfo()) {
38383 context.taginfo().values({key: field.key}, function(err, data) {
38385 _.each(_.pluck(data, 'value'), function(k) {
38386 strings[k] = (snake_case ? unsnake(k) : k);
38394 function stringsLoaded() {
38395 var keys = _.keys(strings),
38399 combobox.data(keys.map(function(k) {
38400 var s = strings[k],
38402 o.title = o.value = s;
38403 if (s.length < 20) { strs.push(s); }
38407 placeholders = strs.length > 1 ? strs : keys;
38408 input.attr('placeholder', field.placeholder() ||
38409 (placeholders.slice(0, 3).join(', ') + '...'));
38413 function change() {
38414 var value = optString() || clean(input.value());
38417 value = snake(value);
38419 if (field.type === 'typeCombo' && !value) {
38424 t[field.key] = value || undefined;
38425 dispatch.change(t);
38428 combo.tags = function(tags) {
38429 var key = tags[field.key],
38430 optstring = optString(),
38431 value = strings[key] || key || '';
38433 if (field.type === 'typeCombo' && value.toLowerCase() === 'yes') {
38436 if (!optstring && snake_case) {
38437 value = unsnake(value);
38439 input.value(value);
38442 combo.focus = function() {
38443 input.node().focus();
38446 return d3.rebind(combo, dispatch, 'on');
38448 iD.ui.preset.cycleway = function(field) {
38449 var dispatch = d3.dispatch('change'),
38452 function cycleway(selection) {
38453 var wrap = selection.selectAll('.preset-input-wrap')
38456 wrap.enter().append('div')
38457 .attr('class', 'cf preset-input-wrap')
38460 items = wrap.select('ul').selectAll('li')
38465 var enter = items.enter().append('li')
38466 .attr('class', function(d) { return 'cf preset-cycleway-' + d; });
38468 enter.append('span')
38469 .attr('class', 'col6 label preset-label-cycleway')
38470 .attr('for', function(d) { return 'preset-input-cycleway-' + d; })
38471 .text(function(d) { return field.t('types.' + d); });
38473 enter.append('div')
38474 .attr('class', 'col6 preset-input-cycleway-wrap')
38476 .attr('type', 'text')
38477 .attr('class', 'preset-input-cycleway')
38478 .attr('id', function(d) { return 'preset-input-cycleway-' + d; })
38479 .each(function(d) {
38481 .call(d3.combobox()
38482 .data(cycleway.options(d)));
38487 wrap.selectAll('.preset-input-cycleway')
38488 .on('change', change)
38489 .on('blur', change);
38492 function change() {
38493 var inputs = d3.selectAll('.preset-input-cycleway')[0],
38494 left = d3.select(inputs[0]).value(),
38495 right = d3.select(inputs[1]).value(),
38497 if (left === 'none' || left === '') { left = undefined; }
38498 if (right === 'none' || right === '') { right = undefined; }
38500 // Always set both left and right as changing one can affect the other
38502 cycleway: undefined,
38503 'cycleway:left': left,
38504 'cycleway:right': right
38507 // If the left and right tags match, use the cycleway tag to tag both
38508 // sides the same way
38509 if (left === right) {
38512 'cycleway:left': undefined,
38513 'cycleway:right': undefined
38517 dispatch.change(tag);
38520 cycleway.options = function() {
38521 return d3.keys(field.strings.options).map(function(option) {
38523 title: field.t('options.' + option + '.description'),
38529 cycleway.tags = function(tags) {
38530 items.selectAll('.preset-input-cycleway')
38531 .value(function(d) {
38532 // If cycleway is set, always return that
38533 if (tags.cycleway) {
38534 return tags.cycleway;
38536 return tags[d] || '';
38538 .attr('placeholder', field.placeholder());
38541 cycleway.focus = function() {
38542 items.selectAll('.preset-input-cycleway')
38546 return d3.rebind(cycleway, dispatch, 'on');
38548 iD.ui.preset.text =
38549 iD.ui.preset.number =
38551 iD.ui.preset.email =
38552 iD.ui.preset.url = function(field) {
38554 var dispatch = d3.dispatch('change'),
38557 function i(selection) {
38558 input = selection.selectAll('input')
38561 input.enter().append('input')
38562 .attr('type', field.type)
38563 .attr('id', 'preset-input-' + field.id)
38564 .attr('placeholder', field.placeholder() || t('inspector.unknown'));
38567 .on('input', change(true))
38568 .on('blur', change())
38569 .on('change', change());
38571 if (field.type === 'number') {
38572 input.attr('type', 'text');
38574 var spinControl = selection.selectAll('.spin-control')
38577 var enter = spinControl.enter().append('div')
38578 .attr('class', 'spin-control');
38580 enter.append('button')
38582 .attr('class', 'increment');
38584 enter.append('button')
38586 .attr('class', 'decrement');
38588 spinControl.selectAll('button')
38589 .on('click', function(d) {
38590 d3.event.preventDefault();
38591 var num = parseInt(input.node().value || 0, 10);
38592 if (!isNaN(num)) input.node().value = num + d;
38598 function change(onInput) {
38599 return function() {
38601 t[field.key] = input.value() || undefined;
38602 dispatch.change(t, onInput);
38606 i.tags = function(tags) {
38607 input.value(tags[field.key] || '');
38610 i.focus = function() {
38611 input.node().focus();
38614 return d3.rebind(i, dispatch, 'on');
38616 iD.ui.preset.localized = function(field, context) {
38617 var dispatch = d3.dispatch('change', 'input'),
38618 wikipedia = iD.services.wikipedia(),
38619 input, localizedInputs, wikiTitles,
38622 function i(selection) {
38623 input = selection.selectAll('.localized-main')
38626 input.enter().append('input')
38627 .attr('type', 'text')
38628 .attr('id', 'preset-input-' + field.id)
38629 .attr('class', 'localized-main')
38630 .attr('placeholder', field.placeholder());
38632 if (field.id === 'name') {
38633 var preset = context.presets().match(entity, context.graph());
38634 input.call(d3.combobox().fetcher(
38635 iD.util.SuggestNames(preset, iD.data.suggestions)
38640 .on('input', change(true))
38641 .on('blur', change())
38642 .on('change', change());
38644 var translateButton = selection.selectAll('.localized-add')
38647 translateButton.enter()
38649 .attr('class', 'button-input-action localized-add minor')
38650 .call(iD.svg.Icon('#icon-plus'))
38651 .call(bootstrap.tooltip()
38652 .title(t('translate.translate'))
38653 .placement('left'));
38656 .on('click', addNew);
38658 localizedInputs = selection.selectAll('.localized-wrap')
38661 localizedInputs.enter().append('div')
38662 .attr('class', 'localized-wrap');
38665 function addNew() {
38666 d3.event.preventDefault();
38667 var data = localizedInputs.selectAll('div.entry').data();
38668 var defaultLang = iD.detect().locale.toLowerCase().split('-')[0];
38669 var langExists = _.find(data, function(datum) { return datum.lang === defaultLang;});
38670 var isLangEn = defaultLang.indexOf('en') > -1;
38671 if (isLangEn || langExists) {
38674 data.push({ lang: defaultLang, value: '' });
38675 localizedInputs.call(render, data);
38678 function change(onInput) {
38679 return function() {
38681 t[field.key] = d3.select(this).value() || undefined;
38682 dispatch.change(t, onInput);
38686 function key(lang) { return field.key + ':' + lang; }
38688 function changeLang(d) {
38689 var lang = d3.select(this).value(),
38691 language = _.find(iD.data.wikipedia, function(d) {
38692 return d[0].toLowerCase() === lang.toLowerCase() ||
38693 d[1].toLowerCase() === lang.toLowerCase();
38696 if (language) lang = language[2];
38698 if (d.lang && d.lang !== lang) {
38699 t[key(d.lang)] = undefined;
38702 var value = d3.select(this.parentNode)
38703 .selectAll('.localized-value')
38706 if (lang && value) {
38707 t[key(lang)] = value;
38708 } else if (lang && wikiTitles && wikiTitles[d.lang]) {
38709 t[key(lang)] = wikiTitles[d.lang];
38713 dispatch.change(t);
38716 function changeValue(d) {
38717 if (!d.lang) return;
38719 t[key(d.lang)] = d3.select(this).value() || undefined;
38720 dispatch.change(t);
38723 function fetcher(value, cb) {
38724 var v = value.toLowerCase();
38726 cb(iD.data.wikipedia.filter(function(d) {
38727 return d[0].toLowerCase().indexOf(v) >= 0 ||
38728 d[1].toLowerCase().indexOf(v) >= 0 ||
38729 d[2].toLowerCase().indexOf(v) >= 0;
38730 }).map(function(d) {
38731 return { value: d[1] };
38735 function render(selection, data) {
38736 var wraps = selection.selectAll('div.entry').
38737 data(data, function(d) { return d.lang; });
38739 var innerWrap = wraps.enter()
38740 .insert('div', ':first-child');
38742 innerWrap.attr('class', 'entry')
38744 var wrap = d3.select(this);
38745 var langcombo = d3.combobox().fetcher(fetcher);
38747 var label = wrap.append('label')
38748 .attr('class','form-label')
38749 .text(t('translate.localized_translation_label'))
38750 .attr('for','localized-lang');
38752 label.append('button')
38753 .attr('class', 'minor remove')
38754 .on('click', function(d){
38755 d3.event.preventDefault();
38757 t[key(d.lang)] = undefined;
38758 dispatch.change(t);
38759 d3.select(this.parentNode.parentNode)
38761 .style('max-height','240px')
38763 .style('opacity', '0')
38764 .style('max-height','0px')
38767 .call(iD.svg.Icon('#operation-delete'));
38769 wrap.append('input')
38770 .attr('class', 'localized-lang')
38771 .attr('type', 'text')
38772 .attr('placeholder',t('translate.localized_translation_language'))
38773 .on('blur', changeLang)
38774 .on('change', changeLang)
38777 wrap.append('input')
38778 .on('blur', changeValue)
38779 .on('change', changeValue)
38780 .attr('type', 'text')
38781 .attr('placeholder', t('translate.localized_translation_name'))
38782 .attr('class', 'localized-value');
38786 .style('margin-top', '0px')
38787 .style('max-height', '0px')
38788 .style('opacity', '0')
38791 .style('margin-top', '10px')
38792 .style('max-height', '240px')
38793 .style('opacity', '1')
38794 .each('end', function() {
38796 .style('max-height', '')
38797 .style('overflow', 'visible');
38803 .style('max-height','0px')
38804 .style('opacity', '0')
38805 .style('top','-10px')
38808 var entry = selection.selectAll('.entry');
38810 entry.select('.localized-lang')
38811 .value(function(d) {
38812 var lang = _.find(iD.data.wikipedia, function(lang) { return lang[2] === d.lang; });
38813 return lang ? lang[1] : d.lang;
38816 entry.select('.localized-value')
38817 .value(function(d) { return d.value; });
38820 i.tags = function(tags) {
38821 // Fetch translations from wikipedia
38822 if (tags.wikipedia && !wikiTitles) {
38824 var wm = tags.wikipedia.match(/([^:]+):(.+)/);
38825 if (wm && wm[0] && wm[1]) {
38826 wikipedia.translations(wm[1], wm[2], function(d) {
38832 input.value(tags[field.key] || '');
38834 var postfixed = [], k, m;
38836 m = k.match(/^(.*):([a-zA-Z_-]+)$/);
38837 if (m && m[1] === field.key && m[2]) {
38838 postfixed.push({ lang: m[2], value: tags[k] });
38842 localizedInputs.call(render, postfixed.reverse());
38845 i.focus = function() {
38846 input.node().focus();
38849 i.entity = function(_) {
38853 return d3.rebind(i, dispatch, 'on');
38855 iD.ui.preset.maxspeed = function(field, context) {
38856 var dispatch = d3.dispatch('change'),
38863 var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
38864 imperialValues = [20, 25, 30, 35, 40, 45, 50, 55, 65, 70];
38866 function maxspeed(selection) {
38867 combobox = d3.combobox();
38868 var unitCombobox = d3.combobox().data(['km/h', 'mph'].map(comboValues));
38870 input = selection.selectAll('#preset-input-' + field.id)
38873 input.enter().append('input')
38874 .attr('type', 'text')
38875 .attr('id', 'preset-input-' + field.id)
38876 .attr('placeholder', field.placeholder());
38880 .on('change', change)
38881 .on('blur', change);
38883 var childNodes = context.graph().childNodes(context.entity(entity.id)),
38884 loc = childNodes[~~(childNodes.length/2)].loc;
38886 imperial = _.any(iD.data.imperial.features, function(f) {
38887 return _.any(f.geometry.coordinates, function(d) {
38888 return iD.geo.pointInPolygon(loc, d[0]);
38892 unitInput = selection.selectAll('input.maxspeed-unit')
38895 unitInput.enter().append('input')
38896 .attr('type', 'text')
38897 .attr('class', 'maxspeed-unit');
38900 .on('blur', changeUnits)
38901 .on('change', changeUnits)
38902 .call(unitCombobox);
38904 function changeUnits() {
38905 imperial = unitInput.value() === 'mph';
38906 unitInput.value(imperial ? 'mph' : 'km/h');
38913 function setSuggestions() {
38914 combobox.data((imperial ? imperialValues : metricValues).map(comboValues));
38915 unitInput.value(imperial ? 'mph' : 'km/h');
38918 function comboValues(d) {
38920 value: d.toString(),
38921 title: d.toString()
38925 function change() {
38927 value = input.value();
38930 tag[field.key] = undefined;
38931 } else if (isNaN(value) || !imperial) {
38932 tag[field.key] = value;
38934 tag[field.key] = value + ' mph';
38937 dispatch.change(tag);
38940 maxspeed.tags = function(tags) {
38941 var value = tags[field.key];
38943 if (value && value.indexOf('mph') >= 0) {
38944 value = parseInt(value, 10);
38946 } else if (value) {
38952 input.value(value || '');
38955 maxspeed.focus = function() {
38956 input.node().focus();
38959 maxspeed.entity = function(_) {
38963 return d3.rebind(maxspeed, dispatch, 'on');
38965 iD.ui.preset.radio = function(field) {
38966 var dispatch = d3.dispatch('change'),
38967 labels, radios, placeholder;
38969 function radio(selection) {
38970 selection.classed('preset-radio', true);
38972 var wrap = selection.selectAll('.preset-input-wrap')
38975 var buttonWrap = wrap.enter().append('div')
38976 .attr('class', 'preset-input-wrap toggle-list');
38978 buttonWrap.append('span')
38979 .attr('class', 'placeholder');
38981 placeholder = selection.selectAll('.placeholder');
38983 labels = wrap.selectAll('label')
38984 .data(field.options || field.keys);
38986 var enter = labels.enter().append('label');
38988 enter.append('input')
38989 .attr('type', 'radio')
38990 .attr('name', field.id)
38991 .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
38992 .attr('checked', false);
38994 enter.append('span')
38995 .text(function(d) { return field.t('options.' + d, { 'default': d }); });
38997 radios = labels.selectAll('input')
38998 .on('change', change);
39001 function change() {
39003 if (field.key) t[field.key] = undefined;
39004 radios.each(function(d) {
39005 var active = d3.select(this).property('checked');
39007 if (active) t[field.key] = d;
39009 t[d] = active ? 'yes' : undefined;
39012 dispatch.change(t);
39015 radio.tags = function(tags) {
39016 function checked(d) {
39018 return tags[field.key] === d;
39020 return !!(tags[d] && tags[d] !== 'no');
39024 labels.classed('active', checked);
39025 radios.property('checked', checked);
39026 var selection = radios.filter(function() { return this.checked; });
39027 if (selection.empty()) {
39028 placeholder.text(t('inspector.none'));
39030 placeholder.text(selection.attr('value'));
39034 radio.focus = function() {
39035 radios.node().focus();
39038 return d3.rebind(radio, dispatch, 'on');
39040 iD.ui.preset.restrictions = function(field, context) {
39041 var dispatch = d3.dispatch('change'),
39042 hover = iD.behavior.Hover(context),
39047 function restrictions(selection) {
39048 // if form field is hidden or has detached from dom, clean up.
39049 if (!d3.select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
39050 selection.call(restrictions.off);
39054 var wrap = selection.selectAll('.preset-input-wrap')
39057 var enter = wrap.enter()
39059 .attr('class', 'preset-input-wrap');
39063 .attr('class', 'restriction-help');
39066 var intersection = iD.geo.Intersection(context.graph(), vertexID),
39067 graph = intersection.graph,
39068 vertex = graph.entity(vertexID),
39069 filter = d3.functor(true),
39070 extent = iD.geo.Extent(),
39071 projection = iD.geo.RawMercator();
39073 var d = wrap.dimensions(),
39074 c = [d[0] / 2, d[1] / 2],
39078 .scale(256 * Math.pow(2, z) / (2 * Math.PI));
39080 var s = projection(vertex.loc);
39083 .translate([c[0] - s[0], c[1] - s[1]])
39084 .clipExtent([[0, 0], d]);
39086 var drawLayers = iD.svg.Layers(projection, context).only('osm').dimensions(d),
39087 drawVertices = iD.svg.Vertices(projection, context),
39088 drawLines = iD.svg.Lines(projection, context),
39089 drawTurns = iD.svg.Turns(projection, context);
39093 .selectAll('.surface')
39097 var surface = wrap.selectAll('.surface');
39101 .call(drawVertices, graph, [vertex], filter, extent, z)
39102 .call(drawLines, graph, intersection.ways, filter)
39103 .call(drawTurns, graph, intersection.turns(fromNodeID));
39106 .on('click.restrictions', click)
39107 .on('mouseover.restrictions', mouseover)
39108 .on('mouseout.restrictions', mouseout);
39111 .selectAll('.selected')
39112 .classed('selected', false);
39116 .selectAll('.' + intersection.highways[fromNodeID].id)
39117 .classed('selected', true);
39123 .on('change.restrictions', render);
39126 .on('resize.restrictions', function() {
39127 wrap.dimensions(null);
39132 var datum = d3.event.target.__data__;
39133 if (datum instanceof iD.Entity) {
39134 fromNodeID = intersection.adjacentNodeId(datum.id);
39136 } else if (datum instanceof iD.geo.Turn) {
39137 if (datum.restriction) {
39139 iD.actions.UnrestrictTurn(datum, projection),
39140 t('operations.restriction.annotation.delete'));
39143 iD.actions.RestrictTurn(datum, projection),
39144 t('operations.restriction.annotation.create'));
39149 function mouseover() {
39150 var datum = d3.event.target.__data__;
39151 if (datum instanceof iD.geo.Turn) {
39152 var graph = context.graph(),
39153 presets = context.presets(),
39156 if (datum.restriction) {
39157 preset = presets.match(graph.entity(datum.restriction), graph);
39159 preset = presets.item('type/restriction/' +
39160 iD.geo.inferRestriction(
39168 wrap.selectAll('.restriction-help')
39169 .text(t('operations.restriction.help.' +
39170 (datum.restriction ? 'toggle_off' : 'toggle_on'),
39171 {restriction: preset.name()}));
39175 function mouseout() {
39176 wrap.selectAll('.restriction-help')
39177 .text(t('operations.restriction.help.' +
39178 (fromNodeID ? 'toggle' : 'select')));
39181 function render() {
39182 if (context.hasEntity(vertexID)) {
39183 restrictions(selection);
39188 restrictions.entity = function(_) {
39189 if (!vertexID || vertexID !== _.id) {
39195 restrictions.tags = function() {};
39196 restrictions.focus = function() {};
39198 restrictions.off = function(selection) {
39199 selection.selectAll('.surface')
39201 .on('click.restrictions', null)
39202 .on('mouseover.restrictions', null)
39203 .on('mouseout.restrictions', null);
39206 .on('change.restrictions', null);
39209 .on('resize.restrictions', null);
39212 return d3.rebind(restrictions, dispatch, 'on');
39214 iD.ui.preset.textarea = function(field) {
39215 var dispatch = d3.dispatch('change'),
39218 function i(selection) {
39219 input = selection.selectAll('textarea')
39222 input.enter().append('textarea')
39223 .attr('id', 'preset-input-' + field.id)
39224 .attr('placeholder', field.placeholder() || t('inspector.unknown'))
39225 .attr('maxlength', 255);
39228 .on('input', change(true))
39229 .on('blur', change())
39230 .on('change', change());
39233 function change(onInput) {
39234 return function() {
39236 t[field.key] = input.value() || undefined;
39237 dispatch.change(t, onInput);
39241 i.tags = function(tags) {
39242 input.value(tags[field.key] || '');
39245 i.focus = function() {
39246 input.node().focus();
39249 return d3.rebind(i, dispatch, 'on');
39251 iD.ui.preset.wikipedia = function(field, context) {
39252 var dispatch = d3.dispatch('change'),
39253 wikipedia = iD.services.wikipedia(),
39254 link, entity, lang, title;
39256 function i(selection) {
39257 var langcombo = d3.combobox()
39258 .fetcher(function(value, cb) {
39259 var v = value.toLowerCase();
39261 cb(iD.data.wikipedia.filter(function(d) {
39262 return d[0].toLowerCase().indexOf(v) >= 0 ||
39263 d[1].toLowerCase().indexOf(v) >= 0 ||
39264 d[2].toLowerCase().indexOf(v) >= 0;
39265 }).map(function(d) {
39266 return { value: d[1] };
39270 var titlecombo = d3.combobox()
39271 .fetcher(function(value, cb) {
39273 if (!value) value = context.entity(entity.id).tags.name || '';
39274 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
39276 searchfn(language()[2], value, function(query, data) {
39277 cb(data.map(function(d) {
39278 return { value: d };
39283 lang = selection.selectAll('input.wiki-lang')
39286 lang.enter().append('input')
39287 .attr('type', 'text')
39288 .attr('class', 'wiki-lang')
39293 .on('blur', changeLang)
39294 .on('change', changeLang);
39296 title = selection.selectAll('input.wiki-title')
39299 title.enter().append('input')
39300 .attr('type', 'text')
39301 .attr('class', 'wiki-title')
39302 .attr('id', 'preset-input-' + field.id);
39306 .on('blur', change)
39307 .on('change', change);
39309 link = selection.selectAll('a.wiki-link')
39312 link.enter().append('a')
39313 .attr('class', 'wiki-link button-input-action minor')
39314 .attr('target', '_blank')
39315 .call(iD.svg.Icon('#icon-out-link', 'inline'));
39318 function language() {
39319 var value = lang.value().toLowerCase();
39320 var locale = iD.detect().locale.toLowerCase();
39321 var localeLanguage;
39322 return _.find(iD.data.wikipedia, function(d) {
39323 if (d[2] === locale) localeLanguage = d;
39324 return d[0].toLowerCase() === value ||
39325 d[1].toLowerCase() === value ||
39327 }) || localeLanguage || ['English', 'English', 'en'];
39330 function changeLang() {
39331 lang.value(language()[1]);
39335 function change() {
39336 var value = title.value(),
39337 m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
39338 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
39342 // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
39343 value = decodeURIComponent(m[2]).replace(/_/g, ' ');
39346 // Best-effort `anchordecode:` implementation
39347 anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
39349 anchor = decodeURIComponent(m[3]);
39351 value += '#' + anchor.replace(/_/g, ' ');
39353 value = value.slice(0, 1).toUpperCase() + value.slice(1);
39355 title.value(value);
39359 t[field.key] = value ? language()[2] + ':' + value : undefined;
39360 dispatch.change(t);
39363 i.tags = function(tags) {
39364 var value = tags[field.key] || '',
39365 m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
39366 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
39367 anchor = m && m[3];
39369 // value in correct format
39372 title.value(m[2] + (anchor ? ('#' + anchor) : ''));
39375 // Best-effort `anchorencode:` implementation
39376 anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
39378 anchor = anchor.replace(/ /g, '_');
39381 link.attr('href', 'https://' + m[1] + '.wikipedia.org/wiki/' +
39382 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : ''));
39384 // unrecognized value format
39386 title.value(value);
39387 link.attr('href', 'https://en.wikipedia.org/wiki/Special:Search?search=' + value);
39391 i.entity = function(_) {
39395 i.focus = function() {
39396 title.node().focus();
39399 return d3.rebind(i, dispatch, 'on');
39401 iD.ui.intro.area = function(context, reveal) {
39402 var event = d3.dispatch('done'),
39406 title: 'intro.areas.title'
39409 step.enter = function() {
39410 var playground = [-85.63552, 41.94159],
39411 corner = [-85.63565411045074, 41.9417715536927];
39412 context.map().centerZoom(playground, 19);
39413 reveal('button.add-area',
39414 t('intro.areas.add', { button: iD.ui.intro.icon('#icon-area', 'pre-text') }),
39415 { tooltipClass: 'intro-areas-add' });
39417 context.on('enter.intro', addArea);
39419 function addArea(mode) {
39420 if (mode.id !== 'add-area') return;
39421 context.on('enter.intro', drawArea);
39423 var padding = 120 * Math.pow(2, context.map().zoom() - 19);
39424 var pointBox = iD.ui.intro.pad(corner, padding, context);
39425 reveal(pointBox, t('intro.areas.corner'));
39427 context.map().on('move.intro', function() {
39428 padding = 120 * Math.pow(2, context.map().zoom() - 19);
39429 pointBox = iD.ui.intro.pad(corner, padding, context);
39430 reveal(pointBox, t('intro.areas.corner'), {duration: 0});
39434 function drawArea(mode) {
39435 if (mode.id !== 'draw-area') return;
39436 context.on('enter.intro', enterSelect);
39438 var padding = 150 * Math.pow(2, context.map().zoom() - 19);
39439 var pointBox = iD.ui.intro.pad(playground, padding, context);
39440 reveal(pointBox, t('intro.areas.place'));
39442 context.map().on('move.intro', function() {
39443 padding = 150 * Math.pow(2, context.map().zoom() - 19);
39444 pointBox = iD.ui.intro.pad(playground, padding, context);
39445 reveal(pointBox, t('intro.areas.place'), {duration: 0});
39449 function enterSelect(mode) {
39450 if (mode.id !== 'select') return;
39451 context.map().on('move.intro', null);
39452 context.on('enter.intro', null);
39454 timeout = setTimeout(function() {
39455 reveal('.preset-search-input',
39456 t('intro.areas.search',
39457 { name: context.presets().item('leisure/playground').name() }));
39458 d3.select('.preset-search-input').on('keyup.intro', keySearch);
39462 function keySearch() {
39463 var first = d3.select('.preset-list-item:first-child');
39464 if (first.classed('preset-leisure-playground')) {
39465 reveal(first.select('.preset-list-button').node(), t('intro.areas.choose'));
39466 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
39467 d3.select('.preset-search-input').on('keyup.intro', null);
39471 function selectedPreset() {
39473 t('intro.areas.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39474 context.on('exit.intro', event.done);
39478 step.exit = function() {
39479 window.clearTimeout(timeout);
39480 context.on('enter.intro', null);
39481 context.on('exit.intro', null);
39482 context.history().on('change.intro', null);
39483 context.map().on('move.intro', null);
39484 d3.select('.preset-search-input').on('keyup.intro', null);
39487 return d3.rebind(step, event, 'on');
39489 iD.ui.intro.line = function(context, reveal) {
39490 var event = d3.dispatch('done'),
39494 title: 'intro.lines.title'
39497 function timeout(f, t) {
39498 timeouts.push(window.setTimeout(f, t));
39501 function eventCancel() {
39502 d3.event.stopPropagation();
39503 d3.event.preventDefault();
39506 step.enter = function() {
39507 var centroid = [-85.62830, 41.95699];
39508 var midpoint = [-85.62975395449628, 41.95787501510204];
39509 var start = [-85.6297754121684, 41.95805253325314];
39510 var intersection = [-85.62974496187628, 41.95742515554585];
39512 context.map().centerZoom(start, 18);
39513 reveal('button.add-line',
39514 t('intro.lines.add', { button: iD.ui.intro.icon('#icon-line', 'pre-text') }),
39515 { tooltipClass: 'intro-lines-add' });
39517 context.on('enter.intro', addLine);
39519 function addLine(mode) {
39520 if (mode.id !== 'add-line') return;
39521 context.on('enter.intro', drawLine);
39523 var padding = 150 * Math.pow(2, context.map().zoom() - 18);
39524 var pointBox = iD.ui.intro.pad(start, padding, context);
39525 reveal(pointBox, t('intro.lines.start'));
39527 context.map().on('move.intro', function() {
39528 padding = 150 * Math.pow(2, context.map().zoom() - 18);
39529 pointBox = iD.ui.intro.pad(start, padding, context);
39530 reveal(pointBox, t('intro.lines.start'), {duration: 0});
39534 function drawLine(mode) {
39535 if (mode.id !== 'draw-line') return;
39536 context.history().on('change.intro', addIntersection);
39537 context.on('enter.intro', retry);
39539 var padding = 300 * Math.pow(2, context.map().zoom() - 19);
39540 var pointBox = iD.ui.intro.pad(midpoint, padding, context);
39541 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}));
39543 context.map().on('move.intro', function() {
39544 padding = 300 * Math.pow(2, context.map().zoom() - 19);
39545 pointBox = iD.ui.intro.pad(midpoint, padding, context);
39546 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}), {duration: 0});
39550 // ended line before creating intersection
39551 function retry(mode) {
39552 if (mode.id !== 'select') return;
39553 var pointBox = iD.ui.intro.pad(intersection, 30, context),
39554 ids = mode.selectedIDs();
39555 reveal(pointBox, t('intro.lines.restart', {name: t('intro.graph.flower_st')}));
39556 d3.select(window).on('mousedown.intro', eventCancel, true);
39558 timeout(function() {
39559 context.replace(iD.actions.DeleteMultiple(ids));
39565 function addIntersection(changes) {
39566 if ( _.any(changes.created(), function(d) {
39567 return d.type === 'node' && context.graph().parentWays(d).length > 1;
39569 context.history().on('change.intro', null);
39570 context.on('enter.intro', enterSelect);
39572 var padding = 900 * Math.pow(2, context.map().zoom() - 19);
39573 var pointBox = iD.ui.intro.pad(centroid, padding, context);
39574 reveal(pointBox, t('intro.lines.finish'));
39576 context.map().on('move.intro', function() {
39577 padding = 900 * Math.pow(2, context.map().zoom() - 19);
39578 pointBox = iD.ui.intro.pad(centroid, padding, context);
39579 reveal(pointBox, t('intro.lines.finish'), {duration: 0});
39584 function enterSelect(mode) {
39585 if (mode.id !== 'select') return;
39586 context.map().on('move.intro', null);
39587 context.on('enter.intro', null);
39588 d3.select('#curtain').style('pointer-events', 'all');
39593 function presetCategory() {
39594 timeout(function() {
39595 d3.select('#curtain').style('pointer-events', 'none');
39596 var road = d3.select('.preset-category-road .preset-list-button');
39597 reveal(road.node(), t('intro.lines.road'));
39598 road.one('click.intro', roadCategory);
39602 function roadCategory() {
39603 timeout(function() {
39604 var grid = d3.select('.subgrid');
39605 reveal(grid.node(), t('intro.lines.residential'));
39606 grid.selectAll(':not(.preset-highway-residential) .preset-list-button')
39607 .one('click.intro', retryPreset);
39608 grid.selectAll('.preset-highway-residential .preset-list-button')
39609 .one('click.intro', roadDetails);
39613 // selected wrong road type
39614 function retryPreset() {
39615 timeout(function() {
39616 var preset = d3.select('.entity-editor-pane .preset-list-button');
39617 reveal(preset.node(), t('intro.lines.wrong_preset'));
39618 preset.one('click.intro', presetCategory);
39622 function roadDetails() {
39624 t('intro.lines.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39625 context.on('exit.intro', event.done);
39630 step.exit = function() {
39631 d3.select(window).on('mousedown.intro', null, true);
39632 d3.select('#curtain').style('pointer-events', 'none');
39633 timeouts.forEach(window.clearTimeout);
39634 context.on('enter.intro', null);
39635 context.on('exit.intro', null);
39636 context.map().on('move.intro', null);
39637 context.history().on('change.intro', null);
39640 return d3.rebind(step, event, 'on');
39642 iD.ui.intro.navigation = function(context, reveal) {
39643 var event = d3.dispatch('done'),
39647 title: 'intro.navigation.title'
39650 function set(f, t) {
39651 timeouts.push(window.setTimeout(f, t));
39654 function eventCancel() {
39655 d3.event.stopPropagation();
39656 d3.event.preventDefault();
39659 step.enter = function() {
39660 var rect = context.surfaceRect(),
39662 left: rect.left + 10,
39663 top: rect.top + 70,
39664 width: rect.width - 70,
39665 height: rect.height - 170
39668 context.map().centerZoom([-85.63591, 41.94285], 19);
39670 reveal(map, t('intro.navigation.drag'));
39672 context.map().on('move.intro', _.debounce(function() {
39673 context.map().on('move.intro', null);
39675 context.on('enter.intro', inspectTownHall);
39678 function townhall() {
39679 var hall = [-85.63645945147184, 41.942986488012565];
39681 var point = context.projection(hall);
39682 if (point[0] < 0 || point[0] > rect.width ||
39683 point[1] < 0 || point[1] > rect.height) {
39684 context.map().center(hall);
39687 var box = iD.ui.intro.pointBox(hall, context);
39688 reveal(box, t('intro.navigation.select'));
39690 context.map().on('move.intro', function() {
39691 var box = iD.ui.intro.pointBox(hall, context);
39692 reveal(box, t('intro.navigation.select'), {duration: 0});
39696 function inspectTownHall(mode) {
39697 if (mode.id !== 'select') return;
39698 context.on('enter.intro', null);
39699 context.map().on('move.intro', null);
39701 reveal('.entity-editor-pane',
39702 t('intro.navigation.pane', { button: iD.ui.intro.icon('#icon-close', 'pre-text') }));
39703 context.on('exit.intro', streetSearch);
39707 function streetSearch() {
39708 context.on('exit.intro', null);
39709 reveal('.search-header input',
39710 t('intro.navigation.search', { name: t('intro.graph.spring_st') }));
39711 d3.select('.search-header input').on('keyup.intro', searchResult);
39714 function searchResult() {
39715 var first = d3.select('.feature-list-item:nth-child(0n+2)'), // skip No Results item
39716 firstName = first.select('.entity-name'),
39717 name = t('intro.graph.spring_st');
39719 if (!firstName.empty() && firstName.text() === name) {
39720 reveal(first.node(), t('intro.navigation.choose', { name: name }));
39721 context.on('exit.intro', selectedStreet);
39722 d3.select('.search-header input')
39723 .on('keydown.intro', eventCancel, true)
39724 .on('keyup.intro', null);
39728 function selectedStreet() {
39729 var springSt = [-85.63585099140167, 41.942506848938926];
39730 context.map().center(springSt);
39731 context.on('exit.intro', event.done);
39733 reveal('.entity-editor-pane',
39734 t('intro.navigation.chosen', {
39735 name: t('intro.graph.spring_st'),
39736 button: iD.ui.intro.icon('#icon-close', 'pre-text')
39742 step.exit = function() {
39743 timeouts.forEach(window.clearTimeout);
39744 context.map().on('move.intro', null);
39745 context.on('enter.intro', null);
39746 context.on('exit.intro', null);
39747 d3.select('.search-header input')
39748 .on('keydown.intro', null)
39749 .on('keyup.intro', null);
39752 return d3.rebind(step, event, 'on');
39754 iD.ui.intro.point = function(context, reveal) {
39755 var event = d3.dispatch('done'),
39759 title: 'intro.points.title'
39762 function setTimeout(f, t) {
39763 timeouts.push(window.setTimeout(f, t));
39766 function eventCancel() {
39767 d3.event.stopPropagation();
39768 d3.event.preventDefault();
39771 step.enter = function() {
39772 context.map().centerZoom([-85.63279, 41.94394], 19);
39773 reveal('button.add-point',
39774 t('intro.points.add', { button: iD.ui.intro.icon('#icon-point', 'pre-text') }),
39775 { tooltipClass: 'intro-points-add' });
39777 var corner = [-85.632481,41.944094];
39779 context.on('enter.intro', addPoint);
39781 function addPoint(mode) {
39782 if (mode.id !== 'add-point') return;
39783 context.on('enter.intro', enterSelect);
39785 var pointBox = iD.ui.intro.pad(corner, 150, context);
39786 reveal(pointBox, t('intro.points.place'));
39788 context.map().on('move.intro', function() {
39789 pointBox = iD.ui.intro.pad(corner, 150, context);
39790 reveal(pointBox, t('intro.points.place'), {duration: 0});
39794 function enterSelect(mode) {
39795 if (mode.id !== 'select') return;
39796 context.map().on('move.intro', null);
39797 context.on('enter.intro', null);
39799 setTimeout(function() {
39800 reveal('.preset-search-input',
39801 t('intro.points.search', {name: context.presets().item('amenity/cafe').name()}));
39802 d3.select('.preset-search-input').on('keyup.intro', keySearch);
39806 function keySearch() {
39807 var first = d3.select('.preset-list-item:first-child');
39808 if (first.classed('preset-amenity-cafe')) {
39809 reveal(first.select('.preset-list-button').node(), t('intro.points.choose'));
39810 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
39811 d3.select('.preset-search-input')
39812 .on('keydown.intro', eventCancel, true)
39813 .on('keyup.intro', null);
39817 function selectedPreset() {
39818 setTimeout(function() {
39819 reveal('.entity-editor-pane', t('intro.points.describe'), {tooltipClass: 'intro-points-describe'});
39820 context.history().on('change.intro', closeEditor);
39821 context.on('exit.intro', selectPoint);
39825 function closeEditor() {
39826 d3.select('.preset-search-input').on('keydown.intro', null);
39827 context.history().on('change.intro', null);
39828 reveal('.entity-editor-pane',
39829 t('intro.points.close', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39832 function selectPoint() {
39833 context.on('exit.intro', null);
39834 context.history().on('change.intro', null);
39835 context.on('enter.intro', enterReselect);
39837 var pointBox = iD.ui.intro.pad(corner, 150, context);
39838 reveal(pointBox, t('intro.points.reselect'));
39840 context.map().on('move.intro', function() {
39841 pointBox = iD.ui.intro.pad(corner, 150, context);
39842 reveal(pointBox, t('intro.points.reselect'), {duration: 0});
39846 function enterReselect(mode) {
39847 if (mode.id !== 'select') return;
39848 context.map().on('move.intro', null);
39849 context.on('enter.intro', null);
39851 setTimeout(function() {
39852 reveal('.entity-editor-pane',
39853 t('intro.points.fixname', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39854 context.on('exit.intro', deletePoint);
39858 function deletePoint() {
39859 context.on('exit.intro', null);
39860 context.on('enter.intro', enterDelete);
39862 var pointBox = iD.ui.intro.pad(corner, 150, context);
39863 reveal(pointBox, t('intro.points.reselect_delete'));
39865 context.map().on('move.intro', function() {
39866 pointBox = iD.ui.intro.pad(corner, 150, context);
39867 reveal(pointBox, t('intro.points.reselect_delete'), {duration: 0});
39871 function enterDelete(mode) {
39872 if (mode.id !== 'select') return;
39873 context.map().on('move.intro', null);
39874 context.on('enter.intro', null);
39875 context.on('exit.intro', deletePoint);
39876 context.map().on('move.intro', deletePoint);
39877 context.history().on('change.intro', deleted);
39879 setTimeout(function() {
39880 var node = d3.select('.radial-menu-item-delete').node();
39881 var pointBox = iD.ui.intro.pad(node.getBoundingClientRect(), 50, context);
39883 t('intro.points.delete', { button: iD.ui.intro.icon('#operation-delete', 'pre-text') }));
39887 function deleted(changed) {
39888 if (changed.deleted().length) event.done();
39893 step.exit = function() {
39894 timeouts.forEach(window.clearTimeout);
39895 context.on('exit.intro', null);
39896 context.on('enter.intro', null);
39897 context.map().on('move.intro', null);
39898 context.history().on('change.intro', null);
39899 d3.select('.preset-search-input')
39900 .on('keyup.intro', null)
39901 .on('keydown.intro', null);
39904 return d3.rebind(step, event, 'on');
39906 iD.ui.intro.startEditing = function(context, reveal) {
39907 var event = d3.dispatch('done', 'startEditing'),
39912 title: 'intro.startediting.title'
39915 function timeout(f, t) {
39916 timeouts.push(window.setTimeout(f, t));
39919 step.enter = function() {
39920 reveal('.map-control.help-control',
39921 t('intro.startediting.help', { button: iD.ui.intro.icon('#icon-help', 'pre-text') }));
39923 timeout(function() {
39924 reveal('#bar button.save', t('intro.startediting.save'));
39927 timeout(function() {
39928 reveal('#surface');
39931 timeout(function() {
39932 modal = iD.ui.modal(context.container());
39934 modal.select('.modal')
39935 .attr('class', 'modal-splash modal col6');
39937 modal.selectAll('.close').remove();
39939 var startbutton = modal.select('.content')
39940 .attr('class', 'fillL')
39942 .attr('class', 'modal-section huge-modal-button')
39943 .on('click', function() {
39947 startbutton.append('div')
39948 .attr('class','illustration');
39949 startbutton.append('h2')
39950 .text(t('intro.startediting.start'));
39952 event.startEditing();
39956 step.exit = function() {
39957 if (modal) modal.remove();
39958 timeouts.forEach(window.clearTimeout);
39961 return d3.rebind(step, event, 'on');
39963 iD.presets = function() {
39965 // an iD.presets.Collection with methods for
39966 // loading new data and returning defaults
39968 var all = iD.presets.Collection([]),
39969 defaults = { area: all, line: all, point: all, vertex: all, relation: all },
39972 recent = iD.presets.Collection([]);
39974 // Index of presets by (geometry, tag key).
39983 all.match = function(entity, resolver) {
39984 var geometry = entity.geometry(resolver),
39985 geometryMatches = index[geometry],
39989 for (var k in entity.tags) {
39990 var keyMatches = geometryMatches[k];
39991 if (!keyMatches) continue;
39993 for (var i = 0; i < keyMatches.length; i++) {
39994 var score = keyMatches[i].matchScore(entity);
39995 if (score > best) {
39997 match = keyMatches[i];
40002 return match || all.item(geometry);
40005 // Because of the open nature of tagging, iD will never have a complete
40006 // list of tags used in OSM, so we want it to have logic like "assume
40007 // that a closed way with an amenity tag is an area, unless the amenity
40008 // is one of these specific types". This function computes a structure
40009 // that allows testing of such conditions, based on the presets designated
40010 // as as supporting (or not supporting) the area geometry.
40012 // The returned object L is a whitelist/blacklist of tags. A closed way
40013 // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
40014 // (see `iD.Way#isArea()`). In other words, the keys of L form the whitelist,
40015 // and the subkeys form the blacklist.
40016 all.areaKeys = function() {
40018 ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],
40019 presets = _.reject(all.collection, 'suggestion');
40022 presets.forEach(function(d) {
40023 for (var key in d.tags) break;
40025 if (ignore.indexOf(key) !== -1) return;
40027 if (d.geometry.indexOf('area') !== -1) {
40028 areaKeys[key] = areaKeys[key] || {};
40033 presets.forEach(function(d) {
40034 for (var key in d.tags) break;
40036 if (ignore.indexOf(key) !== -1) return;
40038 var value = d.tags[key];
40039 if (d.geometry.indexOf('area') === -1 && key in areaKeys && value !== '*') {
40040 areaKeys[key][value] = true;
40047 all.load = function(d) {
40050 _.forEach(d.fields, function(d, id) {
40051 fields[id] = iD.presets.Field(id, d);
40052 if (d.universal) universal.push(fields[id]);
40057 _.forEach(d.presets, function(d, id) {
40058 all.collection.push(iD.presets.Preset(id, d, fields));
40062 if (d.categories) {
40063 _.forEach(d.categories, function(d, id) {
40064 all.collection.push(iD.presets.Category(id, d, all));
40069 var getItem = _.bind(all.item, all);
40071 area: iD.presets.Collection(d.defaults.area.map(getItem)),
40072 line: iD.presets.Collection(d.defaults.line.map(getItem)),
40073 point: iD.presets.Collection(d.defaults.point.map(getItem)),
40074 vertex: iD.presets.Collection(d.defaults.vertex.map(getItem)),
40075 relation: iD.presets.Collection(d.defaults.relation.map(getItem))
40079 for (var i = 0; i < all.collection.length; i++) {
40080 var preset = all.collection[i],
40081 geometry = preset.geometry;
40083 for (var j = 0; j < geometry.length; j++) {
40084 var g = index[geometry[j]];
40085 for (var k in preset.tags) {
40086 (g[k] = g[k] || []).push(preset);
40094 all.field = function(id) {
40098 all.universal = function() {
40102 all.defaults = function(geometry, n) {
40103 var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
40104 def = _.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
40105 return iD.presets.Collection(_.unique(rec.concat(def).concat(all.item(geometry))));
40108 all.choose = function(preset) {
40109 if (!preset.isFallback()) {
40110 recent = iD.presets.Collection(_.unique([preset].concat(recent.collection)));
40117 iD.presets.Category = function(id, category, all) {
40118 category = _.clone(category);
40122 category.members = iD.presets.Collection(category.members.map(function(id) {
40123 return all.item(id);
40126 category.matchGeometry = function(geometry) {
40127 return category.geometry.indexOf(geometry) >= 0;
40130 category.matchScore = function() { return -1; };
40132 category.name = function() {
40133 return t('presets.categories.' + id + '.name', {'default': id});
40136 category.terms = function() {
40142 iD.presets.Collection = function(collection) {
40144 var maxSearchResults = 50,
40145 maxSuggestionResults = 10;
40149 collection: collection,
40151 item: function(id) {
40152 return _.find(collection, function(d) {
40153 return d.id === id;
40157 matchGeometry: function(geometry) {
40158 return iD.presets.Collection(collection.filter(function(d) {
40159 return d.matchGeometry(geometry);
40163 search: function(value, geometry) {
40164 if (!value) return this;
40166 value = value.toLowerCase();
40168 var searchable = _.filter(collection, function(a) {
40169 return a.searchable !== false && a.suggestion !== true;
40171 suggestions = _.filter(collection, function(a) {
40172 return a.suggestion === true;
40175 function leading(a) {
40176 var index = a.indexOf(value);
40177 return index === 0 || a[index - 1] === ' ';
40180 // matches value to preset.name
40181 var leading_name = _.filter(searchable, function(a) {
40182 return leading(a.name().toLowerCase());
40183 }).sort(function(a, b) {
40184 var i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
40185 if (i === 0) return a.name().length - b.name().length;
40189 // matches value to preset.terms values
40190 var leading_terms = _.filter(searchable, function(a) {
40191 return _.any(a.terms() || [], leading);
40194 // matches value to preset.tags values
40195 var leading_tag_values = _.filter(searchable, function(a) {
40196 return _.any(_.without(_.values(a.tags || {}), '*'), leading);
40200 // finds close matches to value in preset.name
40201 var levenstein_name = searchable.map(function(a) {
40204 dist: iD.util.editDistance(value, a.name().toLowerCase())
40206 }).filter(function(a) {
40207 return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
40208 }).sort(function(a, b) {
40209 return a.dist - b.dist;
40210 }).map(function(a) {
40214 // finds close matches to value in preset.terms
40215 var leventstein_terms = _.filter(searchable, function(a) {
40216 return _.any(a.terms() || [], function(b) {
40217 return iD.util.editDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
40221 function suggestionName(name) {
40222 var nameArray = name.split(' - ');
40223 if (nameArray.length > 1) {
40224 name = nameArray.slice(0, nameArray.length-1).join(' - ');
40226 return name.toLowerCase();
40229 var leading_suggestions = _.filter(suggestions, function(a) {
40230 return leading(suggestionName(a.name()));
40231 }).sort(function(a, b) {
40232 a = suggestionName(a.name());
40233 b = suggestionName(b.name());
40234 var i = a.indexOf(value) - b.indexOf(value);
40235 if (i === 0) return a.length - b.length;
40239 var leven_suggestions = suggestions.map(function(a) {
40242 dist: iD.util.editDistance(value, suggestionName(a.name()))
40244 }).filter(function(a) {
40245 return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
40246 }).sort(function(a, b) {
40247 return a.dist - b.dist;
40248 }).map(function(a) {
40252 var other = presets.item(geometry);
40254 var results = leading_name.concat(
40256 leading_tag_values,
40257 leading_suggestions.slice(0, maxSuggestionResults+5),
40260 leven_suggestions.slice(0, maxSuggestionResults)
40261 ).slice(0, maxSearchResults-1);
40263 return iD.presets.Collection(_.unique(
40264 results.concat(other)
40271 iD.presets.Field = function(id, field) {
40272 field = _.clone(field);
40276 field.matchGeometry = function(geometry) {
40277 return !field.geometry || field.geometry === geometry;
40280 field.t = function(scope, options) {
40281 return t('presets.fields.' + id + '.' + scope, options);
40284 field.label = function() {
40285 return field.t('label', {'default': id});
40288 var placeholder = field.placeholder;
40289 field.placeholder = function() {
40290 return field.t('placeholder', {'default': placeholder});
40295 iD.presets.Preset = function(id, preset, fields) {
40296 preset = _.clone(preset);
40299 preset.fields = (preset.fields || []).map(getFields);
40300 preset.geometry = (preset.geometry || []);
40302 function getFields(f) {
40306 preset.matchGeometry = function(geometry) {
40307 return preset.geometry.indexOf(geometry) >= 0;
40310 var matchScore = preset.matchScore || 1;
40311 preset.matchScore = function(entity) {
40312 var tags = preset.tags,
40315 for (var t in tags) {
40316 if (entity.tags[t] === tags[t]) {
40317 score += matchScore;
40318 } else if (tags[t] === '*' && t in entity.tags) {
40319 score += matchScore / 2;
40328 preset.t = function(scope, options) {
40329 return t('presets.presets.' + id + '.' + scope, options);
40332 var name = preset.name;
40333 preset.name = function() {
40334 if (preset.suggestion) {
40335 id = id.split('/');
40336 id = id[0] + '/' + id[1];
40337 return name + ' - ' + t('presets.presets.' + id + '.name');
40339 return preset.t('name', {'default': name});
40342 preset.terms = function() {
40343 return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
40346 preset.isFallback = function() {
40347 var tagCount = Object.keys(preset.tags).length;
40348 return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
40351 preset.reference = function(geometry) {
40352 var key = Object.keys(preset.tags)[0],
40353 value = preset.tags[key];
40355 if (geometry === 'relation' && key === 'type') {
40356 return { rtype: value };
40357 } else if (value === '*') {
40358 return { key: key };
40360 return { key: key, value: value };
40364 var removeTags = preset.removeTags || preset.tags;
40365 preset.removeTags = function(tags, geometry) {
40366 tags = _.omit(tags, _.keys(removeTags));
40368 for (var f in preset.fields) {
40369 var field = preset.fields[f];
40370 if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
40371 delete tags[field.key];
40379 var applyTags = preset.addTags || preset.tags;
40380 preset.applyTags = function(tags, geometry) {
40383 tags = _.clone(tags);
40385 for (k in applyTags) {
40386 if (applyTags[k] === '*') {
40389 tags[k] = applyTags[k];
40393 // Add area=yes if necessary.
40394 // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
40395 // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
40396 // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
40397 if (geometry === 'area') {
40398 var needsAreaTag = true;
40399 if (preset.geometry.indexOf('line') === -1) {
40400 for (k in applyTags) {
40401 if (k in iD.areaKeys) {
40402 needsAreaTag = false;
40407 if (needsAreaTag) {
40412 for (var f in preset.fields) {
40413 var field = preset.fields[f];
40414 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
40415 tags[field.key] = field.default;
40424 iD.validations = {};
40425 iD.validations.DeprecatedTag = function() {
40427 var validation = function(changes) {
40429 for (var i = 0; i < changes.created.length; i++) {
40430 var change = changes.created[i],
40431 deprecatedTags = change.deprecatedTags();
40433 if (!_.isEmpty(deprecatedTags)) {
40434 var tags = iD.util.tagText({ tags: deprecatedTags });
40436 id: 'deprecated_tags',
40437 message: t('validations.deprecated_tags', { tags: tags }),
40447 iD.validations.ManyDeletions = function() {
40448 var threshold = 100;
40450 var validation = function(changes) {
40452 if (changes.deleted.length > threshold) {
40454 id: 'many_deletions',
40455 message: t('validations.many_deletions', { n: changes.deleted.length })
40463 iD.validations.MissingTag = function() {
40465 var validation = function(changes, graph) {
40467 for (var i = 0; i < changes.created.length; i++) {
40468 var change = changes.created[i],
40469 geometry = change.geometry(graph);
40471 if ((geometry === 'point' || geometry === 'line' || geometry === 'area') && !change.isUsed(graph)) {
40474 message: t('validations.untagged_' + geometry),
40475 tooltip: t('validations.untagged_' + geometry + '_tooltip'),
40485 iD.validations.TagSuggestsArea = function() {
40487 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
40488 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
40489 function tagSuggestsArea(tags) {
40490 if (_.isEmpty(tags)) return false;
40492 var presence = ['landuse', 'amenities', 'tourism', 'shop'];
40493 for (var i = 0; i < presence.length; i++) {
40494 if (tags[presence[i]] !== undefined) {
40495 return presence[i] + '=' + tags[presence[i]];
40499 if (tags.building && tags.building === 'yes') return 'building=yes';
40502 var validation = function(changes, graph) {
40504 for (var i = 0; i < changes.created.length; i++) {
40505 var change = changes.created[i],
40506 geometry = change.geometry(graph),
40507 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
40511 id: 'tag_suggests_area',
40512 message: t('validations.tag_suggests_area', { tag: suggestion }),
40523 window.locale = { _current: 'en' };
40525 locale.current = function(_) {
40526 if (!arguments.length) return locale._current;
40527 if (locale[_] !== undefined) locale._current = _;
40528 else if (locale[_.split('-')[0]]) locale._current = _.split('-')[0];
40532 function t(s, o, loc) {
40533 loc = loc || locale._current;
40535 var path = s.split(".").reverse(),
40538 while (rep !== undefined && path.length) rep = rep[path.pop()];
40540 if (rep !== undefined) {
40541 if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
40545 if (loc !== 'en') {
40546 return t(s, o, 'en');
40549 if (o && 'default' in o) {
40550 return o['default'];
40553 var missing = 'Missing ' + loc + ' translation: ' + s;
40554 if (typeof console !== "undefined") console.error(missing);
40558 iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081]},"n185964961":{"id":"n185964961","loc":[-85.6406588,41.942601]},"n185964962":{"id":"n185964962","loc":[-85.6394548,41.94261]},"n185970607":{"id":"n185970607","loc":[-85.641094,41.94006]},"n185970614":{"id":"n185970614","loc":[-85.641825,41.941316]},"n185970616":{"id":"n185970616","loc":[-85.641838,41.941556]},"n185973650":{"id":"n185973650","loc":[-85.639918,41.940064]},"n185973660":{"id":"n185973660","loc":[-85.640645,41.941339]},"n185973659":{"id":"n185973659","loc":[-85.6406115,41.9400658]},"n185974479":{"id":"n185974479","loc":[-85.639402,41.941344]},"n185974481":{"id":"n185974481","loc":[-85.643071,41.941288]},"n185976259":{"id":"n185976259","loc":[-85.642213,41.940043]},"n185976261":{"id":"n185976261","loc":[-85.643056,41.94001]},"n185964959":{"id":"n185964959","loc":[-85.6431031,41.9425754]},"n185964960":{"id":"n185964960","loc":[-85.6418749,41.9425864]},"n185981481":{"id":"n185981481","loc":[-85.6386827,41.9400828]},"n185981482":{"id":"n185981482","loc":[-85.6393664,41.9400854]},"n2138493844":{"id":"n2138493844","loc":[-85.6427969,41.940522]},"n2138493845":{"id":"n2138493845","loc":[-85.6425891,41.9405228]},"n2138493846":{"id":"n2138493846","loc":[-85.6425868,41.9402875]},"n2138493847":{"id":"n2138493847","loc":[-85.6427969,41.9402858]},"n2138493848":{"id":"n2138493848","loc":[-85.6425708,41.9405234]},"n2138493849":{"id":"n2138493849","loc":[-85.642568,41.9402855]},"n2138493850":{"id":"n2138493850","loc":[-85.6423157,41.9402886]},"n2138493851":{"id":"n2138493851","loc":[-85.6423212,41.9404362]},"n2138493852":{"id":"n2138493852","loc":[-85.6422923,41.9404578]},"n2138493853":{"id":"n2138493853","loc":[-85.6422868,41.9404834]},"n2138493854":{"id":"n2138493854","loc":[-85.6423226,41.9405091]},"n2138493855":{"id":"n2138493855","loc":[-85.6423847,41.9405111]},"n2138493856":{"id":"n2138493856","loc":[-85.6424081,41.9405265]},"n2140155811":{"id":"n2140155811","loc":[-85.6419547,41.9410956]},"n2140155814":{"id":"n2140155814","loc":[-85.6427577,41.9410884]},"n2140155816":{"id":"n2140155816","loc":[-85.6427545,41.9410052]},"n2140155818":{"id":"n2140155818","loc":[-85.6428057,41.9410028]},"n2140155821":{"id":"n2140155821","loc":[-85.6427993,41.9407339]},"n2140155823":{"id":"n2140155823","loc":[-85.6427385,41.9407339]},"n2140155825":{"id":"n2140155825","loc":[-85.6427417,41.9406435]},"n2140155827":{"id":"n2140155827","loc":[-85.6419515,41.9406482]},"n2140155828":{"id":"n2140155828","loc":[-85.6429368,41.9412407]},"n2140155829":{"id":"n2140155829","loc":[-85.6417756,41.9412526]},"n2140155830":{"id":"n2140155830","loc":[-85.641766,41.9405983]},"n2140155831":{"id":"n2140155831","loc":[-85.6419803,41.9405983]},"n2140155832":{"id":"n2140155832","loc":[-85.6419611,41.9401366]},"n2140155833":{"id":"n2140155833","loc":[-85.6429336,41.94012]},"n2140155834":{"id":"n2140155834","loc":[-85.6430697,41.9411732]},"n2140155835":{"id":"n2140155835","loc":[-85.6428411,41.9409974]},"n2140155837":{"id":"n2140155837","loc":[-85.6428388,41.9407211]},"n2140155839":{"id":"n2140155839","loc":[-85.6430624,41.9405521]},"n2140155840":{"id":"n2140155840","loc":[-85.6427323,41.9412396]},"n2140155842":{"id":"n2140155842","loc":[-85.6418147,41.9412457]},"n2140155844":{"id":"n2140155844","loc":[-85.641813,41.9411319]},"n2140155845":{"id":"n2140155845","loc":[-85.6418394,41.9411111]},"n2140155847":{"id":"n2140155847","loc":[-85.6418838,41.9410977]},"n2140155849":{"id":"n2140155849","loc":[-85.6427324,41.9410921]},"n2140155851":{"id":"n2140155851","loc":[-85.6427798,41.9412945]},"n2140155852":{"id":"n2140155852","loc":[-85.6427701,41.9411777]},"n2140155854":{"id":"n2140155854","loc":[-85.6427323,41.9411572]},"n2140155856":{"id":"n2140155856","loc":[-85.6418478,41.9411666]},"n2165942818":{"id":"n2165942818","loc":[-85.6437533,41.9415029]},"n2165942819":{"id":"n2165942819","loc":[-85.6437623,41.9421195]},"n2168510551":{"id":"n2168510551","loc":[-85.6423795,41.9422615]},"n2168510552":{"id":"n2168510552","loc":[-85.6423744,41.9419439]},"n2168510553":{"id":"n2168510553","loc":[-85.642518,41.9419427]},"n2168510554":{"id":"n2168510554","loc":[-85.6425186,41.9419801]},"n2168510555":{"id":"n2168510555","loc":[-85.6428314,41.9419773]},"n2168510556":{"id":"n2168510556","loc":[-85.6428368,41.9423116]},"n2168510557":{"id":"n2168510557","loc":[-85.6424947,41.9423146]},"n2168510558":{"id":"n2168510558","loc":[-85.6424938,41.9422605]},"n2189046007":{"id":"n2189046007","loc":[-85.6410866,41.9424327]},"n2189046009":{"id":"n2189046009","loc":[-85.6410805,41.9420061]},"n2189046011":{"id":"n2189046011","loc":[-85.6412443,41.9420048]},"n2189046012":{"id":"n2189046012","loc":[-85.6412505,41.9424314]},"n2189046014":{"id":"n2189046014","loc":[-85.6413311,41.942968]},"n2189046016":{"id":"n2189046016","loc":[-85.6413281,41.942713]},"n2189046018":{"id":"n2189046018","loc":[-85.641521,41.9427117]},"n2189046021":{"id":"n2189046021","loc":[-85.6415234,41.9429236]},"n2189046022":{"id":"n2189046022","loc":[-85.6415045,41.9429238]},"n2189046025":{"id":"n2189046025","loc":[-85.641505,41.9429668]},"n2189046053":{"id":"n2189046053","loc":[-85.6385988,41.942412]},"n2189046054":{"id":"n2189046054","loc":[-85.6385985,41.9423311]},"n2189046055":{"id":"n2189046055","loc":[-85.6387617,41.9423308]},"n2189046056":{"id":"n2189046056","loc":[-85.6387616,41.9423026]},"n2189046058":{"id":"n2189046058","loc":[-85.6388215,41.9423025]},"n2189046059":{"id":"n2189046059","loc":[-85.6388219,41.9424115]},"n2189046060":{"id":"n2189046060","loc":[-85.6391096,41.9424486]},"n2189046061":{"id":"n2189046061","loc":[-85.6391105,41.9423673]},"n2189046063":{"id":"n2189046063","loc":[-85.6392911,41.9423684]},"n2189046065":{"id":"n2189046065","loc":[-85.6392903,41.9424497]},"n2189046067":{"id":"n2189046067","loc":[-85.6397927,41.9423876]},"n2189046069":{"id":"n2189046069","loc":[-85.6397897,41.9422981]},"n2189046070":{"id":"n2189046070","loc":[-85.6399702,41.9422947]},"n2189046072":{"id":"n2189046072","loc":[-85.6399732,41.9423843]},"n2189046074":{"id":"n2189046074","loc":[-85.6396331,41.9430227]},"n2189046075":{"id":"n2189046075","loc":[-85.6398673,41.9430189]},"n2189046077":{"id":"n2189046077","loc":[-85.6398656,41.9429637]},"n2189046079":{"id":"n2189046079","loc":[-85.6398885,41.9429633]},"n2189046082":{"id":"n2189046082","loc":[-85.6398832,41.942779]},"n2189046083":{"id":"n2189046083","loc":[-85.6398513,41.9427796]},"n2189046085":{"id":"n2189046085","loc":[-85.6398502,41.9427401]},"n2189046087":{"id":"n2189046087","loc":[-85.6397889,41.9427411]},"n2189046089":{"id":"n2189046089","loc":[-85.6397892,41.942753]},"n2189046090":{"id":"n2189046090","loc":[-85.6396983,41.9427544]},"n2189046092":{"id":"n2189046092","loc":[-85.6396993,41.9427882]},"n2189046094":{"id":"n2189046094","loc":[-85.6396746,41.9427886]},"n2189046096":{"id":"n2189046096","loc":[-85.6396758,41.9428296]},"n2189046097":{"id":"n2189046097","loc":[-85.6397007,41.9428292]},"n2189046099":{"id":"n2189046099","loc":[-85.6397018,41.9428686]},"n2189046103":{"id":"n2189046103","loc":[-85.6396289,41.9428697]},"n2189046112":{"id":"n2189046112","loc":[-85.6435683,41.9429457]},"n2189046113":{"id":"n2189046113","loc":[-85.643568,41.9427766]},"n2189046115":{"id":"n2189046115","loc":[-85.6434011,41.9427767]},"n2189046116":{"id":"n2189046116","loc":[-85.6434012,41.9428631]},"n2189046117":{"id":"n2189046117","loc":[-85.643448,41.9428631]},"n2189046118":{"id":"n2189046118","loc":[-85.6434481,41.9429457]},"n2189046119":{"id":"n2189046119","loc":[-85.6428363,41.9429809]},"n2189046120":{"id":"n2189046120","loc":[-85.6429171,41.9429791]},"n2189046121":{"id":"n2189046121","loc":[-85.642914,41.9429041]},"n2189046122":{"id":"n2189046122","loc":[-85.6429385,41.9429035]},"n2189046123":{"id":"n2189046123","loc":[-85.6429348,41.9428126]},"n2189046124":{"id":"n2189046124","loc":[-85.6427746,41.9428163]},"n2189046125":{"id":"n2189046125","loc":[-85.6427783,41.942906]},"n2189046126":{"id":"n2189046126","loc":[-85.6428332,41.9429047]},"n2189046127":{"id":"n2189046127","loc":[-85.6423018,41.9428859]},"n2189046128":{"id":"n2189046128","loc":[-85.6422987,41.9427208]},"n2189046130":{"id":"n2189046130","loc":[-85.6424218,41.9427195]},"n2189046131":{"id":"n2189046131","loc":[-85.6424246,41.9428684]},"n2189046132":{"id":"n2189046132","loc":[-85.6423845,41.9428689]},"n2189046133":{"id":"n2189046133","loc":[-85.6423848,41.942885]},"n2189046134":{"id":"n2189046134","loc":[-85.641533,41.9429392]},"n2189046135":{"id":"n2189046135","loc":[-85.6416096,41.9428768]},"n2189046137":{"id":"n2189046137","loc":[-85.6416763,41.9429221]},"n2189046138":{"id":"n2189046138","loc":[-85.6415997,41.9429845]},"n2189046139":{"id":"n2189046139","loc":[-85.6420598,41.9428016]},"n2189046140":{"id":"n2189046140","loc":[-85.6420593,41.9427415]},"n2189046141":{"id":"n2189046141","loc":[-85.6421957,41.9427409]},"n2189046142":{"id":"n2189046142","loc":[-85.6421963,41.9428182]},"n2189046143":{"id":"n2189046143","loc":[-85.6421281,41.9428185]},"n2189046144":{"id":"n2189046144","loc":[-85.6421279,41.9428013]},"n2189046145":{"id":"n2189046145","loc":[-85.6409429,41.9429345]},"n2189046146":{"id":"n2189046146","loc":[-85.6410354,41.9429334]},"n2189046147":{"id":"n2189046147","loc":[-85.6410325,41.9427972]},"n2189046148":{"id":"n2189046148","loc":[-85.640997,41.9427976]},"n2189046149":{"id":"n2189046149","loc":[-85.6409963,41.9427643]},"n2189046150":{"id":"n2189046150","loc":[-85.6408605,41.9427659]},"n2189046152":{"id":"n2189046152","loc":[-85.6408623,41.9428482]},"n2189046153":{"id":"n2189046153","loc":[-85.640941,41.9428473]},"n2189152992":{"id":"n2189152992","loc":[-85.6437661,41.9422257]},"n2189152993":{"id":"n2189152993","loc":[-85.643768,41.9424067]},"n2189152994":{"id":"n2189152994","loc":[-85.6432176,41.9417705]},"n2189152995":{"id":"n2189152995","loc":[-85.6432097,41.941327]},"n2189152996":{"id":"n2189152996","loc":[-85.6436493,41.9413226]},"n2189152997":{"id":"n2189152997","loc":[-85.6436563,41.9417164]},"n2189152998":{"id":"n2189152998","loc":[-85.6435796,41.9417171]},"n2189152999":{"id":"n2189152999","loc":[-85.6435805,41.9417669]},"n2189153000":{"id":"n2189153000","loc":[-85.6438202,41.9414953]},"n2189153001":{"id":"n2189153001","loc":[-85.6438173,41.9413175]},"n2189153004":{"id":"n2189153004","loc":[-85.6432535,41.9418466]},"n2189153005":{"id":"n2189153005","loc":[-85.6433935,41.9418599]},"n2189153006":{"id":"n2189153006","loc":[-85.6434831,41.9418986]},"n2189153007":{"id":"n2189153007","loc":[-85.6435678,41.9419774]},"n2189153008":{"id":"n2189153008","loc":[-85.6435987,41.9420282]},"n2189153009":{"id":"n2189153009","loc":[-85.643438,41.9419573]},"n2189153010":{"id":"n2189153010","loc":[-85.6435284,41.9424676]},"n2189153011":{"id":"n2189153011","loc":[-85.6436207,41.9423631]},"n2189153012":{"id":"n2189153012","loc":[-85.6434957,41.9422973]},"n2189153013":{"id":"n2189153013","loc":[-85.6434457,41.9422458]},"n2189153014":{"id":"n2189153014","loc":[-85.6433976,41.9421772]},"n2189153015":{"id":"n2189153015","loc":[-85.6433861,41.9420785]},"n2189153016":{"id":"n2189153016","loc":[-85.6433765,41.9420313]},"n2189153017":{"id":"n2189153017","loc":[-85.6432207,41.9420284]},"n2189153018":{"id":"n2189153018","loc":[-85.6432245,41.9422759]},"n2189153019":{"id":"n2189153019","loc":[-85.6432649,41.9423474]},"n2189153020":{"id":"n2189153020","loc":[-85.6433226,41.9424132]},"n2189153021":{"id":"n2189153021","loc":[-85.6434111,41.9424704]},"n2189153022":{"id":"n2189153022","loc":[-85.6434591,41.9424347]},"n2189153025":{"id":"n2189153025","loc":[-85.6437669,41.9423073]},"n2189153026":{"id":"n2189153026","loc":[-85.6436611,41.942293]},"n2189153027":{"id":"n2189153027","loc":[-85.6435784,41.9422473]},"n2189153028":{"id":"n2189153028","loc":[-85.6435245,41.9421443]},"n2189153029":{"id":"n2189153029","loc":[-85.6435149,41.9420613]},"n2189153030":{"id":"n2189153030","loc":[-85.6433528,41.9419269]},"n2189153031":{"id":"n2189153031","loc":[-85.6432535,41.9419191]},"n2189153032":{"id":"n2189153032","loc":[-85.6430868,41.9419198]},"n2189153033":{"id":"n2189153033","loc":[-85.6434894,41.9420033]},"n2189153034":{"id":"n2189153034","loc":[-85.6432974,41.9419225]},"n2189153035":{"id":"n2189153035","loc":[-85.6433055,41.9421632]},"n2189153036":{"id":"n2189153036","loc":[-85.6433538,41.9422849]},"n2189153037":{"id":"n2189153037","loc":[-85.6434718,41.9423887]},"n2189153038":{"id":"n2189153038","loc":[-85.6436134,41.9422667]},"n2189153040":{"id":"n2189153040","loc":[-85.6438759,41.9414017]},"n2189153041":{"id":"n2189153041","loc":[-85.6438181,41.9413687]},"n2189153042":{"id":"n2189153042","loc":[-85.6436821,41.9413044]},"n2189153043":{"id":"n2189153043","loc":[-85.6435899,41.9412862]},"n2189153044":{"id":"n2189153044","loc":[-85.6433169,41.9417268]},"n2189153045":{"id":"n2189153045","loc":[-85.643301,41.9412859]},"n2189153046":{"id":"n2189153046","loc":[-85.6435531,41.9416981]},"n2189153047":{"id":"n2189153047","loc":[-85.6435427,41.9412863]},"n185948706":{"id":"n185948706","loc":[-85.6369439,41.940122]},"n185949348":{"id":"n185949348","loc":[-85.640039,41.931135]},"n185949870":{"id":"n185949870","loc":[-85.643195,41.949261]},"n185954680":{"id":"n185954680","loc":[-85.6337802,41.9401143]},"n185954784":{"id":"n185954784","loc":[-85.6487485,41.942527]},"n185958670":{"id":"n185958670","loc":[-85.637255,41.940104]},"n185958672":{"id":"n185958672","loc":[-85.636996,41.941355]},"n185960207":{"id":"n185960207","loc":[-85.634992,41.940118]},"n185963163":{"id":"n185963163","loc":[-85.638831,41.93398]},"n185963165":{"id":"n185963165","loc":[-85.640073,41.933968]},"n185963167":{"id":"n185963167","loc":[-85.641225,41.933972]},"n185963168":{"id":"n185963168","loc":[-85.642386,41.933952]},"n185964695":{"id":"n185964695","loc":[-85.6443608,41.9425645]},"n185964697":{"id":"n185964697","loc":[-85.644384,41.939941]},"n185964963":{"id":"n185964963","loc":[-85.6382347,41.9426146]},"n185964965":{"id":"n185964965","loc":[-85.637022,41.942622]},"n185964967":{"id":"n185964967","loc":[-85.6363706,41.9426606]},"n185964968":{"id":"n185964968","loc":[-85.6357988,41.9427748]},"n185964969":{"id":"n185964969","loc":[-85.6355409,41.9428465]},"n185964970":{"id":"n185964970","loc":[-85.6348729,41.9430443]},"n185966958":{"id":"n185966958","loc":[-85.641946,41.946413]},"n185966960":{"id":"n185966960","loc":[-85.643148,41.946389]},"n185967774":{"id":"n185967774","loc":[-85.641889,41.943852]},"n185967775":{"id":"n185967775","loc":[-85.641922,41.945121]},"n185967776":{"id":"n185967776","loc":[-85.641927,41.947544]},"n185967777":{"id":"n185967777","loc":[-85.641982,41.947622]},"n185969289":{"id":"n185969289","loc":[-85.63928,41.929221]},"n185969704":{"id":"n185969704","loc":[-85.6388186,41.9350099]},"n185969706":{"id":"n185969706","loc":[-85.6400709,41.9349957]},"n185969708":{"id":"n185969708","loc":[-85.6412214,41.9349827]},"n185969710":{"id":"n185969710","loc":[-85.6423509,41.934974]},"n185970602":{"id":"n185970602","loc":[-85.641293,41.931817]},"n185970604":{"id":"n185970604","loc":[-85.641258,41.932705]},"n185970605":{"id":"n185970605","loc":[-85.641148,41.936984]},"n185970606":{"id":"n185970606","loc":[-85.641112,41.938169]},"n185970906":{"id":"n185970906","loc":[-85.639454,41.943871]},"n185970908":{"id":"n185970908","loc":[-85.6394635,41.9450504]},"n185970909":{"id":"n185970909","loc":[-85.6394914,41.9451911]},"n185971368":{"id":"n185971368","loc":[-85.635769,41.940122]},"n185971978":{"id":"n185971978","loc":[-85.640003,41.936988]},"n185971980":{"id":"n185971980","loc":[-85.642299,41.936988]},"n185973633":{"id":"n185973633","loc":[-85.639023,41.92861]},"n185973635":{"id":"n185973635","loc":[-85.639153,41.928969]},"n185973637":{"id":"n185973637","loc":[-85.639213,41.929088]},"n185973639":{"id":"n185973639","loc":[-85.63935,41.929396]},"n185973641":{"id":"n185973641","loc":[-85.640143,41.931462]},"n185973644":{"id":"n185973644","loc":[-85.64019,41.931788]},"n185973646":{"id":"n185973646","loc":[-85.6401365,41.9327199]},"n185973648":{"id":"n185973648","loc":[-85.639983,41.938174]},"n185974477":{"id":"n185974477","loc":[-85.638206,41.941331]},"n185975928":{"id":"n185975928","loc":[-85.640683,41.94513]},"n185975930":{"id":"n185975930","loc":[-85.643102,41.945103]},"n185976255":{"id":"n185976255","loc":[-85.642424,41.931817]},"n185976257":{"id":"n185976257","loc":[-85.64242,41.932699]},"n185976258":{"id":"n185976258","loc":[-85.6422621,41.9381489]},"n185977452":{"id":"n185977452","loc":[-85.6457497,41.9398834]},"n185978772":{"id":"n185978772","loc":[-85.646656,41.939869]},"n185981472":{"id":"n185981472","loc":[-85.6388962,41.9321266]},"n185981474":{"id":"n185981474","loc":[-85.6388769,41.9327334]},"n185981476":{"id":"n185981476","loc":[-85.638829,41.934116]},"n185981478":{"id":"n185981478","loc":[-85.63876,41.937002]},"n185981480":{"id":"n185981480","loc":[-85.638682,41.93819]},"n185981999":{"id":"n185981999","loc":[-85.638194,41.9400866]},"n185982001":{"id":"n185982001","loc":[-85.646302,41.93988]},"n185982877":{"id":"n185982877","loc":[-85.640676,41.943867]},"n185982879":{"id":"n185982879","loc":[-85.640734,41.945887]},"n185985823":{"id":"n185985823","loc":[-85.643106,41.943841]},"n185985824":{"id":"n185985824","loc":[-85.643145,41.947641]},"n185985825":{"id":"n185985825","loc":[-85.643219,41.950829]},"n1475301385":{"id":"n1475301385","loc":[-85.6360612,41.9427042]},"n1475301397":{"id":"n1475301397","loc":[-85.6366651,41.9426328]},"n2139795811":{"id":"n2139795811","loc":[-85.6469154,41.9425427]},"n2139795830":{"id":"n2139795830","loc":[-85.6443194,41.9399444]},"n2139795834":{"id":"n2139795834","loc":[-85.6453506,41.9399002]},"n2139795837":{"id":"n2139795837","loc":[-85.645806,41.9398831]},"n2139858932":{"id":"n2139858932","loc":[-85.6351721,41.9429557]},"n2140019000":{"id":"n2140019000","loc":[-85.6359935,41.9427224]},"n2165942817":{"id":"n2165942817","loc":[-85.6442017,41.9414993]},"n2165942820":{"id":"n2165942820","loc":[-85.6442107,41.9421159]},"n2189152990":{"id":"n2189152990","loc":[-85.6442328,41.942404]},"n2189152991":{"id":"n2189152991","loc":[-85.6442309,41.9422229]},"n2189153002":{"id":"n2189153002","loc":[-85.6441329,41.9413147]},"n2189153003":{"id":"n2189153003","loc":[-85.6441357,41.9414925]},"n2189153023":{"id":"n2189153023","loc":[-85.6443453,41.9423074]},"n2189153024":{"id":"n2189153024","loc":[-85.6442318,41.9423045]},"n2189153039":{"id":"n2189153039","loc":[-85.6441343,41.9414025]},"w208643102":{"id":"w208643102","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153034","n2189153035","n2189153036","n2189153037","n2189153038"]},"w17966942":{"id":"w17966942","tags":{"highway":"residential","name":"Millard St"},"nodes":["n185954680","n185960207","n185971368","n185948706","n185958670","n185981999","n185981481","n185981482","n185973650","n185973659","n185970607","n185976259","n185976261","n2139795830","n185964697","n2139795834","n185977452","n2139795837","n185982001","n185978772"]},"w208643105":{"id":"w208643105","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153046","n2189153047"]},"w208631637":{"id":"w208631637","tags":{"area":"yes","building":"yes"},"nodes":["n2189046014","n2189046016","n2189046018","n2189046021","n2189046022","n2189046025","n2189046014"]},"w208643096":{"id":"w208643096","tags":{"amenity":"parking","area":"yes","fee":"no"},"nodes":["n2189152990","n2189153024","n2189152991","n2189152992","n2189153025","n2189152993","n2189152990"]},"w208631656":{"id":"w208631656","tags":{"area":"yes","building":"yes"},"nodes":["n2189046134","n2189046135","n2189046137","n2189046138","n2189046134"]},"w204003417":{"id":"w204003417","tags":{"area":"yes","building":"school"},"nodes":["n2140155811","n2140155814","n2140155816","n2140155818","n2140155821","n2140155823","n2140155825","n2140155827","n2140155811"]},"w208631654":{"id":"w208631654","tags":{"area":"yes","building":"yes"},"nodes":["n2189046127","n2189046128","n2189046130","n2189046131","n2189046132","n2189046133","n2189046127"]},"w17966327":{"id":"w17966327","tags":{"highway":"residential","name":"S Douglas Ave"},"nodes":["n185976261","n2140155839","n2140155834","n185974481","n2189153032","n185964959"]},"w41785752":{"id":"w41785752","tags":{"highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60","access":"yes"},"nodes":["n185954784","n2139795811","n185964695","n185964959","n185964960","n185964961","n185964962","n185964963","n185964965","n1475301397","n185964967","n1475301385","n2140019000","n185964968","n185964969","n2139858932","n185964970"]},"w203841842":{"id":"w203841842","tags":{"area":"yes","leisure":"playground"},"nodes":["n2138493848","n2138493849","n2138493850","n2138493851","n2138493852","n2138493853","n2138493854","n2138493855","n2138493856","n2138493848"]},"w208643103":{"id":"w208643103","tags":{"highway":"service"},"nodes":["n2189153039","n2189153040","n2189153041","n2189153042","n2189153043","n2189153047","n2189153045","n185974481"]},"w208643098":{"id":"w208643098","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153000","n2189153041","n2189153001","n2189153002","n2189153039","n2189153003","n2189153000"]},"w208631646":{"id":"w208631646","tags":{"area":"yes","building":"yes"},"nodes":["n2189046067","n2189046069","n2189046070","n2189046072","n2189046067"]},"w208631653":{"id":"w208631653","tags":{"area":"yes","building":"yes"},"nodes":["n2189046119","n2189046120","n2189046121","n2189046122","n2189046123","n2189046124","n2189046125","n2189046126","n2189046119"]},"w17966041":{"id":"w17966041","tags":{"highway":"residential","name":"S Lincoln Ave"},"nodes":["n185973659","n185973660","n185964961"]},"w208631645":{"id":"w208631645","tags":{"area":"yes","building":"yes"},"nodes":["n2189046060","n2189046061","n2189046063","n2189046065","n2189046060"]},"w206803397":{"id":"w206803397","tags":{"area":"yes","building":"yes"},"nodes":["n2168510551","n2168510552","n2168510553","n2168510554","n2168510555","n2168510556","n2168510557","n2168510558","n2168510551"]},"w17965792":{"id":"w17965792","tags":{"highway":"residential","name":"N Hooker Ave"},"nodes":["n185964962","n185970906","n185970908","n185970909"]},"w208631651":{"id":"w208631651","tags":{"area":"yes","building":"yes"},"nodes":["n2189046112","n2189046113","n2189046115","n2189046116","n2189046117","n2189046118","n2189046112"]},"w208631643":{"id":"w208631643","tags":{"area":"yes","building":"yes"},"nodes":["n2189046053","n2189046054","n2189046055","n2189046056","n2189046058","n2189046059","n2189046053"]},"w17966878":{"id":"w17966878","tags":{"highway":"residential","name":"S Hooker Ave"},"nodes":["n185981472","n185981474","n185963163","n185981476","n185969704","n185981478","n185981480","n185981481"]},"w17966102":{"id":"w17966102","tags":{"highway":"residential","name":"South St"},"nodes":["n185958672","n185974477","n185974479","n185973660","n185970614"]},"w208631660":{"id":"w208631660","tags":{"area":"yes","building":"yes"},"nodes":["n2189046145","n2189046146","n2189046147","n2189046148","n2189046149","n2189046150","n2189046152","n2189046153","n2189046145"]},"w208643101":{"id":"w208643101","tags":{"highway":"service"},"nodes":["n2189153023","n2189153024","n2189153025","n2189153026","n2189153038","n2189153027","n2189153028","n2189153029","n2189153033","n2189153009","n2189153030","n2189153034","n2189153031","n2189153032"]},"w204000205":{"id":"w204000205","tags":{"highway":"residential","name":"South St","oneway":"yes"},"nodes":["n185974481","n2140155851","n185970614"]},"w203841841":{"id":"w203841841","tags":{"area":"yes","leisure":"pitch","pitch":"basketball"},"nodes":["n2138493844","n2138493845","n2138493846","n2138493847","n2138493844"]},"w17965444":{"id":"w17965444","tags":{"highway":"residential","name":"N Grant Ave"},"nodes":["n185964960","n185967774","n185967775","n185966958","n185967776","n185967777"]},"w208631648":{"id":"w208631648","tags":{"area":"yes","building":"yes"},"nodes":["n2189046074","n2189046075","n2189046077","n2189046079","n2189046082","n2189046083","n2189046085","n2189046087","n2189046089","n2189046090","n2189046092","n2189046094","n2189046096","n2189046097","n2189046099","n2189046103","n2189046074"]},"w208643100":{"id":"w208643100","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153010","n2189153011","n2189153012","n2189153013","n2189153014","n2189153015","n2189153016","n2189153017","n2189153018","n2189153019","n2189153020","n2189153021","n2189153022","n2189153010"]},"w17965749":{"id":"w17965749","tags":{"highway":"residential","name":"S Grant Ave"},"nodes":["n185970614","n185970616","n185964960"]},"w206574482":{"id":"w206574482","tags":{"amenity":"library","area":"yes","building":"yes","name":"Three Rivers Public Library"},"nodes":["n2165942817","n2165942818","n2165942819","n2165942820","n2165942817"]},"w208643097":{"id":"w208643097","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189152994","n2189152995","n2189152996","n2189152997","n2189152998","n2189152999","n2189152994"]},"w17966879":{"id":"w17966879","tags":{"highway":"residential","name":"S Hooker Ave"},"nodes":["n185981482","n185974479","n185964962"]},"w17966325":{"id":"w17966325","tags":{"highway":"residential","name":"S Douglas Ave"},"nodes":["n185976255","n185976257","n185963168","n185969710","n185971980","n185976258","n185954700","n185976259"]},"w17967390":{"id":"w17967390","tags":{"highway":"residential","name":"N Douglas Ave"},"nodes":["n185964959","n185985823","n185975930","n185966960","n185985824","n185949870","n185985825"]},"w208631635":{"id":"w208631635","tags":{"area":"yes","building":"yes"},"nodes":["n2189046007","n2189046009","n2189046011","n2189046012","n2189046007"]},"w208643099":{"id":"w208643099","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153031","n2189153004","n2189153005","n2189153006","n2189153007","n2189153008","n2189153029","n2189153033","n2189153009","n2189153030","n2189153031"]},"w208631658":{"id":"w208631658","tags":{"area":"yes","building":"yes"},"nodes":["n2189046139","n2189046140","n2189046141","n2189046142","n2189046143","n2189046144","n2189046139"]},"w208643104":{"id":"w208643104","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153044","n2189153045"]},"w17966039":{"id":"w17966039","tags":{"highway":"residential","name":"S Lincoln Ave"},"nodes":["n185973633","n185973635","n185973637","n185969289","n185973639","n185949348","n185973641","n185973644","n185973646","n185963165","n185969706","n185971978","n185973648","n185973650"]},"w204003420":{"id":"w204003420","tags":{"amenity":"parking","area":"yes"},"nodes":["n2140155840","n2140155842","n2140155844","n2140155845","n2140155847","n2140155849","n2140155854","n2140155840"]},"w204003419":{"id":"w204003419","tags":{"highway":"service"},"nodes":["n2140155834","n2140155835","n2140155837","n2140155839"]},"w204003418":{"id":"w204003418","tags":{"amenity":"school","area":"yes","name":"Andrews Elementary School"},"nodes":["n2140155828","n2140155829","n2140155830","n2140155831","n2140155832","n2140155833","n2140155828"]},"w17965747":{"id":"w17965747","tags":{"highway":"residential","name":"S Grant Ave"},"nodes":["n185970602","n185970604","n185963167","n185969708","n185970605","n185970606","n185970607"]},"w17967073":{"id":"w17967073","tags":{"highway":"residential","name":"N Lincoln Ave"},"nodes":["n185964961","n185982877","n185975928","n185982879"]},"w204003421":{"id":"w204003421","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2140155851","n2140155852","n2140155854","n2140155856"]},"r1943857":{"id":"r1943857","tags":{"modifier":"Business","name":"US 131 Business (Three Rivers, MI)","network":"US:US","ref":"131","route":"road","type":"route"},"members":[{"id":"w17966509","type":"way","role":"forward"},{"id":"w143497377","type":"way","role":""},{"id":"w134150811","type":"way","role":""},{"id":"w134150800","type":"way","role":""},{"id":"w134150789","type":"way","role":""},{"id":"w134150795","type":"way","role":""},{"id":"w41785752","type":"way","role":""},{"id":"w17965146","type":"way","role":"forward"},{"id":"w17964031","type":"way","role":"forward"}]},"r270277":{"id":"r270277","tags":{"network":"US:MI","ref":"60","route":"road","state_id":"MI","type":"route","url":"http://en.wikipedia.org/wiki/M-60_%28Michigan_highway%29"},"members":[{"id":"w17751087","type":"way","role":"east"},{"id":"w117148312","type":"way","role":"east"},{"id":"w40942155","type":"way","role":"west"},{"id":"w17751017","type":"way","role":""},{"id":"w17751083","type":"way","role":""},{"id":"w17747780","type":"way","role":""},{"id":"w41068082","type":"way","role":""},{"id":"w197025212","type":"way","role":""},{"id":"w17743874","type":"way","role":""},{"id":"w17751044","type":"way","role":""},{"id":"w17752167","type":"way","role":""},{"id":"w17751089","type":"way","role":""},{"id":"w17743879","type":"way","role":""},{"id":"w17751064","type":"way","role":""},{"id":"w197057073","type":"way","role":""},{"id":"w167699963","type":"way","role":""},{"id":"w167699972","type":"way","role":""},{"id":"w17967584","type":"way","role":""},{"id":"w167699964","type":"way","role":""},{"id":"w17967582","type":"way","role":"west"},{"id":"w41260270","type":"way","role":"west"},{"id":"w17965146","type":"way","role":"west"},{"id":"w41785752","type":"way","role":""},{"id":"w134150795","type":"way","role":""},{"id":"w134150789","type":"way","role":""},{"id":"w134150800","type":"way","role":""},{"id":"w134150811","type":"way","role":""},{"id":"w134150836","type":"way","role":""},{"id":"w134150802","type":"way","role":""},{"id":"w41074896","type":"way","role":""},{"id":"w17966773","type":"way","role":""},{"id":"w17967415","type":"way","role":""},{"id":"w41074899","type":"way","role":""},{"id":"w17967581","type":"way","role":""},{"id":"w41074902","type":"way","role":""},{"id":"w41074906","type":"way","role":""},{"id":"w209707997","type":"way","role":""},{"id":"w209707998","type":"way","role":""},{"id":"w17964798","type":"way","role":""},{"id":"w17966034","type":"way","role":""},{"id":"w17967593","type":"way","role":""},{"id":"w41074888","type":"way","role":""},{"id":"w17733772","type":"way","role":""},{"id":"w41074813","type":"way","role":""},{"id":"w17742213","type":"way","role":""},{"id":"w17746863","type":"way","role":""},{"id":"w17745772","type":"way","role":""},{"id":"w17742222","type":"way","role":""},{"id":"w17745922","type":"way","role":""},{"id":"w17742198","type":"way","role":""},{"id":"w17747675","type":"way","role":""},{"id":"w17739927","type":"way","role":""},{"id":"w17745708","type":"way","role":""},{"id":"w41006323","type":"way","role":""},{"id":"w17744233","type":"way","role":""},{"id":"w17739436","type":"way","role":""},{"id":"w17742201","type":"way","role":""},{"id":"w151418616","type":"way","role":""},{"id":"w17750062","type":"way","role":""},{"id":"w17742227","type":"way","role":"east"},{"id":"w41006348","type":"way","role":"east"},{"id":"w41260984","type":"way","role":""},{"id":"w17832427","type":"way","role":""},{"id":"w17838408","type":"way","role":""},{"id":"w17835846","type":"way","role":""},{"id":"w17832923","type":"way","role":""},{"id":"w17839388","type":"way","role":""},{"id":"w17838390","type":"way","role":""},{"id":"w17831272","type":"way","role":""},{"id":"w17828581","type":"way","role":""},{"id":"w38240686","type":"way","role":""},{"id":"w17838405","type":"way","role":"east"},{"id":"w123323711","type":"way","role":"east"},{"id":"w17830167","type":"way","role":"east"},{"id":"w99011909","type":"way","role":"east"},{"id":"w41911361","type":"way","role":"east"},{"id":"w41911355","type":"way","role":"east"},{"id":"w41911356","type":"way","role":"east"},{"id":"w117148326","type":"way","role":"west"},{"id":"w41911352","type":"way","role":"west"},{"id":"w41911353","type":"way","role":"west"},{"id":"w41911354","type":"way","role":"west"},{"id":"w41911360","type":"way","role":"west"},{"id":"w38240676","type":"way","role":"west"},{"id":"w123323710","type":"way","role":"west"},{"id":"w41260271","type":"way","role":"east"},{"id":"w41260273","type":"way","role":"east"},{"id":"w17964031","type":"way","role":"east"},{"id":"w41006344","type":"way","role":"west"},{"id":"w41006351","type":"way","role":"west"}]},"n367813436":{"id":"n367813436","loc":[-85.63605205663384,41.94305506683346],"tags":{"amenity":"fire_station","name":"Three Rivers Fire Department"}},"n185948708":{"id":"n185948708","loc":[-85.6369828,41.9408789]},"n185948710":{"id":"n185948710","loc":[-85.6370184,41.9411346]},"n185954691":{"id":"n185954691","loc":[-85.634476,41.941475]},"n185954692":{"id":"n185954692","loc":[-85.635008,41.941846]},"n185954693":{"id":"n185954693","loc":[-85.635362,41.941962]},"n185954695":{"id":"n185954695","loc":[-85.63578,41.941978]},"n185972903":{"id":"n185972903","loc":[-85.63295,41.9430062]},"n185964971":{"id":"n185964971","loc":[-85.6346811,41.9431023]},"n1819805854":{"id":"n1819805854","loc":[-85.6331275,41.9404837]},"n1819805918":{"id":"n1819805918","loc":[-85.6331168,41.942798]},"n1819805762":{"id":"n1819805762","loc":[-85.6333034,41.9424123]},"n1819805907":{"id":"n1819805907","loc":[-85.6334819,41.9419121]},"n1819805915":{"id":"n1819805915","loc":[-85.6334554,41.9413588]},"n1819848888":{"id":"n1819848888","loc":[-85.6331625,41.942679]},"n1819848930":{"id":"n1819848930","loc":[-85.6338684,41.9431252]},"n1819858505":{"id":"n1819858505","loc":[-85.6346782,41.9429092]},"n1819858507":{"id":"n1819858507","loc":[-85.6339003,41.9414534]},"n1819858508":{"id":"n1819858508","loc":[-85.6345709,41.9427742]},"n1819858509":{"id":"n1819858509","loc":[-85.63419,41.9417322]},"n1819858511":{"id":"n1819858511","loc":[-85.6340666,41.9415652]},"n1819858512":{"id":"n1819858512","loc":[-85.6343295,41.9423027]},"n1819858514":{"id":"n1819858514","loc":[-85.6343241,41.942207]},"n1819858521":{"id":"n1819858521","loc":[-85.633391,41.941231]},"n1819858528":{"id":"n1819858528","loc":[-85.6343027,41.9419716]},"n185954683":{"id":"n185954683","loc":[-85.6335412,41.940147]},"n185954685":{"id":"n185954685","loc":[-85.6334296,41.9403023]},"n185954687":{"id":"n185954687","loc":[-85.6333988,41.9404704]},"n185954689":{"id":"n185954689","loc":[-85.6335511,41.9410225]},"n185954690":{"id":"n185954690","loc":[-85.6336721,41.9411669]},"n1820938802":{"id":"n1820938802","loc":[-85.6330671,41.941845]},"n1821006702":{"id":"n1821006702","loc":[-85.6344047,41.9395496]},"n2130304133":{"id":"n2130304133","loc":[-85.6349025,41.9427659]},"n2130304136":{"id":"n2130304136","loc":[-85.6346027,41.9422017]},"n2130304138":{"id":"n2130304138","loc":[-85.6348577,41.9421517]},"n2130304140":{"id":"n2130304140","loc":[-85.6348419,41.9422694]},"n2130304142":{"id":"n2130304142","loc":[-85.6349071,41.9423135]},"n2130304144":{"id":"n2130304144","loc":[-85.6350495,41.9423312]},"n2130304146":{"id":"n2130304146","loc":[-85.6351009,41.9422812]},"n2130304147":{"id":"n2130304147","loc":[-85.6351227,41.9421532]},"n2130304148":{"id":"n2130304148","loc":[-85.635526,41.9421547]},"n2130304149":{"id":"n2130304149","loc":[-85.6355339,41.9425768]},"n2130304150":{"id":"n2130304150","loc":[-85.6351582,41.9426562]},"n2130304151":{"id":"n2130304151","loc":[-85.6351207,41.9427032]},"n2138493807":{"id":"n2138493807","loc":[-85.6350923,41.9415216]},"n2138493808":{"id":"n2138493808","loc":[-85.6353603,41.9411061]},"n2138493809":{"id":"n2138493809","loc":[-85.6354421,41.9410942]},"n2138493810":{"id":"n2138493810","loc":[-85.6355079,41.9411044]},"n2138493811":{"id":"n2138493811","loc":[-85.6355693,41.9411246]},"n2138493812":{"id":"n2138493812","loc":[-85.6355829,41.9411061]},"n2138493813":{"id":"n2138493813","loc":[-85.6355624,41.9409777]},"n2138493814":{"id":"n2138493814","loc":[-85.6355011,41.9409152]},"n2138493815":{"id":"n2138493815","loc":[-85.635383,41.9409219]},"n2138493816":{"id":"n2138493816","loc":[-85.635299,41.9409658]},"n2138493817":{"id":"n2138493817","loc":[-85.6351695,41.941204]},"n2138493818":{"id":"n2138493818","loc":[-85.6348879,41.9415166]},"n2138493819":{"id":"n2138493819","loc":[-85.634897,41.9415757]},"n2138493820":{"id":"n2138493820","loc":[-85.6349606,41.9416399]},"n2138493821":{"id":"n2138493821","loc":[-85.6350219,41.9416669]},"n2138493822":{"id":"n2138493822","loc":[-85.6351241,41.9416314]},"n2138493823":{"id":"n2138493823","loc":[-85.6350855,41.9415622]},"n2138493824":{"id":"n2138493824","loc":[-85.6350401,41.9413603]},"n2138493825":{"id":"n2138493825","loc":[-85.6352206,41.9410765]},"n2138493826":{"id":"n2138493826","loc":[-85.6343865,41.9415594]},"n2138493827":{"id":"n2138493827","loc":[-85.6343506,41.9415873]},"n2138493828":{"id":"n2138493828","loc":[-85.6344158,41.9417557]},"n2138493829":{"id":"n2138493829","loc":[-85.6344614,41.9417968]},"n2138493830":{"id":"n2138493830","loc":[-85.6345005,41.9418186]},"n2138493831":{"id":"n2138493831","loc":[-85.6345965,41.9418162]},"n2138493832":{"id":"n2138493832","loc":[-85.6347317,41.9417242]},"n2138493833":{"id":"n2138493833","loc":[-85.6346722,41.941775]},"n2139858909":{"id":"n2139858909","loc":[-85.633403,41.9391006]},"n2139858910":{"id":"n2139858910","loc":[-85.6332973,41.9393967]},"n2139858911":{"id":"n2139858911","loc":[-85.633205,41.9396742]},"n2139858912":{"id":"n2139858912","loc":[-85.6332203,41.9397772]},"n2139858913":{"id":"n2139858913","loc":[-85.6333453,41.939936]},"n2139858914":{"id":"n2139858914","loc":[-85.6333761,41.9400018]},"n2139858915":{"id":"n2139858915","loc":[-85.63328,41.9402249]},"n2139858916":{"id":"n2139858916","loc":[-85.6332357,41.9403523]},"n2139858917":{"id":"n2139858917","loc":[-85.6332838,41.9405831]},"n2139858918":{"id":"n2139858918","loc":[-85.6333643,41.9408744]},"n2139858919":{"id":"n2139858919","loc":[-85.6334394,41.9410519]},"n2139858920":{"id":"n2139858920","loc":[-85.6335815,41.9411717]},"n2139858921":{"id":"n2139858921","loc":[-85.6337478,41.9412734]},"n2139858922":{"id":"n2139858922","loc":[-85.6343174,41.9415268]},"n2139858923":{"id":"n2139858923","loc":[-85.6343886,41.9417397]},"n2139858924":{"id":"n2139858924","loc":[-85.6344407,41.9418015]},"n2139858925":{"id":"n2139858925","loc":[-85.6345139,41.9418366]},"n2139858926":{"id":"n2139858926","loc":[-85.6344846,41.942005]},"n2139858927":{"id":"n2139858927","loc":[-85.6345775,41.9422218]},"n2139858928":{"id":"n2139858928","loc":[-85.6348771,41.9427814]},"n2139858929":{"id":"n2139858929","loc":[-85.6349487,41.9427995]},"n2139858930":{"id":"n2139858930","loc":[-85.6350415,41.9427874]},"n2139858931":{"id":"n2139858931","loc":[-85.6351246,41.9428589]},"n2139858978":{"id":"n2139858978","loc":[-85.6349658,41.9431481]},"n2139858979":{"id":"n2139858979","loc":[-85.6350081,41.9431287]},"n2139858980":{"id":"n2139858980","loc":[-85.6349967,41.9430997]},"n2139858981":{"id":"n2139858981","loc":[-85.6352158,41.9430352]},"n2139858982":{"id":"n2139858982","loc":[-85.6348174,41.94267]},"n2139858983":{"id":"n2139858983","loc":[-85.6346142,41.9425989]},"n2139858984":{"id":"n2139858984","loc":[-85.6344938,41.9423809]},"n2139858985":{"id":"n2139858985","loc":[-85.6344856,41.9422997]},"n2139870380":{"id":"n2139870380","loc":[-85.6346707,41.9417955]},"n2139870381":{"id":"n2139870381","loc":[-85.6345949,41.9418311]},"n2139870382":{"id":"n2139870382","loc":[-85.6343322,41.9418659]},"n2139870383":{"id":"n2139870383","loc":[-85.6342072,41.941885]},"n2139870384":{"id":"n2139870384","loc":[-85.6341325,41.9418919]},"n2139870385":{"id":"n2139870385","loc":[-85.6341314,41.9422028]},"n2139870386":{"id":"n2139870386","loc":[-85.6340472,41.9423271]},"n2139870387":{"id":"n2139870387","loc":[-85.6342185,41.9427933]},"n2139870388":{"id":"n2139870388","loc":[-85.6340605,41.9423924]},"n2139870389":{"id":"n2139870389","loc":[-85.6339889,41.9424069]},"n2139870390":{"id":"n2139870390","loc":[-85.633971,41.942356]},"n2139870391":{"id":"n2139870391","loc":[-85.63361,41.9424235]},"n2139870392":{"id":"n2139870392","loc":[-85.6337137,41.9426819]},"n2139870393":{"id":"n2139870393","loc":[-85.6336977,41.9428632]},"n2139870394":{"id":"n2139870394","loc":[-85.6338823,41.9428647]},"n2139870395":{"id":"n2139870395","loc":[-85.6339412,41.9430069]},"n2139870396":{"id":"n2139870396","loc":[-85.6338873,41.9430353]},"n2139870397":{"id":"n2139870397","loc":[-85.6337676,41.942815]},"n2139870398":{"id":"n2139870398","loc":[-85.6336822,41.9423505]},"n2139870399":{"id":"n2139870399","loc":[-85.634037,41.9422725]},"n2139870400":{"id":"n2139870400","loc":[-85.6340294,41.9422518]},"n2139870401":{"id":"n2139870401","loc":[-85.6336726,41.9423312]},"n2139870402":{"id":"n2139870402","loc":[-85.6342188,41.9425715]},"n2139870403":{"id":"n2139870403","loc":[-85.6342524,41.942565]},"n2139870404":{"id":"n2139870404","loc":[-85.6341438,41.942299]},"n2139870405":{"id":"n2139870405","loc":[-85.6341149,41.9423061]},"n2139870407":{"id":"n2139870407","loc":[-85.6340846,41.9431458]},"n2139870408":{"id":"n2139870408","loc":[-85.6339436,41.9429032]},"n2139870409":{"id":"n2139870409","loc":[-85.6343143,41.9428207]},"n2139870410":{"id":"n2139870410","loc":[-85.6343507,41.94277]},"n2139870411":{"id":"n2139870411","loc":[-85.6341527,41.942254]},"n2139870412":{"id":"n2139870412","loc":[-85.6340925,41.9422199]},"n2139870413":{"id":"n2139870413","loc":[-85.6335435,41.9423433]},"n2139870414":{"id":"n2139870414","loc":[-85.6335023,41.9423975]},"n2139870415":{"id":"n2139870415","loc":[-85.6335086,41.9424552]},"n2139870416":{"id":"n2139870416","loc":[-85.6336296,41.942665]},"n2139870417":{"id":"n2139870417","loc":[-85.6341396,41.9428596]},"n2139870418":{"id":"n2139870418","loc":[-85.6339701,41.9424487]},"n2139870419":{"id":"n2139870419","loc":[-85.6335514,41.9425294]},"n2139870420":{"id":"n2139870420","loc":[-85.6337406,41.9424929]},"n2139870421":{"id":"n2139870421","loc":[-85.6338939,41.9428687]},"n2139870422":{"id":"n2139870422","loc":[-85.6341323,41.9419538]},"n2139870423":{"id":"n2139870423","loc":[-85.6340321,41.9420376]},"n2139870424":{"id":"n2139870424","loc":[-85.6337648,41.942238]},"n2139870425":{"id":"n2139870425","loc":[-85.6337604,41.9422685]},"n2139870426":{"id":"n2139870426","loc":[-85.6337682,41.9422928]},"n2139870427":{"id":"n2139870427","loc":[-85.6338086,41.9423862]},"n2139870428":{"id":"n2139870428","loc":[-85.6349465,41.9416631]},"n2139870429":{"id":"n2139870429","loc":[-85.6351097,41.9416973]},"n2139870430":{"id":"n2139870430","loc":[-85.6353371,41.9416798]},"n2139870431":{"id":"n2139870431","loc":[-85.6349627,41.9422506]},"n2139870432":{"id":"n2139870432","loc":[-85.634979,41.9421815]},"n2139870433":{"id":"n2139870433","loc":[-85.634885,41.9421679]},"n2139870434":{"id":"n2139870434","loc":[-85.6348689,41.9422377]},"n2139870435":{"id":"n2139870435","loc":[-85.6349779,41.9419486]},"n2139870436":{"id":"n2139870436","loc":[-85.6349505,41.9418933]},"n2139870437":{"id":"n2139870437","loc":[-85.6347327,41.9419505]},"n2139870438":{"id":"n2139870438","loc":[-85.6347614,41.9420087]},"n2139870439":{"id":"n2139870439","loc":[-85.6351889,41.9416912]},"n2139870440":{"id":"n2139870440","loc":[-85.6351092,41.9418426]},"n2139870441":{"id":"n2139870441","loc":[-85.635086,41.9419659]},"n2139870442":{"id":"n2139870442","loc":[-85.6350584,41.9421466]},"n2139870443":{"id":"n2139870443","loc":[-85.6350993,41.9421606]},"n2139870444":{"id":"n2139870444","loc":[-85.6350993,41.9422132]},"n2139870445":{"id":"n2139870445","loc":[-85.6350794,41.9422855]},"n2139870446":{"id":"n2139870446","loc":[-85.6350474,41.9423159]},"n2139870447":{"id":"n2139870447","loc":[-85.6349251,41.9422998]},"n2139870448":{"id":"n2139870448","loc":[-85.634911,41.9422755]},"n2139870449":{"id":"n2139870449","loc":[-85.6349157,41.9422553]},"n2139870450":{"id":"n2139870450","loc":[-85.6347213,41.9419324]},"n2139870451":{"id":"n2139870451","loc":[-85.6349535,41.9418771]},"n2139870452":{"id":"n2139870452","loc":[-85.6350135,41.9419421]},"n2139870453":{"id":"n2139870453","loc":[-85.6348584,41.9418997]},"n2139870454":{"id":"n2139870454","loc":[-85.6348113,41.9418101]},"n2139870455":{"id":"n2139870455","loc":[-85.6347306,41.9417449]},"n2139870456":{"id":"n2139870456","loc":[-85.6349123,41.941776]},"n2139870457":{"id":"n2139870457","loc":[-85.6349423,41.9421448]},"n2139870458":{"id":"n2139870458","loc":[-85.6349436,41.9420652]},"n2139870459":{"id":"n2139870459","loc":[-85.6349136,41.9419963]},"n2139870460":{"id":"n2139870460","loc":[-85.6349814,41.9419789]},"n2139989328":{"id":"n2139989328","loc":[-85.6334188,41.9421725]},"n2139989330":{"id":"n2139989330","loc":[-85.6335087,41.9416308]},"n2139989335":{"id":"n2139989335","loc":[-85.6336856,41.9429371]},"n2139989337":{"id":"n2139989337","loc":[-85.6333713,41.9427217]},"n2139989339":{"id":"n2139989339","loc":[-85.6332912,41.9425383]},"n2139989341":{"id":"n2139989341","loc":[-85.6339369,41.9409198]},"n2139989344":{"id":"n2139989344","loc":[-85.634097,41.9409469]},"n2139989346":{"id":"n2139989346","loc":[-85.634137,41.9412852]},"n2139989348":{"id":"n2139989348","loc":[-85.6344536,41.9414151]},"n2139989350":{"id":"n2139989350","loc":[-85.6350794,41.9412392]},"n2139989351":{"id":"n2139989351","loc":[-85.6352541,41.9409387]},"n2139989353":{"id":"n2139989353","loc":[-85.6357198,41.9408007]},"n2139989355":{"id":"n2139989355","loc":[-85.6357235,41.9427088]},"n2139989357":{"id":"n2139989357","loc":[-85.6337119,41.9421256]},"n2139989359":{"id":"n2139989359","loc":[-85.6336913,41.9420655]},"n2139989360":{"id":"n2139989360","loc":[-85.633582,41.9420867]},"n2139989362":{"id":"n2139989362","loc":[-85.6336058,41.9421491]},"n2139989364":{"id":"n2139989364","loc":[-85.6339685,41.9410995]},"n2139989366":{"id":"n2139989366","loc":[-85.6339067,41.9411383]},"n2139989368":{"id":"n2139989368","loc":[-85.6339685,41.9411972]},"n2139989370":{"id":"n2139989370","loc":[-85.6340398,41.9411619]},"n2139870379":{"id":"n2139870379","loc":[-85.6348391,41.9416651]},"n2140006363":{"id":"n2140006363","loc":[-85.6353144,41.9430345]},"n2140006364":{"id":"n2140006364","loc":[-85.6349191,41.9431422]},"n2140018997":{"id":"n2140018997","loc":[-85.63645945147184,41.942986488012565],"tags":{"amenity":"townhall","name":"Three Rivers City Hall"}},"n2140018998":{"id":"n2140018998","loc":[-85.6370319,41.9427919]},"n2140018999":{"id":"n2140018999","loc":[-85.6360687,41.9427808]},"n2199856288":{"id":"n2199856288","loc":[-85.6344968,41.9407307]},"n2199856289":{"id":"n2199856289","loc":[-85.634492,41.9406036]},"n2199856290":{"id":"n2199856290","loc":[-85.634891,41.9406001]},"n2199856291":{"id":"n2199856291","loc":[-85.6348894,41.9405288]},"n2199856292":{"id":"n2199856292","loc":[-85.6349166,41.94053]},"n2199856293":{"id":"n2199856293","loc":[-85.6349166,41.9404956]},"n2199856294":{"id":"n2199856294","loc":[-85.6350219,41.9404956]},"n2199856295":{"id":"n2199856295","loc":[-85.6350251,41.94053]},"n2199856296":{"id":"n2199856296","loc":[-85.6350538,41.9405288]},"n2199856297":{"id":"n2199856297","loc":[-85.6350602,41.94079]},"n2199856298":{"id":"n2199856298","loc":[-85.6351703,41.9407912]},"n2199856299":{"id":"n2199856299","loc":[-85.6351688,41.9409171]},"n2199856300":{"id":"n2199856300","loc":[-85.6347889,41.9409135]},"n2199856301":{"id":"n2199856301","loc":[-85.6347921,41.94079]},"n2199856302":{"id":"n2199856302","loc":[-85.6348942,41.9407888]},"n2199856303":{"id":"n2199856303","loc":[-85.6348926,41.9407283]},"n185951869":{"id":"n185951869","loc":[-85.6387639,41.957288]},"n185958643":{"id":"n185958643","loc":[-85.636746,41.929221]},"n185958645":{"id":"n185958645","loc":[-85.636791,41.929363]},"n185958647":{"id":"n185958647","loc":[-85.6375975,41.9314987]},"n185958649":{"id":"n185958649","loc":[-85.637669,41.931667]},"n185958651":{"id":"n185958651","loc":[-85.637728,41.931901]},"n185958653":{"id":"n185958653","loc":[-85.637724,41.932187]},"n185958656":{"id":"n185958656","loc":[-85.637732,41.932761]},"n185958658":{"id":"n185958658","loc":[-85.637688,41.93398]},"n185958660":{"id":"n185958660","loc":[-85.637685,41.934223]},"n185958662":{"id":"n185958662","loc":[-85.6376468,41.9350232]},"n185958664":{"id":"n185958664","loc":[-85.637564,41.937028]},"n185958666":{"id":"n185958666","loc":[-85.637458,41.938197]},"n185958668":{"id":"n185958668","loc":[-85.637424,41.938692]},"n185964972":{"id":"n185964972","loc":[-85.6341901,41.9432732]},"n185971361":{"id":"n185971361","loc":[-85.635762,41.938208]},"n185971364":{"id":"n185971364","loc":[-85.635732,41.9384]},"n185971366":{"id":"n185971366","loc":[-85.635736,41.938697]},"n185972775":{"id":"n185972775","loc":[-85.635638,42.070357]},"n185972777":{"id":"n185972777","loc":[-85.635724,42.069929]},"n185972779":{"id":"n185972779","loc":[-85.635804,42.069248]},"n185972781":{"id":"n185972781","loc":[-85.635869,42.068361]},"n185972783":{"id":"n185972783","loc":[-85.635883,42.067582]},"n185972785":{"id":"n185972785","loc":[-85.635875,42.067114]},"n185972787":{"id":"n185972787","loc":[-85.635778,42.065359]},"n185972788":{"id":"n185972788","loc":[-85.635728,42.063416]},"n185972789":{"id":"n185972789","loc":[-85.635665,42.062491]},"n185972790":{"id":"n185972790","loc":[-85.635617,42.061928]},"n185972791":{"id":"n185972791","loc":[-85.635614,42.061898]},"n185972793":{"id":"n185972793","loc":[-85.635379,42.060288]},"n185972795":{"id":"n185972795","loc":[-85.635092,42.05799]},"n185972797":{"id":"n185972797","loc":[-85.634843,42.055781]},"n185972798":{"id":"n185972798","loc":[-85.634817,42.055549]},"n185972800":{"id":"n185972800","loc":[-85.634708,42.053942]},"n185972802":{"id":"n185972802","loc":[-85.634447,42.051809]},"n185972805":{"id":"n185972805","loc":[-85.634241,42.04946]},"n185972807":{"id":"n185972807","loc":[-85.633787,42.045926]},"n185972809":{"id":"n185972809","loc":[-85.633811,42.045645]},"n185972811":{"id":"n185972811","loc":[-85.63373,42.043626]},"n185972813":{"id":"n185972813","loc":[-85.633698,42.042184]},"n185972814":{"id":"n185972814","loc":[-85.63369,42.04181]},"n185972815":{"id":"n185972815","loc":[-85.633681,42.040714]},"n185972816":{"id":"n185972816","loc":[-85.633571,42.036322]},"n185972817":{"id":"n185972817","loc":[-85.633537,42.034044]},"n185972819":{"id":"n185972819","loc":[-85.633481,42.030785]},"n185972821":{"id":"n185972821","loc":[-85.633452,42.027538]},"n185972824":{"id":"n185972824","loc":[-85.633438,42.027427]},"n185972826":{"id":"n185972826","loc":[-85.633342,42.022656]},"n185972830":{"id":"n185972830","loc":[-85.63327,42.020724]},"n185972832":{"id":"n185972832","loc":[-85.633198,42.019106]},"n185972834":{"id":"n185972834","loc":[-85.633249,42.018363]},"n185972835":{"id":"n185972835","loc":[-85.633139,42.012944]},"n185972836":{"id":"n185972836","loc":[-85.63309,42.008284]},"n185972839":{"id":"n185972839","loc":[-85.63298,42.00005]},"n185972845":{"id":"n185972845","loc":[-85.6325369,41.9764959]},"n185972847":{"id":"n185972847","loc":[-85.6327549,41.9750005]},"n185972849":{"id":"n185972849","loc":[-85.6329374,41.9742527]},"n185972851":{"id":"n185972851","loc":[-85.6331387,41.9736039]},"n185972862":{"id":"n185972862","loc":[-85.6383589,41.9585023]},"n185972868":{"id":"n185972868","loc":[-85.6393633,41.9551716]},"n185972878":{"id":"n185972878","loc":[-85.639377,41.95335]},"n185972882":{"id":"n185972882","loc":[-85.6389179,41.9516944]},"n185972885":{"id":"n185972885","loc":[-85.6387444,41.9512105]},"n185972891":{"id":"n185972891","loc":[-85.636421,41.946392]},"n185972895":{"id":"n185972895","loc":[-85.635965,41.945809]},"n185972897":{"id":"n185972897","loc":[-85.635683,41.945449]},"n185972899":{"id":"n185972899","loc":[-85.635281,41.9450252]},"n185972905":{"id":"n185972905","loc":[-85.6324428,41.9425743]},"n185985217":{"id":"n185985217","loc":[-85.638243,41.943674]},"n185985219":{"id":"n185985219","loc":[-85.638228,41.943747]},"n185985221":{"id":"n185985221","loc":[-85.638163,41.943797]},"n185985222":{"id":"n185985222","loc":[-85.638089,41.943832]},"n185985223":{"id":"n185985223","loc":[-85.637969,41.943841]},"n185985225":{"id":"n185985225","loc":[-85.637841,41.943833]},"n185985227":{"id":"n185985227","loc":[-85.637601,41.943789]},"n185985229":{"id":"n185985229","loc":[-85.637449,41.943754]},"n185985231":{"id":"n185985231","loc":[-85.637342,41.943734]},"n185985233":{"id":"n185985233","loc":[-85.637218,41.943703]},"n185985235":{"id":"n185985235","loc":[-85.637151,41.943663]},"n185985238":{"id":"n185985238","loc":[-85.637118,41.943615]},"n185985240":{"id":"n185985240","loc":[-85.637073,41.943494]},"n185990434":{"id":"n185990434","loc":[-85.6329028,41.9984292],"tags":{"railway":"level_crossing"}},"n1475284023":{"id":"n1475284023","loc":[-85.6336163,41.9435806],"tags":{"railway":"level_crossing"}},"n1475293222":{"id":"n1475293222","loc":[-85.6394045,41.953658],"tags":{"railway":"level_crossing"}},"n1475293226":{"id":"n1475293226","loc":[-85.6364975,41.9638663],"tags":{"railway":"level_crossing"}},"n1475293234":{"id":"n1475293234","loc":[-85.6390449,41.9565145]},"n1475293240":{"id":"n1475293240","loc":[-85.636943,41.9473114]},"n1475293252":{"id":"n1475293252","loc":[-85.6392115,41.9559003]},"n1475293254":{"id":"n1475293254","loc":[-85.6348931,41.9685127],"tags":{"railway":"level_crossing"}},"n1475293260":{"id":"n1475293260","loc":[-85.6375999,41.9485401]},"n1475293261":{"id":"n1475293261","loc":[-85.6391256,41.9523817],"tags":{"railway":"level_crossing"}},"n1475293264":{"id":"n1475293264","loc":[-85.6394155,41.9546493],"tags":{"railway":"level_crossing"}},"n1819805614":{"id":"n1819805614","loc":[-85.6345652,41.9363097]},"n1819805618":{"id":"n1819805618","loc":[-85.6295334,41.9426862]},"n1819805622":{"id":"n1819805622","loc":[-85.6308208,41.9430773]},"n1819805626":{"id":"n1819805626","loc":[-85.6274734,41.9406592]},"n1819805629":{"id":"n1819805629","loc":[-85.6296943,41.9430533]},"n1819805632":{"id":"n1819805632","loc":[-85.6340931,41.9354477]},"n1819805636":{"id":"n1819805636","loc":[-85.6304131,41.9436598]},"n1819805639":{"id":"n1819805639","loc":[-85.6304882,41.9426623]},"n1819805641":{"id":"n1819805641","loc":[-85.6336103,41.9367487]},"n1819805643":{"id":"n1819805643","loc":[-85.6300376,41.9418084]},"n1819805645":{"id":"n1819805645","loc":[-85.6365286,41.9336679]},"n1819805647":{"id":"n1819805647","loc":[-85.632016,41.9429221]},"n1819805666":{"id":"n1819805666","loc":[-85.6314753,41.9442663]},"n1819805669":{"id":"n1819805669","loc":[-85.6268619,41.9402203]},"n1819805673":{"id":"n1819805673","loc":[-85.6296728,41.9412099]},"n1819805676":{"id":"n1819805676","loc":[-85.6354557,41.932766]},"n1819805680":{"id":"n1819805680","loc":[-85.632752,41.9431012]},"n1819805683":{"id":"n1819805683","loc":[-85.631147,41.9432014]},"n1819805687":{"id":"n1819805687","loc":[-85.635284,41.9343942]},"n1819805690":{"id":"n1819805690","loc":[-85.6249736,41.9405794]},"n1819805694":{"id":"n1819805694","loc":[-85.6294153,41.9417925]},"n1819805698":{"id":"n1819805698","loc":[-85.6323486,41.9426986]},"n1819805702":{"id":"n1819805702","loc":[-85.6340287,41.9373871]},"n1819805707":{"id":"n1819805707","loc":[-85.6353698,41.9316326]},"n1819805711":{"id":"n1819805711","loc":[-85.6284176,41.940356]},"n1819805715":{"id":"n1819805715","loc":[-85.6291471,41.9412897]},"n1819805718":{"id":"n1819805718","loc":[-85.6311105,41.943979]},"n1819805722":{"id":"n1819805722","loc":[-85.6320868,41.9400128]},"n1819805724":{"id":"n1819805724","loc":[-85.635166,41.9324627]},"n1819805727":{"id":"n1819805727","loc":[-85.6344686,41.9350567]},"n1819805728":{"id":"n1819805728","loc":[-85.6357132,41.9332369]},"n1819805731":{"id":"n1819805731","loc":[-85.629984,41.9434444]},"n1819805760":{"id":"n1819805760","loc":[-85.6330996,41.9378784]},"n1819805766":{"id":"n1819805766","loc":[-85.625274,41.9411141]},"n1819805770":{"id":"n1819805770","loc":[-85.6326321,41.9412173]},"n1819805774":{"id":"n1819805774","loc":[-85.6347047,41.9312096]},"n1819805777":{"id":"n1819805777","loc":[-85.6363569,41.9339552]},"n1819805780":{"id":"n1819805780","loc":[-85.6327392,41.941926]},"n1819805783":{"id":"n1819805783","loc":[-85.6357239,41.9338435]},"n1819805786":{"id":"n1819805786","loc":[-85.6356595,41.9346576]},"n1819805789":{"id":"n1819805789","loc":[-85.6316469,41.9436598]},"n1819805792":{"id":"n1819805792","loc":[-85.6350587,41.9354557]},"n1819805795":{"id":"n1819805795","loc":[-85.6360028,41.9322791]},"n1819805798":{"id":"n1819805798","loc":[-85.63125,41.9443062]},"n1819805802":{"id":"n1819805802","loc":[-85.6263362,41.9408109]},"n1819805805":{"id":"n1819805805","loc":[-85.6315075,41.9438753]},"n1819805808":{"id":"n1819805808","loc":[-85.6340008,41.9316051]},"n1819805810":{"id":"n1819805810","loc":[-85.6345545,41.9320557]},"n1819805812":{"id":"n1819805812","loc":[-85.6250809,41.9408587]},"n1819805814":{"id":"n1819805814","loc":[-85.6257783,41.9400926]},"n1819805834":{"id":"n1819805834","loc":[-85.6326408,41.9424363]},"n1819805838":{"id":"n1819805838","loc":[-85.6365607,41.9334365]},"n1819805842":{"id":"n1819805842","loc":[-85.6288253,41.9410343]},"n1819805846":{"id":"n1819805846","loc":[-85.6279133,41.9402921]},"n1819805849":{"id":"n1819805849","loc":[-85.6289433,41.9405156]},"n1819805852":{"id":"n1819805852","loc":[-85.6313787,41.9439152]},"n1819805858":{"id":"n1819805858","loc":[-85.6300805,41.9420398]},"n1819805861":{"id":"n1819805861","loc":[-85.6321941,41.9396297]},"n1819805864":{"id":"n1819805864","loc":[-85.6329129,41.9393903]},"n1819805868":{"id":"n1819805868","loc":[-85.632001,41.9434922]},"n1819805870":{"id":"n1819805870","loc":[-85.6314903,41.9431535]},"n1819805873":{"id":"n1819805873","loc":[-85.6251667,41.9401166]},"n1819805876":{"id":"n1819805876","loc":[-85.63287,41.939941]},"n1819805878":{"id":"n1819805878","loc":[-85.6307886,41.9437317]},"n1819805880":{"id":"n1819805880","loc":[-85.6321727,41.940348]},"n1819805883":{"id":"n1819805883","loc":[-85.6265872,41.940113]},"n1819805885":{"id":"n1819805885","loc":[-85.6268404,41.9406672]},"n1819805887":{"id":"n1819805887","loc":[-85.6325267,41.9389035]},"n1819805889":{"id":"n1819805889","loc":[-85.6364964,41.933189]},"n1819805911":{"id":"n1819805911","loc":[-85.6248663,41.9401804]},"n1819805922":{"id":"n1819805922","loc":[-85.633267,41.9387199]},"n1819805925":{"id":"n1819805925","loc":[-85.6293402,41.9408428]},"n1819848849":{"id":"n1819848849","loc":[-85.6464957,41.9695178]},"n1819848850":{"id":"n1819848850","loc":[-85.6497642,41.9611355]},"n1819848851":{"id":"n1819848851","loc":[-85.6480943,41.9624818]},"n1819848854":{"id":"n1819848854","loc":[-85.6500362,41.9657367]},"n1819848855":{"id":"n1819848855","loc":[-85.6493673,41.9783496]},"n1819848856":{"id":"n1819848856","loc":[-85.6457409,41.9548007]},"n1819848857":{"id":"n1819848857","loc":[-85.651313,41.9760426]},"n1819848858":{"id":"n1819848858","loc":[-85.6495819,41.9784772]},"n1819848859":{"id":"n1819848859","loc":[-85.6495105,41.9833722]},"n1819848860":{"id":"n1819848860","loc":[-85.6405053,41.9492792]},"n1819848863":{"id":"n1819848863","loc":[-85.6502293,41.9786826]},"n1819848865":{"id":"n1819848865","loc":[-85.6406877,41.9495106]},"n1819848870":{"id":"n1819848870","loc":[-85.6493136,41.9704611]},"n1819848871":{"id":"n1819848871","loc":[-85.6372249,41.9441284]},"n1819848873":{"id":"n1819848873","loc":[-85.6512379,41.9659441]},"n1819848875":{"id":"n1819848875","loc":[-85.6508087,41.9650187]},"n1819848877":{"id":"n1819848877","loc":[-85.6487166,41.9605352]},"n1819848878":{"id":"n1819848878","loc":[-85.6506478,41.9760665]},"n1819848879":{"id":"n1819848879","loc":[-85.651431,41.9758512]},"n1819848886":{"id":"n1819848886","loc":[-85.6477617,41.9563945]},"n1819848889":{"id":"n1819848889","loc":[-85.6497895,41.9832286]},"n1819848892":{"id":"n1819848892","loc":[-85.6504868,41.9791931]},"n1819848893":{"id":"n1819848893","loc":[-85.6498002,41.9615085]},"n1819848894":{"id":"n1819848894","loc":[-85.6404302,41.9502846]},"n1819848901":{"id":"n1819848901","loc":[-85.6354412,41.9439886]},"n1819848903":{"id":"n1819848903","loc":[-85.6472145,41.9698528]},"n1819848904":{"id":"n1819848904","loc":[-85.6401979,41.9486233]},"n1819848905":{"id":"n1819848905","loc":[-85.6475042,41.963503]},"n1819848909":{"id":"n1819848909","loc":[-85.6343405,41.94358]},"n1819848914":{"id":"n1819848914","loc":[-85.6503474,41.9737773]},"n1819848915":{"id":"n1819848915","loc":[-85.6389533,41.9470992]},"n1819848916":{"id":"n1819848916","loc":[-85.6483625,41.9577907]},"n1819848917":{"id":"n1819848917","loc":[-85.6484768,41.9617419]},"n1819848918":{"id":"n1819848918","loc":[-85.644078,41.9545693]},"n1819848919":{"id":"n1819848919","loc":[-85.6437169,41.9543041]},"n1819848920":{"id":"n1819848920","loc":[-85.6478331,41.9627949]},"n1819848922":{"id":"n1819848922","loc":[-85.6499144,41.9785889]},"n1819848924":{"id":"n1819848924","loc":[-85.647633,41.9720066]},"n1819848926":{"id":"n1819848926","loc":[-85.6487987,41.978868]},"n1819848927":{"id":"n1819848927","loc":[-85.6495105,41.9730355]},"n1819848928":{"id":"n1819848928","loc":[-85.648223,41.9829654]},"n1819848929":{"id":"n1819848929","loc":[-85.6514846,41.9659122]},"n1819848931":{"id":"n1819848931","loc":[-85.6498753,41.9731871]},"n1819848932":{"id":"n1819848932","loc":[-85.640906,41.9508575]},"n1819848933":{"id":"n1819848933","loc":[-85.649775,41.9799767]},"n1819848934":{"id":"n1819848934","loc":[-85.6507014,41.9739927]},"n1819848937":{"id":"n1819848937","loc":[-85.6479763,41.9840899]},"n1819848938":{"id":"n1819848938","loc":[-85.6501113,41.9600884]},"n1819848939":{"id":"n1819848939","loc":[-85.6389962,41.9478253]},"n1819848941":{"id":"n1819848941","loc":[-85.637469,41.9445791]},"n1819848942":{"id":"n1819848942","loc":[-85.6494569,41.9601682]},"n1819848943":{"id":"n1819848943","loc":[-85.6368803,41.9439351]},"n1819848945":{"id":"n1819848945","loc":[-85.6474398,41.9724213]},"n1819848946":{"id":"n1819848946","loc":[-85.6382629,41.9463666]},"n1819848948":{"id":"n1819848948","loc":[-85.6489633,41.9830771]},"n1819848952":{"id":"n1819848952","loc":[-85.6488882,41.9600326]},"n1819848953":{"id":"n1819848953","loc":[-85.6488094,41.9774324]},"n1819848954":{"id":"n1819848954","loc":[-85.6491135,41.9600485]},"n1819848955":{"id":"n1819848955","loc":[-85.6501435,41.9734583]},"n1819848956":{"id":"n1819848956","loc":[-85.6495534,41.960958]},"n1819848958":{"id":"n1819848958","loc":[-85.6474683,41.9561491]},"n1819848959":{"id":"n1819848959","loc":[-85.6401083,41.9485451]},"n1819848960":{"id":"n1819848960","loc":[-85.6481764,41.9678686]},"n1819848961":{"id":"n1819848961","loc":[-85.6484017,41.967382]},"n1819848962":{"id":"n1819848962","loc":[-85.6501328,41.959897]},"n1819848964":{"id":"n1819848964","loc":[-85.6403695,41.9504586]},"n1819848966":{"id":"n1819848966","loc":[-85.6398975,41.9491499]},"n1819848967":{"id":"n1819848967","loc":[-85.6412455,41.9510187]},"n1819848968":{"id":"n1819848968","loc":[-85.6482622,41.9619493]},"n1819848969":{"id":"n1819848969","loc":[-85.6405841,41.9501474]},"n1819848970":{"id":"n1819848970","loc":[-85.6478583,41.9703394]},"n1819848971":{"id":"n1819848971","loc":[-85.6493388,41.9832845]},"n1819848972":{"id":"n1819848972","loc":[-85.6485664,41.9829415]},"n1819848974":{"id":"n1819848974","loc":[-85.6491457,41.9779887]},"n1819848975":{"id":"n1819848975","loc":[-85.6468889,41.9697033]},"n1819848976":{"id":"n1819848976","loc":[-85.6452726,41.9546072]},"n1819848977":{"id":"n1819848977","loc":[-85.6448435,41.9546072]},"n1819848979":{"id":"n1819848979","loc":[-85.6485342,41.9763138]},"n1819848980":{"id":"n1819848980","loc":[-85.6495282,41.9664087]},"n1819848986":{"id":"n1819848986","loc":[-85.6486307,41.9603278]},"n1819848987":{"id":"n1819848987","loc":[-85.6492278,41.9791871]},"n1819848990":{"id":"n1819848990","loc":[-85.6501934,41.9800724]},"n1819848992":{"id":"n1819848992","loc":[-85.6482445,41.9819685]},"n1819848993":{"id":"n1819848993","loc":[-85.6481871,41.9704451]},"n1819848994":{"id":"n1819848994","loc":[-85.6371364,41.9457602]},"n1819848996":{"id":"n1819848996","loc":[-85.6500362,41.9801023]},"n1819849000":{"id":"n1819849000","loc":[-85.639007,41.9485914]},"n1819849001":{"id":"n1819849001","loc":[-85.6488882,41.9669253]},"n1819849002":{"id":"n1819849002","loc":[-85.6484698,41.9565062]},"n1819849004":{"id":"n1819849004","loc":[-85.6510769,41.9761064]},"n1819849005":{"id":"n1819849005","loc":[-85.6503581,41.9799029]},"n1819849006":{"id":"n1819849006","loc":[-85.6489381,41.9703893]},"n1819849008":{"id":"n1819849008","loc":[-85.6497457,41.9833588]},"n1819849011":{"id":"n1819849011","loc":[-85.6497358,41.9717593]},"n1819849012":{"id":"n1819849012","loc":[-85.6494676,41.9796796]},"n1819849019":{"id":"n1819849019","loc":[-85.6486093,41.9771034]},"n1819849021":{"id":"n1819849021","loc":[-85.6504546,41.9796556]},"n1819849022":{"id":"n1819849022","loc":[-85.6371294,41.9454154]},"n1819849023":{"id":"n1819849023","loc":[-85.6503436,41.9759249]},"n1819849025":{"id":"n1819849025","loc":[-85.6462382,41.9693822]},"n1819849026":{"id":"n1819849026","loc":[-85.6497573,41.983093]},"n1819849028":{"id":"n1819849028","loc":[-85.6497465,41.9602799]},"n1819849029":{"id":"n1819849029","loc":[-85.6374728,41.9460698]},"n1819849030":{"id":"n1819849030","loc":[-85.6486592,41.9566039]},"n1819849031":{"id":"n1819849031","loc":[-85.6515989,41.9654993]},"n1819849032":{"id":"n1819849032","loc":[-85.6387028,41.9482658]},"n1819849033":{"id":"n1819849033","loc":[-85.6464742,41.9688398]},"n1819849034":{"id":"n1819849034","loc":[-85.6495212,41.9589236]},"n1819849035":{"id":"n1819849035","loc":[-85.6490599,41.9790096]},"n1819849036":{"id":"n1819849036","loc":[-85.6489918,41.9800724]},"n1819849038":{"id":"n1819849038","loc":[-85.6499182,41.9659042]},"n1819849040":{"id":"n1819849040","loc":[-85.639758,41.9490143]},"n1819849041":{"id":"n1819849041","loc":[-85.6514846,41.9755241]},"n1819849042":{"id":"n1819849042","loc":[-85.6436633,41.9540647]},"n1819849045":{"id":"n1819849045","loc":[-85.6475541,41.9726387]},"n1819849046":{"id":"n1819849046","loc":[-85.6488308,41.9718331]},"n1819849047":{"id":"n1819849047","loc":[-85.6377694,41.9460953]},"n1819849048":{"id":"n1819849048","loc":[-85.6490706,41.9804452]},"n1819849049":{"id":"n1819849049","loc":[-85.6485449,41.9766248]},"n1819849051":{"id":"n1819849051","loc":[-85.6483625,41.9790256]},"n1819849052":{"id":"n1819849052","loc":[-85.6490706,41.9585167]},"n1819849053":{"id":"n1819849053","loc":[-85.6425008,41.9522874]},"n1819849054":{"id":"n1819849054","loc":[-85.6475793,41.9632158]},"n1819849055":{"id":"n1819849055","loc":[-85.6408631,41.9499399]},"n1819849056":{"id":"n1819849056","loc":[-85.6483373,41.9814681]},"n1819849057":{"id":"n1819849057","loc":[-85.6313548,41.9442876]},"n1819849058":{"id":"n1819849058","loc":[-85.6432663,41.9529796]},"n1819849059":{"id":"n1819849059","loc":[-85.6487128,41.9582873]},"n1819849060":{"id":"n1819849060","loc":[-85.6482338,41.9817612]},"n1819849062":{"id":"n1819849062","loc":[-85.6485664,41.9788661]},"n1819849063":{"id":"n1819849063","loc":[-85.6373081,41.9448824]},"n1819849064":{"id":"n1819849064","loc":[-85.6472215,41.9557582]},"n1819849065":{"id":"n1819849065","loc":[-85.6348984,41.9440414]},"n1819849066":{"id":"n1819849066","loc":[-85.6501972,41.9647315]},"n1819849067":{"id":"n1819849067","loc":[-85.6489741,41.9808281]},"n1819849068":{"id":"n1819849068","loc":[-85.6420111,41.9515034]},"n1819849069":{"id":"n1819849069","loc":[-85.6397972,41.9488882]},"n1819849070":{"id":"n1819849070","loc":[-85.6499718,41.9593465]},"n1819849071":{"id":"n1819849071","loc":[-85.6486844,41.9811311]},"n1819849072":{"id":"n1819849072","loc":[-85.6390392,41.9474663]},"n1819849074":{"id":"n1819849074","loc":[-85.6495642,41.9616362]},"n1819849075":{"id":"n1819849075","loc":[-85.6483518,41.9791931]},"n1819849076":{"id":"n1819849076","loc":[-85.6478974,41.9833104]},"n1819849077":{"id":"n1819849077","loc":[-85.640155,41.948719]},"n1819849078":{"id":"n1819849078","loc":[-85.6399366,41.9487845]},"n1819849079":{"id":"n1819849079","loc":[-85.6492959,41.9825348]},"n1819849080":{"id":"n1819849080","loc":[-85.6505083,41.9648352]},"n1819849081":{"id":"n1819849081","loc":[-85.6492959,41.9645241]},"n1819849082":{"id":"n1819849082","loc":[-85.6402049,41.9491835]},"n1819849083":{"id":"n1819849083","loc":[-85.6495175,41.9826963]},"n1819849084":{"id":"n1819849084","loc":[-85.6480836,41.9728361]},"n1819849085":{"id":"n1819849085","loc":[-85.6374349,41.9443425]},"n1819849086":{"id":"n1819849086","loc":[-85.6478331,41.9681238]},"n1819849089":{"id":"n1819849089","loc":[-85.639368,41.9486169]},"n1819849092":{"id":"n1819849092","loc":[-85.6503581,41.9788022]},"n1819849093":{"id":"n1819849093","loc":[-85.64862,41.9568014]},"n1819849094":{"id":"n1819849094","loc":[-85.6496999,41.9828877]},"n1819849095":{"id":"n1819849095","loc":[-85.647472,41.972198]},"n1819849096":{"id":"n1819849096","loc":[-85.6485771,41.9644523]},"n1819849097":{"id":"n1819849097","loc":[-85.6388353,41.9480488]},"n1819849099":{"id":"n1819849099","loc":[-85.6472752,41.9683312]},"n1819849104":{"id":"n1819849104","loc":[-85.6479548,41.9836035]},"n1819849105":{"id":"n1819849105","loc":[-85.6462489,41.9691668]},"n1819849107":{"id":"n1819849107","loc":[-85.6511912,41.9746328]},"n1819849108":{"id":"n1819849108","loc":[-85.6498646,41.9714881]},"n1819849111":{"id":"n1819849111","loc":[-85.6488239,41.961684]},"n1819849112":{"id":"n1819849112","loc":[-85.6469356,41.9553812]},"n1819849114":{"id":"n1819849114","loc":[-85.6479548,41.9640853]},"n1819849119":{"id":"n1819849119","loc":[-85.6491565,41.961692]},"n1819849121":{"id":"n1819849121","loc":[-85.651667,41.9656728]},"n1819849124":{"id":"n1819849124","loc":[-85.6388423,41.9484414]},"n1819849126":{"id":"n1819849126","loc":[-85.6371686,41.9450978]},"n1819849127":{"id":"n1819849127","loc":[-85.6502615,41.9656728]},"n1819849129":{"id":"n1819849129","loc":[-85.6498501,41.9613031]},"n1819849131":{"id":"n1819849131","loc":[-85.6513881,41.9653298]},"n1819849133":{"id":"n1819849133","loc":[-85.639883,41.9485291]},"n1819849139":{"id":"n1819849139","loc":[-85.6508693,41.9658264]},"n1819849140":{"id":"n1819849140","loc":[-85.6486806,41.9761642]},"n1819849141":{"id":"n1819849141","loc":[-85.6483159,41.9717613]},"n1819849144":{"id":"n1819849144","loc":[-85.6443714,41.9546232]},"n1819849146":{"id":"n1819849146","loc":[-85.641775,41.9513359]},"n1819849147":{"id":"n1819849147","loc":[-85.6495604,41.9757335]},"n1819849148":{"id":"n1819849148","loc":[-85.6465671,41.9551678]},"n1819849150":{"id":"n1819849150","loc":[-85.6485127,41.9794084]},"n1819849151":{"id":"n1819849151","loc":[-85.6499144,41.9757096]},"n1819849152":{"id":"n1819849152","loc":[-85.6433736,41.9531072]},"n1819849154":{"id":"n1819849154","loc":[-85.6489741,41.9607426]},"n1819849155":{"id":"n1819849155","loc":[-85.640627,41.9507697]},"n1819849156":{"id":"n1819849156","loc":[-85.6509659,41.9743058]},"n1819849157":{"id":"n1819849157","loc":[-85.6486844,41.9704431]},"n1819849158":{"id":"n1819849158","loc":[-85.6498538,41.9711132]},"n1819849159":{"id":"n1819849159","loc":[-85.6358937,41.943719]},"n1819849160":{"id":"n1819849160","loc":[-85.6497358,41.9707702]},"n1819849161":{"id":"n1819849161","loc":[-85.6480476,41.9564842]},"n1819849162":{"id":"n1819849162","loc":[-85.6482982,41.9574556]},"n1819849163":{"id":"n1819849163","loc":[-85.6501757,41.9757794]},"n1819849164":{"id":"n1819849164","loc":[-85.6372973,41.9459916]},"n1819849165":{"id":"n1819849165","loc":[-85.6513773,41.9750775]},"n1819849166":{"id":"n1819849166","loc":[-85.6436418,41.9537455]},"n1819849167":{"id":"n1819849167","loc":[-85.6483625,41.9571524]},"n1819849169":{"id":"n1819849169","loc":[-85.647751,41.9727962]},"n1819849170":{"id":"n1819849170","loc":[-85.6504546,41.9656808]},"n1819849171":{"id":"n1819849171","loc":[-85.6479977,41.971839]},"n1819849172":{"id":"n1819849172","loc":[-85.6482767,41.9642449]},"n1819849174":{"id":"n1819849174","loc":[-85.6414317,41.9512086]},"n1819849176":{"id":"n1819849176","loc":[-85.6469034,41.9685287]},"n1819849179":{"id":"n1819849179","loc":[-85.6408631,41.9497564]},"n1819849182":{"id":"n1819849182","loc":[-85.6476721,41.96384]},"n1819849183":{"id":"n1819849183","loc":[-85.6479725,41.983111]},"n1819849184":{"id":"n1819849184","loc":[-85.640788,41.9500516]},"n1819849185":{"id":"n1819849185","loc":[-85.6427798,41.9528778]},"n1819849186":{"id":"n1819849186","loc":[-85.6435308,41.9534124]},"n1819849187":{"id":"n1819849187","loc":[-85.6483733,41.9821998]},"n1819849189":{"id":"n1819849189","loc":[-85.6351752,41.9440796]},"n1819849191":{"id":"n1819849191","loc":[-85.6487021,41.9601463]},"n1819849192":{"id":"n1819849192","loc":[-85.6363811,41.9437605]},"n1819849193":{"id":"n1819849193","loc":[-85.6490883,41.9759728]},"n1819849194":{"id":"n1819849194","loc":[-85.6423292,41.9520081]},"n1819849195":{"id":"n1819849195","loc":[-85.6500003,41.960242]},"n1819849196":{"id":"n1819849196","loc":[-85.6385778,41.9466443]},"n1819849197":{"id":"n1819849197","loc":[-85.6494032,41.9718789]},"n1819849198":{"id":"n1819849198","loc":[-85.6404339,41.9506501]},"n1819849199":{"id":"n1819849199","loc":[-85.6426226,41.9527083]},"n1819849200":{"id":"n1819849200","loc":[-85.6439101,41.9545035]},"n1819849201":{"id":"n1819849201","loc":[-85.6516563,41.9657845]},"n1819849202":{"id":"n1819849202","loc":[-85.6473395,41.9699585]},"n1819858501":{"id":"n1819858501","loc":[-85.6361263,41.9437126]},"n1819858503":{"id":"n1819858503","loc":[-85.6350068,41.944034]},"n1819858513":{"id":"n1819858513","loc":[-85.6371402,41.9453282]},"n1819858518":{"id":"n1819858518","loc":[-85.6348713,41.9432923]},"n1819858523":{"id":"n1819858523","loc":[-85.6357047,41.943799]},"n1819858526":{"id":"n1819858526","loc":[-85.6349947,41.9435756]},"n1819858531":{"id":"n1819858531","loc":[-85.6350376,41.943827]},"n1820937508":{"id":"n1820937508","loc":[-85.1026013,42.0881722]},"n1820937509":{"id":"n1820937509","loc":[-85.0558088,42.102493]},"n1820937511":{"id":"n1820937511","loc":[-85.3030116,41.9724451]},"n1820937513":{"id":"n1820937513","loc":[-85.0353221,42.1027398]},"n1820937514":{"id":"n1820937514","loc":[-85.0835468,42.1015469]},"n1820937515":{"id":"n1820937515","loc":[-85.2421298,42.0106305]},"n1820937517":{"id":"n1820937517","loc":[-85.0090632,42.0910452]},"n1820937518":{"id":"n1820937518","loc":[-85.086626,42.0948838]},"n1820937520":{"id":"n1820937520","loc":[-85.2552039,42.0015448]},"n1820937521":{"id":"n1820937521","loc":[-85.3739614,41.9969917]},"n1820937522":{"id":"n1820937522","loc":[-85.4831166,41.993898]},"n1820937523":{"id":"n1820937523","loc":[-85.0341084,42.0977657]},"n1820937524":{"id":"n1820937524","loc":[-85.3272802,41.9710333]},"n1820937525":{"id":"n1820937525","loc":[-85.2125568,42.0414521]},"n1820937526":{"id":"n1820937526","loc":[-85.3798022,41.9992458]},"n1820937527":{"id":"n1820937527","loc":[-85.2652021,41.999768]},"n1820937528":{"id":"n1820937528","loc":[-85.3852739,42.0004896]},"n1820937529":{"id":"n1820937529","loc":[-85.3911919,42.0030513]},"n1820937530":{"id":"n1820937530","loc":[-85.5440349,41.9717109]},"n1820937531":{"id":"n1820937531","loc":[-85.2790155,41.9911764]},"n1820937532":{"id":"n1820937532","loc":[-85.4723277,41.9950518]},"n1820937533":{"id":"n1820937533","loc":[-85.5690546,41.9653931]},"n1820937535":{"id":"n1820937535","loc":[-85.5674882,41.9649623]},"n1820937536":{"id":"n1820937536","loc":[-85.6362815,41.9189165]},"n1820937537":{"id":"n1820937537","loc":[-85.5659003,41.963638]},"n1820937539":{"id":"n1820937539","loc":[-85.6391353,41.9122262]},"n1820937540":{"id":"n1820937540","loc":[-85.4834385,41.9894803]},"n1820937541":{"id":"n1820937541","loc":[-85.6399078,41.9160744]},"n1820937542":{"id":"n1820937542","loc":[-85.632874,41.941031]},"n1820937543":{"id":"n1820937543","loc":[-85.1307591,42.0726961]},"n1820937544":{"id":"n1820937544","loc":[-85.6444397,41.9128378]},"n1820937545":{"id":"n1820937545","loc":[-85.6197204,41.9420365]},"n1820937546":{"id":"n1820937546","loc":[-85.1164857,42.0864631]},"n1820937547":{"id":"n1820937547","loc":[-85.6476111,41.9142222]},"n1820937548":{"id":"n1820937548","loc":[-85.2915747,41.9774223]},"n1820937549":{"id":"n1820937549","loc":[-85.6430192,41.9102461]},"n1820937550":{"id":"n1820937550","loc":[-85.1597495,42.0639017]},"n1820937551":{"id":"n1820937551","loc":[-85.5504079,41.9701793]},"n1820937553":{"id":"n1820937553","loc":[-85.2781317,41.9948951]},"n1820937555":{"id":"n1820937555","loc":[-85.3724594,41.997518]},"n1820937556":{"id":"n1820937556","loc":[-85.5629434,41.9665155]},"n1820937557":{"id":"n1820937557","loc":[-85.3791971,41.9990808]},"n1820937558":{"id":"n1820937558","loc":[-85.001891,42.0878843]},"n1820937560":{"id":"n1820937560","loc":[-85.3140838,41.9709056]},"n1820937561":{"id":"n1820937561","loc":[-85.2468032,42.0146987]},"n1820937563":{"id":"n1820937563","loc":[-85.0877378,42.097255]},"n1820937564":{"id":"n1820937564","loc":[-85.2442498,42.0150654]},"n1820937566":{"id":"n1820937566","loc":[-85.3108973,41.9701478]},"n1820937568":{"id":"n1820937568","loc":[-85.0344584,42.1016572]},"n1820937569":{"id":"n1820937569","loc":[-85.2331025,42.0297387]},"n1820937570":{"id":"n1820937570","loc":[-85.5058446,41.9746996]},"n1820937571":{"id":"n1820937571","loc":[-85.5622739,41.9676427]},"n1820937572":{"id":"n1820937572","loc":[-85.2792687,41.9890337]},"n1820937574":{"id":"n1820937574","loc":[-84.9909302,42.08695]},"n1820937575":{"id":"n1820937575","loc":[-85.6218233,41.9418609]},"n1820937576":{"id":"n1820937576","loc":[-85.3577437,41.9931062]},"n1820937577":{"id":"n1820937577","loc":[-85.639028,41.9165853]},"n1820937578":{"id":"n1820937578","loc":[-84.9956576,42.0865348]},"n1820937579":{"id":"n1820937579","loc":[-85.4828376,41.990198]},"n1820937580":{"id":"n1820937580","loc":[-85.3244478,41.9720543]},"n1820937582":{"id":"n1820937582","loc":[-85.0517479,42.1035159]},"n1820937583":{"id":"n1820937583","loc":[-85.225646,42.0338025]},"n1820937584":{"id":"n1820937584","loc":[-84.9941019,42.0862163]},"n1820937586":{"id":"n1820937586","loc":[-85.1051762,42.0879452]},"n1820937587":{"id":"n1820937587","loc":[-85.1245203,42.0753162]},"n1820937588":{"id":"n1820937588","loc":[-85.3250808,41.9719506]},"n1820937589":{"id":"n1820937589","loc":[-85.2720109,41.997933]},"n1820937590":{"id":"n1820937590","loc":[-85.2556653,42.0027248]},"n1820937591":{"id":"n1820937591","loc":[-85.0872483,42.0943544]},"n1820937592":{"id":"n1820937592","loc":[-85.2778353,41.9955023]},"n1820937593":{"id":"n1820937593","loc":[-85.2984733,41.9735538]},"n1820937594":{"id":"n1820937594","loc":[-85.101578,42.0889552]},"n1820937595":{"id":"n1820937595","loc":[-85.3888745,42.0016959]},"n1820937596":{"id":"n1820937596","loc":[-84.9903508,42.0870654]},"n1820937597":{"id":"n1820937597","loc":[-85.6405558,41.9146261]},"n1820937598":{"id":"n1820937598","loc":[-85.6460704,41.9141311]},"n1820937599":{"id":"n1820937599","loc":[-85.0377468,42.1037428]},"n1820937600":{"id":"n1820937600","loc":[-85.2298345,42.0312899]},"n1820937601":{"id":"n1820937601","loc":[-85.1080958,42.0861964]},"n1820937602":{"id":"n1820937602","loc":[-85.6325307,41.9402329]},"n1820937603":{"id":"n1820937603","loc":[-85.1165984,42.0832184]},"n1820937604":{"id":"n1820937604","loc":[-85.6354446,41.9190602]},"n1820937605":{"id":"n1820937605","loc":[-85.1114592,42.0862959]},"n1820937606":{"id":"n1820937606","loc":[-85.0858763,42.1001646]},"n1820937607":{"id":"n1820937607","loc":[-85.0472083,42.1015151]},"n1820937608":{"id":"n1820937608","loc":[-85.0802477,42.1027609]},"n1820937610":{"id":"n1820937610","loc":[-85.0924585,42.0928564]},"n1820937611":{"id":"n1820937611","loc":[-85.0329617,42.09827]},"n1820937612":{"id":"n1820937612","loc":[-85.2814617,41.993465]},"n1820937613":{"id":"n1820937613","loc":[-85.3097708,41.9700282]},"n1820937614":{"id":"n1820937614","loc":[-85.2809427,41.993695]},"n1820937615":{"id":"n1820937615","loc":[-85.0583233,42.1026494]},"n1820937617":{"id":"n1820937617","loc":[-85.2801592,41.9840021]},"n1820937619":{"id":"n1820937619","loc":[-85.1064154,42.0863449]},"n1820937620":{"id":"n1820937620","loc":[-85.0423173,42.1014662]},"n1820937621":{"id":"n1820937621","loc":[-85.2168913,42.0398107]},"n1820937622":{"id":"n1820937622","loc":[-85.2798481,41.9833401]},"n1820937623":{"id":"n1820937623","loc":[-85.0575468,42.1028672]},"n1820937625":{"id":"n1820937625","loc":[-85.0130369,42.0893067]},"n1820937626":{"id":"n1820937626","loc":[-85.0346985,42.1018256]},"n1820937627":{"id":"n1820937627","loc":[-85.2231569,42.0372768]},"n1820937628":{"id":"n1820937628","loc":[-85.2956195,41.9732268]},"n1820937629":{"id":"n1820937629","loc":[-85.1052312,42.086893]},"n1820937630":{"id":"n1820937630","loc":[-85.4813356,41.9958436]},"n1820937631":{"id":"n1820937631","loc":[-85.0961599,42.0914672]},"n1820937632":{"id":"n1820937632","loc":[-85.308419,41.9704749]},"n1820937633":{"id":"n1820937633","loc":[-85.295952,41.9715119]},"n1820937634":{"id":"n1820937634","loc":[-85.3310933,41.9703923]},"n1820937635":{"id":"n1820937635","loc":[-85.2940745,41.9739686]},"n1820937636":{"id":"n1820937636","loc":[-85.3803343,42.000484]},"n1820937637":{"id":"n1820937637","loc":[-85.1174231,42.0845533]},"n1820937638":{"id":"n1820937638","loc":[-85.0095836,42.089839]},"n1820937639":{"id":"n1820937639","loc":[-85.3179354,41.9705866]},"n1820937640":{"id":"n1820937640","loc":[-85.257708,42.0001189]},"n1820937641":{"id":"n1820937641","loc":[-85.2563522,42.0002771]},"n1820937642":{"id":"n1820937642","loc":[-85.3181929,41.970419]},"n1820937643":{"id":"n1820937643","loc":[-85.2911884,41.9757154]},"n1820937644":{"id":"n1820937644","loc":[-85.2714423,41.9975862]},"n1820937645":{"id":"n1820937645","loc":[-85.0193669,42.089888]},"n1820937646":{"id":"n1820937646","loc":[-85.3889818,42.0039921]},"n1820937647":{"id":"n1820937647","loc":[-85.3408093,41.9853965]},"n1820937648":{"id":"n1820937648","loc":[-85.1258091,42.0748332]},"n1820937649":{"id":"n1820937649","loc":[-85.5722561,41.962782]},"n1820937650":{"id":"n1820937650","loc":[-85.3266902,41.9721819]},"n1820937651":{"id":"n1820937651","loc":[-85.1473255,42.065192]},"n1820937652":{"id":"n1820937652","loc":[-85.1462526,42.0655106]},"n1820937653":{"id":"n1820937653","loc":[-85.4641051,42.0013929]},"n1820937654":{"id":"n1820937654","loc":[-85.5620379,41.9700677]},"n1820937655":{"id":"n1820937655","loc":[-85.3226025,41.971121]},"n1820937656":{"id":"n1820937656","loc":[-85.0200965,42.0899516]},"n1820937657":{"id":"n1820937657","loc":[-85.0624714,42.1044711]},"n1820937658":{"id":"n1820937658","loc":[-85.5649562,41.9637178]},"n1820937659":{"id":"n1820937659","loc":[-85.2360315,42.0253315]},"n1820937660":{"id":"n1820937660","loc":[-85.3881449,41.9994475]},"n1820937661":{"id":"n1820937661","loc":[-85.5032911,41.976263]},"n1820937662":{"id":"n1820937662","loc":[-85.481297,41.9871414]},"n1820937663":{"id":"n1820937663","loc":[-85.1167056,42.0841898]},"n1820937664":{"id":"n1820937664","loc":[-85.2891714,41.9787223]},"n1820937665":{"id":"n1820937665","loc":[-85.4393429,42.0058736]},"n1820937666":{"id":"n1820937666","loc":[-85.0077007,42.0895762]},"n1820937667":{"id":"n1820937667","loc":[-85.2736202,41.9979171]},"n1820937668":{"id":"n1820937668","loc":[-84.9935332,42.0859296]},"n1820937669":{"id":"n1820937669","loc":[-85.0622769,42.1046713]},"n1820937670":{"id":"n1820937670","loc":[-85.2309031,42.0311249]},"n1820937671":{"id":"n1820937671","loc":[-85.0343726,42.10069]},"n1820937672":{"id":"n1820937672","loc":[-85.0596551,42.1048612]},"n1820937673":{"id":"n1820937673","loc":[-85.1338597,42.0707449]},"n1820937674":{"id":"n1820937674","loc":[-85.3117663,41.9689194]},"n1820937675":{"id":"n1820937675","loc":[-85.0705649,42.1057499]},"n1820937676":{"id":"n1820937676","loc":[-85.2441425,42.0180944]},"n1820937677":{"id":"n1820937677","loc":[-85.1171174,42.0862692]},"n1820937678":{"id":"n1820937678","loc":[-85.0346824,42.1005519]},"n1820937680":{"id":"n1820937680","loc":[-85.2389927,42.0229245]},"n1820937681":{"id":"n1820937681","loc":[-85.0834892,42.1018642]},"n1820937682":{"id":"n1820937682","loc":[-85.0619443,42.1049459]},"n1820937683":{"id":"n1820937683","loc":[-85.2845366,41.9811868]},"n1820937684":{"id":"n1820937684","loc":[-85.210411,42.0394123]},"n1820937685":{"id":"n1820937685","loc":[-85.4377383,42.0055942]},"n1820937686":{"id":"n1820937686","loc":[-85.2882058,41.9789138]},"n1820937687":{"id":"n1820937687","loc":[-85.2741191,41.9955808]},"n1820937688":{"id":"n1820937688","loc":[-85.3442211,41.9903575]},"n1820937689":{"id":"n1820937689","loc":[-85.2641413,41.9995237]},"n1820937690":{"id":"n1820937690","loc":[-85.2804489,41.9829174]},"n1820937691":{"id":"n1820937691","loc":[-85.5593342,41.9729074]},"n1820937692":{"id":"n1820937692","loc":[-85.3590912,41.9932601]},"n1820937694":{"id":"n1820937694","loc":[-85.4826445,41.9957479]},"n1820937695":{"id":"n1820937695","loc":[-85.4539127,42.0063041]},"n1820937696":{"id":"n1820937696","loc":[-85.2456767,42.0153683]},"n1820937697":{"id":"n1820937697","loc":[-85.5794015,41.9489631]},"n1820937698":{"id":"n1820937698","loc":[-85.4108686,42.0078507]},"n1820937699":{"id":"n1820937699","loc":[-85.0616386,42.1051529]},"n1820937700":{"id":"n1820937700","loc":[-85.4977979,41.978241]},"n1820937701":{"id":"n1820937701","loc":[-85.2488417,42.0086319]},"n1820937702":{"id":"n1820937702","loc":[-85.5588836,41.9728116]},"n1820937703":{"id":"n1820937703","loc":[-85.4557366,42.0051241]},"n1820937705":{"id":"n1820937705","loc":[-85.0723151,42.1056094]},"n1820937706":{"id":"n1820937706","loc":[-85.0057909,42.0887323]},"n1820937707":{"id":"n1820937707","loc":[-85.0756786,42.105677]},"n1820937708":{"id":"n1820937708","loc":[-85.0901504,42.0940001]},"n1820937709":{"id":"n1820937709","loc":[-85.0979999,42.0910213]},"n1820937710":{"id":"n1820937710","loc":[-85.2376301,42.0239686]},"n1820937711":{"id":"n1820937711","loc":[-85.2780671,41.9902299]},"n1820937712":{"id":"n1820937712","loc":[-85.251481,42.0113188]},"n1820937713":{"id":"n1820937713","loc":[-85.3114767,41.9690311]},"n1820937714":{"id":"n1820937714","loc":[-85.2649621,41.9975662]},"n1820937715":{"id":"n1820937715","loc":[-85.283807,41.9813383]},"n1820937716":{"id":"n1820937716","loc":[-85.5515451,41.9703867]},"n1820937717":{"id":"n1820937717","loc":[-85.1176605,42.0850896]},"n1820937718":{"id":"n1820937718","loc":[-85.1069317,42.0862441]},"n1820937719":{"id":"n1820937719","loc":[-85.2739314,41.9976938]},"n1820937720":{"id":"n1820937720","loc":[-85.5550212,41.9702112]},"n1820937721":{"id":"n1820937721","loc":[-85.3076679,41.9719904]},"n1820937722":{"id":"n1820937722","loc":[-85.592319,41.9440316]},"n1820937723":{"id":"n1820937723","loc":[-85.3139979,41.9704031]},"n1820937724":{"id":"n1820937724","loc":[-85.0421134,42.1013149]},"n1820937725":{"id":"n1820937725","loc":[-85.2508373,42.0102741]},"n1820937726":{"id":"n1820937726","loc":[-85.0830922,42.1038821]},"n1820937727":{"id":"n1820937727","loc":[-85.6342473,41.9360031]},"n1820937730":{"id":"n1820937730","loc":[-85.0500192,42.1024942]},"n1820937731":{"id":"n1820937731","loc":[-85.3498644,41.9926221]},"n1820937732":{"id":"n1820937732","loc":[-85.0234117,42.0918903]},"n1820937733":{"id":"n1820937733","loc":[-85.0464425,42.1009408]},"n1820937734":{"id":"n1820937734","loc":[-85.033938,42.099886]},"n1820937736":{"id":"n1820937736","loc":[-85.0152752,42.0886009]},"n1820937737":{"id":"n1820937737","loc":[-85.0441894,42.1012671]},"n1820937738":{"id":"n1820937738","loc":[-85.4668731,41.9979804]},"n1820937739":{"id":"n1820937739","loc":[-85.4407377,42.006033]},"n1820937740":{"id":"n1820937740","loc":[-85.2262253,42.0344878]},"n1820937741":{"id":"n1820937741","loc":[-85.2550001,42.0033706]},"n1820937742":{"id":"n1820937742","loc":[-85.3071422,41.9722617]},"n1820937743":{"id":"n1820937743","loc":[-85.6147852,41.942228]},"n1820937744":{"id":"n1820937744","loc":[-85.0183853,42.0901825]},"n1820937745":{"id":"n1820937745","loc":[-85.6323161,41.9228489]},"n1820937746":{"id":"n1820937746","loc":[-85.0095568,42.0901376]},"n1820937747":{"id":"n1820937747","loc":[-85.2524037,42.0113826]},"n1820937748":{"id":"n1820937748","loc":[-85.3186864,41.9708578]},"n1820937749":{"id":"n1820937749","loc":[-85.2805669,41.9870883]},"n1820937750":{"id":"n1820937750","loc":[-85.0585768,42.1038144]},"n1820937751":{"id":"n1820937751","loc":[-85.2970786,41.9715358]},"n1820937752":{"id":"n1820937752","loc":[-85.1315758,42.0723445]},"n1820937753":{"id":"n1820937753","loc":[-85.2448291,42.0175444]},"n1820937754":{"id":"n1820937754","loc":[-85.2446468,42.0174248]},"n1820937755":{"id":"n1820937755","loc":[-85.229165,42.032129]},"n1820937756":{"id":"n1820937756","loc":[-85.5612654,41.9724926]},"n1820937757":{"id":"n1820937757","loc":[-85.2331776,42.030854]},"n1820937758":{"id":"n1820937758","loc":[-85.2271909,42.0334519]},"n1820937759":{"id":"n1820937759","loc":[-85.1032396,42.0879214]},"n1820937760":{"id":"n1820937760","loc":[-85.0638447,42.1044154]},"n1820937761":{"id":"n1820937761","loc":[-85.1260706,42.0745556]},"n1820937762":{"id":"n1820937762","loc":[-85.3454485,41.99132]},"n1820937763":{"id":"n1820937763","loc":[-85.2639321,41.9980088]},"n1820937764":{"id":"n1820937764","loc":[-85.0837681,42.1013746]},"n1820937765":{"id":"n1820937765","loc":[-85.2808137,41.9869368]},"n1820937766":{"id":"n1820937766","loc":[-85.6338997,41.9309373]},"n1820937767":{"id":"n1820937767","loc":[-85.2267403,42.0332766]},"n1820937768":{"id":"n1820937768","loc":[-85.0605831,42.1052074]},"n1820937769":{"id":"n1820937769","loc":[-85.0259021,42.0930037]},"n1820937770":{"id":"n1820937770","loc":[-85.232963,42.0313162]},"n1820937771":{"id":"n1820937771","loc":[-85.2404947,42.0125381]},"n1820937772":{"id":"n1820937772","loc":[-85.0910892,42.0935742]},"n1820937773":{"id":"n1820937773","loc":[-85.2554829,42.0019435]},"n1820937774":{"id":"n1820937774","loc":[-85.2799339,41.9867773]},"n1820937775":{"id":"n1820937775","loc":[-85.1075432,42.0852767]},"n1820937776":{"id":"n1820937776","loc":[-85.1176927,42.0854001]},"n1820937777":{"id":"n1820937777","loc":[-85.1067064,42.0863357]},"n1820937778":{"id":"n1820937778","loc":[-85.2517492,42.0106333]},"n1820937779":{"id":"n1820937779","loc":[-85.0987174,42.0909031]},"n1820937780":{"id":"n1820937780","loc":[-85.1160083,42.0863994]},"n1820937781":{"id":"n1820937781","loc":[-85.1268645,42.0739703]},"n1820937782":{"id":"n1820937782","loc":[-85.0454702,42.1002852]},"n1820937783":{"id":"n1820937783","loc":[-85.1334145,42.0705418]},"n1820937784":{"id":"n1820937784","loc":[-85.5866542,41.947431]},"n1820937786":{"id":"n1820937786","loc":[-85.2359886,42.0250366]},"n1820937787":{"id":"n1820937787","loc":[-85.3138048,41.9698527]},"n1820937788":{"id":"n1820937788","loc":[-85.1274291,42.0733081]},"n1820937790":{"id":"n1820937790","loc":[-85.6292905,41.9411267]},"n1820937791":{"id":"n1820937791","loc":[-85.5958809,41.9417333]},"n1820937792":{"id":"n1820937792","loc":[-85.1271019,42.0737581]},"n1820937793":{"id":"n1820937793","loc":[-85.2312679,42.0314437]},"n1820937794":{"id":"n1820937794","loc":[-85.1081387,42.0863516]},"n1820937795":{"id":"n1820937795","loc":[-85.2424473,42.0212109]},"n1820937796":{"id":"n1820937796","loc":[-85.2710654,41.9975236]},"n1820937797":{"id":"n1820937797","loc":[-85.4798408,41.9863223]},"n1820937798":{"id":"n1820937798","loc":[-85.035939,42.104296]},"n1820937799":{"id":"n1820937799","loc":[-85.2178139,42.0395398]},"n1820937800":{"id":"n1820937800","loc":[-85.0630709,42.1042614]},"n1820937801":{"id":"n1820937801","loc":[-85.0440124,42.1014861]},"n1820937802":{"id":"n1820937802","loc":[-85.1321874,42.0720458]},"n1820937804":{"id":"n1820937804","loc":[-85.079427,42.1029121]},"n1820937805":{"id":"n1820937805","loc":[-85.2962632,41.9738968]},"n1820937806":{"id":"n1820937806","loc":[-85.6334748,41.9274627]},"n1820937807":{"id":"n1820937807","loc":[-85.1057341,42.0872804]},"n1820937808":{"id":"n1820937808","loc":[-85.4960169,41.9778263]},"n1820937809":{"id":"n1820937809","loc":[-85.2821226,41.9910273]},"n1820937810":{"id":"n1820937810","loc":[-85.0013868,42.0885054]},"n1820937811":{"id":"n1820937811","loc":[-85.2952547,41.9729795]},"n1820937812":{"id":"n1820937812","loc":[-85.1298375,42.0667842]},"n1820937813":{"id":"n1820937813","loc":[-85.1339201,42.0710025]},"n1820937814":{"id":"n1820937814","loc":[-85.0374356,42.103691]},"n1820937815":{"id":"n1820937815","loc":[-85.0061115,42.0880607]},"n1820937817":{"id":"n1820937817","loc":[-85.2398402,42.0226934]},"n1820937818":{"id":"n1820937818","loc":[-85.123501,42.076236]},"n1820937819":{"id":"n1820937819","loc":[-85.1209489,42.0791294]},"n1820937820":{"id":"n1820937820","loc":[-85.0818624,42.1025778]},"n1820937821":{"id":"n1820937821","loc":[-85.4428835,42.0054749]},"n1820937822":{"id":"n1820937822","loc":[-85.4710359,41.9961147]},"n1820937823":{"id":"n1820937823","loc":[-85.4253354,42.006198]},"n1820937824":{"id":"n1820937824","loc":[-85.5486483,41.9709451]},"n1820937825":{"id":"n1820937825","loc":[-85.2303238,42.0310452]},"n1820937826":{"id":"n1820937826","loc":[-85.6450405,41.9136361]},"n1820937828":{"id":"n1820937828","loc":[-85.2606853,41.9964073]},"n1820937830":{"id":"n1820937830","loc":[-85.097383,42.0911447]},"n1820937831":{"id":"n1820937831","loc":[-85.0498207,42.102136]},"n1820937832":{"id":"n1820937832","loc":[-85.1232435,42.0763793]},"n1820937833":{"id":"n1820937833","loc":[-85.394093,42.0055921]},"n1820937834":{"id":"n1820937834","loc":[-85.3566665,41.9928295]},"n1820937835":{"id":"n1820937835","loc":[-85.3543276,41.9920002]},"n1820937837":{"id":"n1820937837","loc":[-85.084668,42.1034932]},"n1820937838":{"id":"n1820937838","loc":[-85.4400296,42.0060649]},"n1820937839":{"id":"n1820937839","loc":[-85.2362246,42.025714]},"n1820937840":{"id":"n1820937840","loc":[-85.0409225,42.1012791]},"n1820937841":{"id":"n1820937841","loc":[-85.2442283,42.019832]},"n1820937842":{"id":"n1820937842","loc":[-85.1123001,42.084824]},"n1820937843":{"id":"n1820937843","loc":[-85.1603074,42.0638061]},"n1820937844":{"id":"n1820937844","loc":[-85.1359744,42.0650646]},"n1820937845":{"id":"n1820937845","loc":[-85.1757569,42.053849]},"n1820937846":{"id":"n1820937846","loc":[-85.5200925,41.9716686]},"n1820937848":{"id":"n1820937848","loc":[-85.5525322,41.9701315]},"n1820937849":{"id":"n1820937849","loc":[-85.0406489,42.10149]},"n1820937850":{"id":"n1820937850","loc":[-85.0142547,42.088825]},"n1820937851":{"id":"n1820937851","loc":[-85.343749,41.9881884]},"n1820937852":{"id":"n1820937852","loc":[-85.074996,42.1060205]},"n1820937853":{"id":"n1820937853","loc":[-85.2436275,42.0136864]},"n1820937854":{"id":"n1820937854","loc":[-85.2641453,41.9980897]},"n1820937856":{"id":"n1820937856","loc":[-85.2802343,41.9870086]},"n1820937857":{"id":"n1820937857","loc":[-85.0099256,42.0909946]},"n1820937858":{"id":"n1820937858","loc":[-85.493957,41.9786079]},"n1820937859":{"id":"n1820937859","loc":[-85.0739405,42.1059795]},"n1820937860":{"id":"n1820937860","loc":[-85.2331605,42.0301423]},"n1820937862":{"id":"n1820937862","loc":[-85.2035231,42.0438425]},"n1820937863":{"id":"n1820937863","loc":[-85.0884928,42.0986971]},"n1820937864":{"id":"n1820937864","loc":[-85.131597,42.0690142]},"n1820937865":{"id":"n1820937865","loc":[-85.3937454,42.0052677]},"n1820937866":{"id":"n1820937866","loc":[-85.2212729,42.0378561]},"n1820937867":{"id":"n1820937867","loc":[-85.0886068,42.0982421]},"n1820937868":{"id":"n1820937868","loc":[-85.0875004,42.0968064]},"n1820937869":{"id":"n1820937869","loc":[-85.0771323,42.1042642]},"n1820937870":{"id":"n1820937870","loc":[-85.0164554,42.0894887]},"n1820937871":{"id":"n1820937871","loc":[-85.6069102,41.9415577]},"n1820937872":{"id":"n1820937872","loc":[-85.3273875,41.9704908]},"n1820937873":{"id":"n1820937873","loc":[-85.3890891,41.9997983]},"n1820937875":{"id":"n1820937875","loc":[-85.5091276,41.9723705]},"n1820937876":{"id":"n1820937876","loc":[-85.0770626,42.1047696]},"n1820937877":{"id":"n1820937877","loc":[-85.612575,41.9419567]},"n1820937878":{"id":"n1820937878","loc":[-85.3868146,42.0036094]},"n1820937879":{"id":"n1820937879","loc":[-85.2722738,41.9981204]},"n1820937880":{"id":"n1820937880","loc":[-85.3064878,41.9723733]},"n1820937882":{"id":"n1820937882","loc":[-85.1270845,42.0727678]},"n1820937884":{"id":"n1820937884","loc":[-85.3316512,41.97923]},"n1820937885":{"id":"n1820937885","loc":[-85.3932519,42.0042472]},"n1820937886":{"id":"n1820937886","loc":[-85.2457411,42.0175444]},"n1820937887":{"id":"n1820937887","loc":[-85.1397509,42.0648415]},"n1820937891":{"id":"n1820937891","loc":[-85.3196735,41.9719665]},"n1820937892":{"id":"n1820937892","loc":[-85.3372473,41.9845033]},"n1820937894":{"id":"n1820937894","loc":[-85.3254778,41.9719745]},"n1820937897":{"id":"n1820937897","loc":[-85.3185148,41.9691268]},"n1820937899":{"id":"n1820937899","loc":[-85.5419106,41.9714556]},"n1820937901":{"id":"n1820937901","loc":[-85.3293509,41.9748368]},"n1820937903":{"id":"n1820937903","loc":[-85.0798078,42.1028365]},"n1820937905":{"id":"n1820937905","loc":[-85.3954191,42.0056025]},"n1820937909":{"id":"n1820937909","loc":[-85.3417534,41.9857155]},"n1820937913":{"id":"n1820937913","loc":[-84.9927822,42.0857107]},"n1820937915":{"id":"n1820937915","loc":[-85.5444212,41.9712801]},"n1820937917":{"id":"n1820937917","loc":[-85.259088,41.9981682]},"n1820937921":{"id":"n1820937921","loc":[-85.2784576,41.9876358]},"n1820937922":{"id":"n1820937922","loc":[-84.9971918,42.087753]},"n1820937924":{"id":"n1820937924","loc":[-85.5310688,41.966899]},"n1820937928":{"id":"n1820937928","loc":[-85.3766436,41.9979326]},"n1820937930":{"id":"n1820937930","loc":[-85.5494852,41.9704346]},"n1820937933":{"id":"n1820937933","loc":[-85.5548281,41.9695412]},"n1820937935":{"id":"n1820937935","loc":[-85.0768588,42.105088]},"n1820937937":{"id":"n1820937937","loc":[-85.2646885,41.9978054]},"n1820937939":{"id":"n1820937939","loc":[-85.2441532,42.0176082]},"n1820937941":{"id":"n1820937941","loc":[-85.105553,42.0877928]},"n1820937943":{"id":"n1820937943","loc":[-85.0879457,42.0958909]},"n1820937944":{"id":"n1820937944","loc":[-85.3187015,41.9704402]},"n1820937945":{"id":"n1820937945","loc":[-85.5624456,41.970626]},"n1820937946":{"id":"n1820937946","loc":[-85.0580176,42.1028644]},"n1820937948":{"id":"n1820937948","loc":[-85.3016061,41.9726286]},"n1820937949":{"id":"n1820937949","loc":[-85.4310388,42.0069418]},"n1820937950":{"id":"n1820937950","loc":[-85.2945144,41.9740723]},"n1820937951":{"id":"n1820937951","loc":[-85.1170222,42.082657]},"n1820937952":{"id":"n1820937952","loc":[-85.0864503,42.0947632]},"n1820937953":{"id":"n1820937953","loc":[-85.4285926,42.0059533]},"n1820937970":{"id":"n1820937970","loc":[-85.3629965,41.9938023]},"n1820937972":{"id":"n1820937972","loc":[-85.2438099,42.0199755]},"n1820937974":{"id":"n1820937974","loc":[-85.1327654,42.0699285]},"n1820937977":{"id":"n1820937977","loc":[-85.1515956,42.0611935]},"n1820937978":{"id":"n1820937978","loc":[-85.0107369,42.0896638]},"n1820937979":{"id":"n1820937979","loc":[-85.1152626,42.0862083]},"n1820937980":{"id":"n1820937980","loc":[-85.4531831,42.0062881]},"n1820937981":{"id":"n1820937981","loc":[-85.0341473,42.0985924]},"n1820937982":{"id":"n1820937982","loc":[-85.0877485,42.0960171]},"n1820937983":{"id":"n1820937983","loc":[-85.2756373,41.9951742]},"n1820937984":{"id":"n1820937984","loc":[-85.2965421,41.9714401]},"n1820937985":{"id":"n1820937985","loc":[-85.2409775,42.0226934]},"n1820937986":{"id":"n1820937986","loc":[-85.0170723,42.0900579]},"n1820937987":{"id":"n1820937987","loc":[-85.1034663,42.0880555]},"n1820937988":{"id":"n1820937988","loc":[-85.0585071,42.1031577]},"n1820937990":{"id":"n1820937990","loc":[-85.0819174,42.1032373]},"n1820937992":{"id":"n1820937992","loc":[-85.0546608,42.1030542]},"n1820937993":{"id":"n1820937993","loc":[-85.0100811,42.0906125]},"n1820937995":{"id":"n1820937995","loc":[-85.6304278,41.9432655]},"n1820937997":{"id":"n1820937997","loc":[-85.0255628,42.092778]},"n1820938011":{"id":"n1820938011","loc":[-85.2316756,42.0317146]},"n1820938012":{"id":"n1820938012","loc":[-85.4067917,42.008042]},"n1820938013":{"id":"n1820938013","loc":[-85.390398,42.0028759]},"n1820938014":{"id":"n1820938014","loc":[-85.0161604,42.0886527]},"n1820938015":{"id":"n1820938015","loc":[-85.125337,42.0744589]},"n1820938016":{"id":"n1820938016","loc":[-85.2151317,42.0404801]},"n1820938017":{"id":"n1820938017","loc":[-85.3165085,41.9706025]},"n1820938018":{"id":"n1820938018","loc":[-85.5641193,41.9640688]},"n1820938019":{"id":"n1820938019","loc":[-85.147583,42.0642203]},"n1820938022":{"id":"n1820938022","loc":[-85.2803781,41.9947886]},"n1820938024":{"id":"n1820938024","loc":[-85.2692469,41.9982053]},"n1820938026":{"id":"n1820938026","loc":[-85.4321975,42.0067505]},"n1820938028":{"id":"n1820938028","loc":[-85.572535,41.9633405]},"n1820938030":{"id":"n1820938030","loc":[-85.3237505,41.9716475]},"n1820938032":{"id":"n1820938032","loc":[-85.6487698,41.9141583]},"n1820938033":{"id":"n1820938033","loc":[-85.0526371,42.1038315]},"n1820938034":{"id":"n1820938034","loc":[-85.088069,42.0978731]},"n1820938035":{"id":"n1820938035","loc":[-85.2516312,42.0102267]},"n1820938039":{"id":"n1820938039","loc":[-85.2731374,41.9982958]},"n1820938040":{"id":"n1820938040","loc":[-85.5453224,41.9713439]},"n1820938041":{"id":"n1820938041","loc":[-85.4480548,42.0049647]},"n1820938043":{"id":"n1820938043","loc":[-85.2504081,42.010322]},"n1820938045":{"id":"n1820938045","loc":[-85.2663447,41.99919]},"n1820938046":{"id":"n1820938046","loc":[-85.0507287,42.102907]},"n1820938047":{"id":"n1820938047","loc":[-85.0408246,42.1024743]},"n1820938048":{"id":"n1820938048","loc":[-85.2796335,41.9866099]},"n1820938050":{"id":"n1820938050","loc":[-85.452475,42.0061127]},"n1820938051":{"id":"n1820938051","loc":[-85.2410569,42.0128147]},"n1820938052":{"id":"n1820938052","loc":[-85.0413302,42.1011477]},"n1820938053":{"id":"n1820938053","loc":[-85.6327409,41.9197627]},"n1820938056":{"id":"n1820938056","loc":[-85.1072039,42.0857994]},"n1820938057":{"id":"n1820938057","loc":[-85.2001114,42.0448145]},"n1820938058":{"id":"n1820938058","loc":[-85.2655347,41.9978186]},"n1820938059":{"id":"n1820938059","loc":[-85.2330918,42.0304874]},"n1820938060":{"id":"n1820938060","loc":[-85.2601113,41.9966545]},"n1820938061":{"id":"n1820938061","loc":[-85.5397863,41.9708494]},"n1820938062":{"id":"n1820938062","loc":[-85.2702085,41.9977217]},"n1820938063":{"id":"n1820938063","loc":[-85.2219982,42.03699]},"n1820938064":{"id":"n1820938064","loc":[-85.0668957,42.105121]},"n1820938065":{"id":"n1820938065","loc":[-85.2328665,42.0270769]},"n1820938066":{"id":"n1820938066","loc":[-85.3189654,41.9694778]},"n1820938067":{"id":"n1820938067","loc":[-85.3814115,42.0022915]},"n1820938068":{"id":"n1820938068","loc":[-85.2759108,41.9956008]},"n1820938069":{"id":"n1820938069","loc":[-85.0391938,42.1034853]},"n1820938070":{"id":"n1820938070","loc":[-85.2850623,41.9810353]},"n1820938071":{"id":"n1820938071","loc":[-85.538074,41.970855]},"n1820938073":{"id":"n1820938073","loc":[-85.1319661,42.0670932]},"n1820938074":{"id":"n1820938074","loc":[-85.2816763,41.9913678]},"n1820938075":{"id":"n1820938075","loc":[-85.3182144,41.9700282]},"n1820938076":{"id":"n1820938076","loc":[-85.5909028,41.9458989]},"n1820938077":{"id":"n1820938077","loc":[-85.4057617,42.0074361]},"n1820938078":{"id":"n1820938078","loc":[-85.2620438,41.9967729]},"n1820938079":{"id":"n1820938079","loc":[-85.1122143,42.0851107]},"n1820938080":{"id":"n1820938080","loc":[-85.2443785,42.0174567]},"n1820938081":{"id":"n1820938081","loc":[-85.0319733,42.0953853]},"n1820938082":{"id":"n1820938082","loc":[-85.0878276,42.09443]},"n1820938083":{"id":"n1820938083","loc":[-85.0271789,42.0935809]},"n1820938084":{"id":"n1820938084","loc":[-85.0326399,42.0974222]},"n1820938085":{"id":"n1820938085","loc":[-85.3989167,42.0065592]},"n1820938086":{"id":"n1820938086","loc":[-85.3263361,41.9721261]},"n1820938087":{"id":"n1820938087","loc":[-85.2547855,42.0037134]},"n1820938088":{"id":"n1820938088","loc":[-85.4373259,42.005746]},"n1820938089":{"id":"n1820938089","loc":[-85.3094275,41.9699245]},"n1820938090":{"id":"n1820938090","loc":[-85.2783246,41.9872793]},"n1820938092":{"id":"n1820938092","loc":[-85.0815633,42.1025169]},"n1820938093":{"id":"n1820938093","loc":[-85.1788511,42.0522134]},"n1820938095":{"id":"n1820938095","loc":[-85.2830345,41.9816733]},"n1820938096":{"id":"n1820938096","loc":[-85.0744984,42.1059835]},"n1820938097":{"id":"n1820938097","loc":[-85.2788396,41.9879333]},"n1820938098":{"id":"n1820938098","loc":[-85.3640093,41.9946531]},"n1820938099":{"id":"n1820938099","loc":[-85.291167,41.9787463]},"n1820938100":{"id":"n1820938100","loc":[-85.0772436,42.1038156]},"n1820938101":{"id":"n1820938101","loc":[-85.00563,42.0887482]},"n1820938102":{"id":"n1820938102","loc":[-85.0326881,42.0961245]},"n1820938104":{"id":"n1820938104","loc":[-85.0530448,42.1038634]},"n1820938105":{"id":"n1820938105","loc":[-85.2625266,41.9970639]},"n1820938106":{"id":"n1820938106","loc":[-85.2827556,41.9823512]},"n1820938107":{"id":"n1820938107","loc":[-85.2784319,41.9910752]},"n1820938108":{"id":"n1820938108","loc":[-85.0882099,42.094393]},"n1820938109":{"id":"n1820938109","loc":[-85.5718484,41.9645371]},"n1820938110":{"id":"n1820938110","loc":[-85.2559764,42.0099317]},"n1820938111":{"id":"n1820938111","loc":[-85.2969284,41.973179]},"n1820938113":{"id":"n1820938113","loc":[-85.3875055,42.0019726]},"n1820938114":{"id":"n1820938114","loc":[-85.4250779,42.0068199]},"n1820938115":{"id":"n1820938115","loc":[-85.0645367,42.104889]},"n1820938116":{"id":"n1820938116","loc":[-85.1636762,42.0623724]},"n1820938117":{"id":"n1820938117","loc":[-85.0757322,42.1055935]},"n1820938118":{"id":"n1820938118","loc":[-85.3695197,41.9981559]},"n1820938120":{"id":"n1820938120","loc":[-85.1297516,42.0671027]},"n1820938121":{"id":"n1820938121","loc":[-85.1057448,42.0875551]},"n1820938122":{"id":"n1820938122","loc":[-85.2805175,41.9943182]},"n1820938123":{"id":"n1820938123","loc":[-85.2545173,42.0040722]},"n1820938124":{"id":"n1820938124","loc":[-84.9966607,42.0871319]},"n1820938125":{"id":"n1820938125","loc":[-85.0099899,42.0904612]},"n1820938126":{"id":"n1820938126","loc":[-85.2489919,42.0091102]},"n1820938127":{"id":"n1820938127","loc":[-85.0342706,42.0979476]},"n1820938128":{"id":"n1820938128","loc":[-85.1080891,42.0855884]},"n1820938129":{"id":"n1820938129","loc":[-85.0128183,42.0905356]},"n1820938130":{"id":"n1820938130","loc":[-85.631608,41.9434251]},"n1820938131":{"id":"n1820938131","loc":[-85.2551975,42.0008524]},"n1820938132":{"id":"n1820938132","loc":[-85.6421823,41.9096233]},"n1820938133":{"id":"n1820938133","loc":[-85.0125059,42.0906284]},"n1820938134":{"id":"n1820938134","loc":[-85.5499358,41.9701793]},"n1820938135":{"id":"n1820938135","loc":[-85.5472107,41.9712323]},"n1820938136":{"id":"n1820938136","loc":[-85.2760758,41.9958691]},"n1820938137":{"id":"n1820938137","loc":[-85.276678,41.9960433]},"n1820938138":{"id":"n1820938138","loc":[-85.0570319,42.1024731]},"n1820938140":{"id":"n1820938140","loc":[-85.2394325,42.0227492]},"n1820938142":{"id":"n1820938142","loc":[-85.5666341,41.9638829]},"n1820938144":{"id":"n1820938144","loc":[-85.258101,41.9996353]},"n1820938147":{"id":"n1820938147","loc":[-85.2129645,42.0413565]},"n1820938149":{"id":"n1820938149","loc":[-84.9962369,42.0868373]},"n1820938151":{"id":"n1820938151","loc":[-85.2570386,42.0084968]},"n1820938153":{"id":"n1820938153","loc":[-85.3971142,42.0050285]},"n1820938155":{"id":"n1820938155","loc":[-85.1072093,42.0855566]},"n1820938157":{"id":"n1820938157","loc":[-85.2840323,41.9920959]},"n1820938159":{"id":"n1820938159","loc":[-85.1187924,42.0816458]},"n1820938161":{"id":"n1820938161","loc":[-85.2681324,41.9985788]},"n1820938163":{"id":"n1820938163","loc":[-85.0887034,42.0984969]},"n1820938165":{"id":"n1820938165","loc":[-85.4133405,42.0073141]},"n1820938166":{"id":"n1820938166","loc":[-85.0097445,42.0902888]},"n1820938167":{"id":"n1820938167","loc":[-85.0828133,42.1037388]},"n1820938168":{"id":"n1820938168","loc":[-85.0549599,42.1030833]},"n1820938169":{"id":"n1820938169","loc":[-85.4571528,42.0010421]},"n1820938178":{"id":"n1820938178","loc":[-85.2706644,41.9975941]},"n1820938180":{"id":"n1820938180","loc":[-85.2258606,42.0335794]},"n1820938182":{"id":"n1820938182","loc":[-85.2832276,41.9814659]},"n1820938184":{"id":"n1820938184","loc":[-85.1082299,42.0860928]},"n1820938185":{"id":"n1820938185","loc":[-85.3839392,42.0022381]},"n1820938186":{"id":"n1820938186","loc":[-85.2772131,41.995905]},"n1820938187":{"id":"n1820938187","loc":[-85.1044895,42.0879214]},"n1820938188":{"id":"n1820938188","loc":[-85.2135267,42.0407087]},"n1820938189":{"id":"n1820938189","loc":[-85.2543993,42.0044628]},"n1820938190":{"id":"n1820938190","loc":[-85.1501793,42.0617351]},"n1820938191":{"id":"n1820938191","loc":[-85.3350587,41.9820469]},"n1820938192":{"id":"n1820938192","loc":[-85.1350731,42.0655735]},"n1820938193":{"id":"n1820938193","loc":[-85.0404008,42.1028843]},"n1820938194":{"id":"n1820938194","loc":[-85.6323161,41.943042]},"n1820938195":{"id":"n1820938195","loc":[-85.1259593,42.0742837]},"n1820938196":{"id":"n1820938196","loc":[-85.4562988,42.0033758]},"n1820938197":{"id":"n1820938197","loc":[-85.256824,42.0056826]},"n1820938198":{"id":"n1820938198","loc":[-85.2742103,41.9963862]},"n1820938199":{"id":"n1820938199","loc":[-85.0380888,42.1037877]},"n1820938200":{"id":"n1820938200","loc":[-85.47404,41.9944721]},"n1820938201":{"id":"n1820938201","loc":[-85.103021,42.087948]},"n1820938202":{"id":"n1820938202","loc":[-85.4030151,42.0065113]},"n1820938203":{"id":"n1820938203","loc":[-85.2113981,42.040735]},"n1820938204":{"id":"n1820938204","loc":[-85.2603433,41.9965137]},"n1820938206":{"id":"n1820938206","loc":[-85.1669378,42.0607634]},"n1820938207":{"id":"n1820938207","loc":[-85.0642027,42.1046076]},"n1820938208":{"id":"n1820938208","loc":[-85.2812428,41.9915696]},"n1820938209":{"id":"n1820938209","loc":[-85.0839559,42.1038343]},"n1820938210":{"id":"n1820938210","loc":[-85.1239946,42.0769368]},"n1820938211":{"id":"n1820938211","loc":[-85.2311177,42.0283042]},"n1820938212":{"id":"n1820938212","loc":[-85.2791614,41.9882682]},"n1820938213":{"id":"n1820938213","loc":[-85.2674941,41.9987582]},"n1820938214":{"id":"n1820938214","loc":[-85.352787,41.9919579]},"n1820938215":{"id":"n1820938215","loc":[-85.0874146,42.0952182]},"n1820938216":{"id":"n1820938216","loc":[-85.0069711,42.0877092]},"n1820938217":{"id":"n1820938217","loc":[-85.2059049,42.0404004]},"n1820938218":{"id":"n1820938218","loc":[-85.2403552,42.0227332]},"n1820938219":{"id":"n1820938219","loc":[-85.2492923,42.0098915]},"n1820938220":{"id":"n1820938220","loc":[-85.269778,41.9979541]},"n1820938221":{"id":"n1820938221","loc":[-85.2097673,42.0389024]},"n1820938222":{"id":"n1820938222","loc":[-85.0845942,42.1032015]},"n1820938223":{"id":"n1820938223","loc":[-84.993206,42.0858142]},"n1820938224":{"id":"n1820938224","loc":[-85.2108187,42.0402729]},"n1820938225":{"id":"n1820938225","loc":[-84.9893959,42.0873043]},"n1820938226":{"id":"n1820938226","loc":[-85.2952332,41.9719984]},"n1820938227":{"id":"n1820938227","loc":[-85.4100961,42.0081536]},"n1820938228":{"id":"n1820938228","loc":[-85.3299088,41.9785696]},"n1820938229":{"id":"n1820938229","loc":[-85.2258176,42.0340097]},"n1820938230":{"id":"n1820938230","loc":[-85.3146739,41.9711449]},"n1820938231":{"id":"n1820938231","loc":[-85.5447645,41.9712801]},"n1820938232":{"id":"n1820938232","loc":[-85.5510087,41.9705941]},"n1820938233":{"id":"n1820938233","loc":[-85.5122389,41.9703445]},"n1820938234":{"id":"n1820938234","loc":[-85.2792687,41.9865381]},"n1820938235":{"id":"n1820938235","loc":[-85.1475229,42.0630151]},"n1820938237":{"id":"n1820938237","loc":[-85.0332889,42.0996034]},"n1820938238":{"id":"n1820938238","loc":[-85.2588882,41.9986877]},"n1820938239":{"id":"n1820938239","loc":[-85.0656458,42.1050892]},"n1820938240":{"id":"n1820938240","loc":[-84.9913915,42.086098]},"n1820938241":{"id":"n1820938241","loc":[-85.4752416,41.9944402]},"n1820938242":{"id":"n1820938242","loc":[-85.1214304,42.0791147]},"n1820938243":{"id":"n1820938243","loc":[-85.0075183,42.0886925]},"n1820938244":{"id":"n1820938244","loc":[-85.1052888,42.0872087]},"n1820938245":{"id":"n1820938245","loc":[-85.3104252,41.9703393]},"n1820938246":{"id":"n1820938246","loc":[-85.232109,42.0318158]},"n1820938247":{"id":"n1820938247","loc":[-85.0756075,42.1059528]},"n1820938248":{"id":"n1820938248","loc":[-85.0075612,42.0890866]},"n1820938249":{"id":"n1820938249","loc":[-85.1013312,42.0897474]},"n1820938250":{"id":"n1820938250","loc":[-85.1168076,42.0828919]},"n1820938251":{"id":"n1820938251","loc":[-85.2951367,41.9723334]},"n1820938252":{"id":"n1820938252","loc":[-85.0879363,42.0976053]},"n1820938253":{"id":"n1820938253","loc":[-85.0354763,42.1021838]},"n1820938254":{"id":"n1820938254","loc":[-85.2379627,42.0236339]},"n1820938255":{"id":"n1820938255","loc":[-85.1308245,42.0685364]},"n1820938256":{"id":"n1820938256","loc":[-85.0914446,42.0934774]},"n1820938257":{"id":"n1820938257","loc":[-85.2436812,42.014069]},"n1820938258":{"id":"n1820938258","loc":[-85.0682529,42.1056106]},"n1820938259":{"id":"n1820938259","loc":[-85.290652,41.9766805]},"n1820938260":{"id":"n1820938260","loc":[-85.0133494,42.0897434]},"n1820938261":{"id":"n1820938261","loc":[-85.2753047,41.9949429]},"n1820938262":{"id":"n1820938262","loc":[-85.0314691,42.0950788]},"n1820938263":{"id":"n1820938263","loc":[-85.3444786,41.9908359]},"n1820938264":{"id":"n1820938264","loc":[-85.0443115,42.1009061]},"n1820938265":{"id":"n1820938265","loc":[-85.0634853,42.1043159]},"n1820938267":{"id":"n1820938267","loc":[-85.3978223,42.0053952]},"n1820938268":{"id":"n1820938268","loc":[-85.0228659,42.0911885]},"n1820938269":{"id":"n1820938269","loc":[-85.0220237,42.0906272]},"n1820938270":{"id":"n1820938270","loc":[-85.1061525,42.0863369]},"n1820938271":{"id":"n1820938271","loc":[-85.2382309,42.0233708]},"n1820938272":{"id":"n1820938272","loc":[-85.310672,41.9702755]},"n1820938273":{"id":"n1820938273","loc":[-85.1448192,42.0652613]},"n1820938274":{"id":"n1820938274","loc":[-85.6036057,41.9403766]},"n1820938275":{"id":"n1820938275","loc":[-85.0778941,42.1032413]},"n1820938276":{"id":"n1820938276","loc":[-85.1279374,42.0723974]},"n1820938277":{"id":"n1820938277","loc":[-85.2806635,41.9847836]},"n1820938278":{"id":"n1820938278","loc":[-85.2653201,41.9976352]},"n1820938279":{"id":"n1820938279","loc":[-85.0351665,42.1001805]},"n1820938280":{"id":"n1820938280","loc":[-85.0718269,42.1056253]},"n1820938281":{"id":"n1820938281","loc":[-85.2574248,42.0075322]},"n1820938282":{"id":"n1820938282","loc":[-85.126666,42.0740778]},"n1820938283":{"id":"n1820938283","loc":[-85.077705,42.1034733]},"n1820938284":{"id":"n1820938284","loc":[-85.3535552,41.9919045]},"n1820938286":{"id":"n1820938286","loc":[-85.2810711,41.9866657]},"n1820938287":{"id":"n1820938287","loc":[-85.4567494,42.0019885]},"n1820938288":{"id":"n1820938288","loc":[-85.2642419,41.9992936]},"n1820938289":{"id":"n1820938289","loc":[-85.2643344,41.9980925]},"n1820938290":{"id":"n1820938290","loc":[-85.3270335,41.9776125]},"n1820938291":{"id":"n1820938291","loc":[-85.1200584,42.0795077]},"n1820938292":{"id":"n1820938292","loc":[-85.2290792,42.0340256]},"n1820938293":{"id":"n1820938293","loc":[-85.6015887,41.9401372]},"n1820938294":{"id":"n1820938294","loc":[-85.5370869,41.970488]},"n1820938295":{"id":"n1820938295","loc":[-85.3108866,41.9698048]},"n1820938297":{"id":"n1820938297","loc":[-85.1556511,42.0628184]},"n1820938298":{"id":"n1820938298","loc":[-85.0027922,42.0875221]},"n1820938300":{"id":"n1820938300","loc":[-85.3873338,42.0040614]},"n1820938301":{"id":"n1820938301","loc":[-85.0350753,42.1004034]},"n1820938302":{"id":"n1820938302","loc":[-85.6239476,41.9411906]},"n1820938304":{"id":"n1820938304","loc":[-85.0118246,42.0897964]},"n1820938306":{"id":"n1820938306","loc":[-85.4796877,41.995275]},"n1820938307":{"id":"n1820938307","loc":[-85.5388636,41.9707856]},"n1820938309":{"id":"n1820938309","loc":[-85.2971902,41.9727773]},"n1820938310":{"id":"n1820938310","loc":[-85.5426831,41.9715513]},"n1820938311":{"id":"n1820938311","loc":[-85.2798373,41.9836671]},"n1820938312":{"id":"n1820938312","loc":[-85.2432198,42.0104017]},"n1820938313":{"id":"n1820938313","loc":[-85.2650412,41.9987554]},"n1820938317":{"id":"n1820938317","loc":[-85.0015423,42.0882386]},"n1820938318":{"id":"n1820938318","loc":[-85.1409783,42.064879]},"n1820938319":{"id":"n1820938319","loc":[-85.1691908,42.058995]},"n1820938320":{"id":"n1820938320","loc":[-85.1059165,42.0864882]},"n1820938321":{"id":"n1820938321","loc":[-85.3664941,41.9965771]},"n1820938323":{"id":"n1820938323","loc":[-85.3143198,41.9710971]},"n1820938324":{"id":"n1820938324","loc":[-85.0016067,42.0880675]},"n1820938325":{"id":"n1820938325","loc":[-85.0148139,42.0887164]},"n1820938326":{"id":"n1820938326","loc":[-85.0324682,42.0959056]},"n1820938327":{"id":"n1820938327","loc":[-85.0898661,42.0939921]},"n1820938328":{"id":"n1820938328","loc":[-85.2556427,42.0004936]},"n1820938329":{"id":"n1820938329","loc":[-85.6287112,41.9407437]},"n1820938330":{"id":"n1820938330","loc":[-84.9913392,42.0866701]},"n1820938331":{"id":"n1820938331","loc":[-85.2685777,41.9984632]},"n1820938332":{"id":"n1820938332","loc":[-85.0078884,42.0901614]},"n1820938333":{"id":"n1820938333","loc":[-84.999642,42.0878616]},"n1820938334":{"id":"n1820938334","loc":[-85.0188909,42.0899186]},"n1820938335":{"id":"n1820938335","loc":[-85.2830238,41.9819843]},"n1820938336":{"id":"n1820938336","loc":[-85.2491421,42.0096204]},"n1820938337":{"id":"n1820938337","loc":[-85.0585701,42.1034295]},"n1820938338":{"id":"n1820938338","loc":[-85.0651965,42.1051636]},"n1820938339":{"id":"n1820938339","loc":[-85.0583944,42.104292]},"n1820938340":{"id":"n1820938340","loc":[-85.119876,42.0801567]},"n1820938341":{"id":"n1820938341","loc":[-85.0943937,42.0931323]},"n1820938342":{"id":"n1820938342","loc":[-85.1504583,42.0613209]},"n1820938343":{"id":"n1820938343","loc":[-85.0425426,42.1019836]},"n1820938345":{"id":"n1820938345","loc":[-84.9991391,42.0878206]},"n1820938346":{"id":"n1820938346","loc":[-85.2563841,42.0094614]},"n1820938347":{"id":"n1820938347","loc":[-85.0515387,42.103297]},"n1820938348":{"id":"n1820938348","loc":[-85.0857261,42.1003636]},"n1820938349":{"id":"n1820938349","loc":[-85.078971,42.1029241]},"n1820938350":{"id":"n1820938350","loc":[-85.5699558,41.958931]},"n1820938351":{"id":"n1820938351","loc":[-85.3181285,41.9696533]},"n1820938352":{"id":"n1820938352","loc":[-85.5998506,41.9402329]},"n1820938353":{"id":"n1820938353","loc":[-85.2567277,42.000317]},"n1820938354":{"id":"n1820938354","loc":[-85.3082795,41.9708338]},"n1820938355":{"id":"n1820938355","loc":[-85.3127856,41.9692784]},"n1820938356":{"id":"n1820938356","loc":[-85.0340775,42.1010721]},"n1820938357":{"id":"n1820938357","loc":[-85.3158111,41.9706583]},"n1820938359":{"id":"n1820938359","loc":[-85.2312035,42.0280412]},"n1820938360":{"id":"n1820938360","loc":[-85.2448613,42.018477]},"n1820938361":{"id":"n1820938361","loc":[-85.29077,41.9759068]},"n1820938364":{"id":"n1820938364","loc":[-85.3677387,41.9976615]},"n1820938365":{"id":"n1820938365","loc":[-85.0785204,42.1030355]},"n1820938366":{"id":"n1820938366","loc":[-85.2262039,42.0333722]},"n1820938367":{"id":"n1820938367","loc":[-85.1226011,42.0780902]},"n1820938368":{"id":"n1820938368","loc":[-85.3229673,41.971129]},"n1820938369":{"id":"n1820938369","loc":[-85.385334,42.0000056]},"n1820938370":{"id":"n1820938370","loc":[-85.000098,42.0879094]},"n1820938372":{"id":"n1820938372","loc":[-85.3852481,42.0025091]},"n1820938373":{"id":"n1820938373","loc":[-85.3770513,41.9982515]},"n1820938374":{"id":"n1820938374","loc":[-85.6278314,41.9405362]},"n1820938375":{"id":"n1820938375","loc":[-85.6355133,41.9344068]},"n1820938376":{"id":"n1820938376","loc":[-85.635642,41.9324753]},"n1820938377":{"id":"n1820938377","loc":[-85.3154463,41.970778]},"n1820938378":{"id":"n1820938378","loc":[-85.0920334,42.093411]},"n1820938379":{"id":"n1820938379","loc":[-85.3269155,41.9722297]},"n1820938381":{"id":"n1820938381","loc":[-85.1134334,42.0849184]},"n1820938382":{"id":"n1820938382","loc":[-85.005968,42.088585]},"n1820938384":{"id":"n1820938384","loc":[-85.1245203,42.0757183]},"n1820938385":{"id":"n1820938385","loc":[-85.020704,42.0905396]},"n1820938386":{"id":"n1820938386","loc":[-85.119585,42.0808984]},"n1820938387":{"id":"n1820938387","loc":[-85.0072447,42.0880117]},"n1820938388":{"id":"n1820938388","loc":[-85.2742908,41.9960273]},"n1820938389":{"id":"n1820938389","loc":[-85.3275807,41.9696852]},"n1820938390":{"id":"n1820938390","loc":[-85.2385635,42.0231556]},"n1820938392":{"id":"n1820938392","loc":[-85.0202856,42.0900778]},"n1820938393":{"id":"n1820938393","loc":[-85.2067847,42.0395398]},"n1820938394":{"id":"n1820938394","loc":[-85.5183544,41.9713495]},"n1820938396":{"id":"n1820938396","loc":[-85.5073037,41.9736787]},"n1820938397":{"id":"n1820938397","loc":[-85.2519638,42.0114225]},"n1820938398":{"id":"n1820938398","loc":[-85.287487,41.9793285]},"n1820938399":{"id":"n1820938399","loc":[-85.2298088,42.0336431]},"n1820938400":{"id":"n1820938400","loc":[-85.229444,42.0339141]},"n1820938401":{"id":"n1820938401","loc":[-85.2421791,42.0220239]},"n1820938402":{"id":"n1820938402","loc":[-85.2976687,41.9737612]},"n1820938403":{"id":"n1820938403","loc":[-85.3622069,41.993473]},"n1820938404":{"id":"n1820938404","loc":[-85.2465458,42.014906]},"n1820938405":{"id":"n1820938405","loc":[-85.5724663,41.9639412]},"n1820938406":{"id":"n1820938406","loc":[-85.3708501,41.9982037]},"n1820938408":{"id":"n1820938408","loc":[-85.2564592,42.0055311]},"n1820938409":{"id":"n1820938409","loc":[-85.1192846,42.0810856]},"n1820938410":{"id":"n1820938410","loc":[-85.5623812,41.971663]},"n1820938411":{"id":"n1820938411","loc":[-85.3221948,41.9719665]},"n1820938412":{"id":"n1820938412","loc":[-85.5168738,41.9710305]},"n1820938413":{"id":"n1820938413","loc":[-85.4546852,42.0061127]},"n1820938414":{"id":"n1820938414","loc":[-85.5896153,41.9463617]},"n1820938415":{"id":"n1820938415","loc":[-85.2978189,41.9722138]},"n1820938416":{"id":"n1820938416","loc":[-85.1021681,42.0883581]},"n1820938417":{"id":"n1820938417","loc":[-85.2797193,41.9912984]},"n1820938419":{"id":"n1820938419","loc":[-85.2362461,42.0248533]},"n1820938420":{"id":"n1820938420","loc":[-85.4833639,41.9846252]},"n1820938422":{"id":"n1820938422","loc":[-85.3281064,41.9689433]},"n1820938424":{"id":"n1820938424","loc":[-85.2416963,42.0130088]},"n1820938425":{"id":"n1820938425","loc":[-85.5718655,41.9564577]},"n1820938426":{"id":"n1820938426","loc":[-85.0512812,42.1030701]},"n1820938427":{"id":"n1820938427","loc":[-85.1273527,42.0723616]},"n1820938428":{"id":"n1820938428","loc":[-85.0215033,42.0904083]},"n1820938429":{"id":"n1820938429","loc":[-85.6169953,41.942228]},"n1820938430":{"id":"n1820938430","loc":[-85.2829165,41.9907243]},"n1820938431":{"id":"n1820938431","loc":[-85.2240796,42.0374203]},"n1820938432":{"id":"n1820938432","loc":[-85.0167598,42.0898442]},"n1820938433":{"id":"n1820938433","loc":[-85.2132649,42.0411334]},"n1820938434":{"id":"n1820938434","loc":[-85.2293839,42.031513]},"n1820938435":{"id":"n1820938435","loc":[-85.1203374,42.0792608]},"n1820938436":{"id":"n1820938436","loc":[-85.109571,42.086268]},"n1820938437":{"id":"n1820938437","loc":[-85.1079026,42.0853842]},"n1820938438":{"id":"n1820938438","loc":[-85.109237,42.0862413]},"n1820938439":{"id":"n1820938439","loc":[-85.2259936,42.0350831]},"n1820938440":{"id":"n1820938440","loc":[-85.3669705,41.99679]},"n1820938441":{"id":"n1820938441","loc":[-85.2418143,42.0223507]},"n1820938442":{"id":"n1820938442","loc":[-85.3101248,41.9702515]},"n1820938443":{"id":"n1820938443","loc":[-85.069315,42.1059688]},"n1820938444":{"id":"n1820938444","loc":[-85.205862,42.0410378]},"n1820938445":{"id":"n1820938445","loc":[-85.0388076,42.1036604]},"n1820938446":{"id":"n1820938446","loc":[-85.2225389,42.0370115]},"n1820938447":{"id":"n1820938447","loc":[-85.3241474,41.9719346]},"n1820938448":{"id":"n1820938448","loc":[-85.3125496,41.9690789]},"n1820938449":{"id":"n1820938449","loc":[-85.1146497,42.0857039]},"n1820938450":{"id":"n1820938450","loc":[-85.1333944,42.0714963]},"n1820938451":{"id":"n1820938451","loc":[-85.5619306,41.9720937]},"n1820938452":{"id":"n1820938452","loc":[-85.2553651,42.0006479]},"n1820938453":{"id":"n1820938453","loc":[-85.3151137,41.9710093]},"n1820938454":{"id":"n1820938454","loc":[-85.2592315,41.9977947]},"n1820938455":{"id":"n1820938455","loc":[-85.2655723,41.9995966]},"n1820938456":{"id":"n1820938456","loc":[-85.4820652,41.9959233]},"n1820938459":{"id":"n1820938459","loc":[-85.450737,42.0055068]},"n1820938460":{"id":"n1820938460","loc":[-85.2428658,42.0205573]},"n1820938461":{"id":"n1820938461","loc":[-85.0835576,42.1021559]},"n1820938462":{"id":"n1820938462","loc":[-85.244636,42.0194733]},"n1820938463":{"id":"n1820938463","loc":[-85.5702562,41.9581332]},"n1820938465":{"id":"n1820938465","loc":[-85.5680031,41.9659515]},"n1820938467":{"id":"n1820938467","loc":[-85.2798752,41.9948353]},"n1820938468":{"id":"n1820938468","loc":[-85.0477407,42.1015537]},"n1820938469":{"id":"n1820938469","loc":[-85.6403842,41.913732]},"n1820938470":{"id":"n1820938470","loc":[-85.0396029,42.103289]},"n1820938471":{"id":"n1820938471","loc":[-85.2824702,41.9907777]},"n1820938472":{"id":"n1820938472","loc":[-85.2969284,41.9735538]},"n1820938474":{"id":"n1820938474","loc":[-85.401041,42.0070853]},"n1820938475":{"id":"n1820938475","loc":[-85.4116625,42.0073883]},"n1820938476":{"id":"n1820938476","loc":[-85.0437764,42.1016214]},"n1820938477":{"id":"n1820938477","loc":[-85.3643269,41.9958436]},"n1820938478":{"id":"n1820938478","loc":[-85.3895182,42.0009465]},"n1820938479":{"id":"n1820938479","loc":[-85.636157,41.9333373]},"n1820938480":{"id":"n1820938480","loc":[-85.2811355,41.9858044]},"n1820938481":{"id":"n1820938481","loc":[-85.0239052,42.092153]},"n1820938482":{"id":"n1820938482","loc":[-85.2558798,42.0053557]},"n1820938483":{"id":"n1820938483","loc":[-85.2544422,42.0047339]},"n1820938484":{"id":"n1820938484","loc":[-85.4864683,41.9843183]},"n1820938485":{"id":"n1820938485","loc":[-85.2554185,42.0031075]},"n1820938486":{"id":"n1820938486","loc":[-85.3082795,41.9712486]},"n1820938487":{"id":"n1820938487","loc":[-85.2433378,42.0133436]},"n1820938488":{"id":"n1820938488","loc":[-85.0216696,42.0904162]},"n1820938489":{"id":"n1820938489","loc":[-85.2546138,42.0050289]},"n1820938490":{"id":"n1820938490","loc":[-85.2717521,41.9977349]},"n1820938491":{"id":"n1820938491","loc":[-85.0100489,42.0908195]},"n1820938492":{"id":"n1820938492","loc":[-85.207879,42.0392211]},"n1820938493":{"id":"n1820938493","loc":[-85.0007363,42.0882836]},"n1820938494":{"id":"n1820938494","loc":[-85.5775303,41.9504097]},"n1820938495":{"id":"n1820938495","loc":[-85.1131584,42.0847683]},"n1820938496":{"id":"n1820938496","loc":[-85.0887825,42.0941633]},"n1820938497":{"id":"n1820938497","loc":[-85.1185926,42.0818938]},"n1820938498":{"id":"n1820938498","loc":[-85.2748487,41.9948712]},"n1820938499":{"id":"n1820938499","loc":[-85.2566952,42.0090788]},"n1820938500":{"id":"n1820938500","loc":[-85.0774757,42.1036234]},"n1820938501":{"id":"n1820938501","loc":[-85.4190869,42.008903]},"n1820938502":{"id":"n1820938502","loc":[-85.1140395,42.0850577]},"n1820938503":{"id":"n1820938503","loc":[-85.1136104,42.0848627]},"n1820938504":{"id":"n1820938504","loc":[-85.5828089,41.9480638]},"n1820938505":{"id":"n1820938505","loc":[-85.625514,41.9405202]},"n1820938506":{"id":"n1820938506","loc":[-85.2063384,42.0398322]},"n1820938507":{"id":"n1820938507","loc":[-85.3395476,41.9851636]},"n1820938508":{"id":"n1820938508","loc":[-85.0328853,42.0963606]},"n1820938510":{"id":"n1820938510","loc":[-85.1170369,42.0843702]},"n1820938511":{"id":"n1820938511","loc":[-85.2784748,41.9868487]},"n1820938512":{"id":"n1820938512","loc":[-85.6310501,41.9435528]},"n1820938514":{"id":"n1820938514","loc":[-85.0334284,42.0981028]},"n1820938515":{"id":"n1820938515","loc":[-84.9912091,42.0868226]},"n1820938516":{"id":"n1820938516","loc":[-85.2806141,41.9940351]},"n1820938517":{"id":"n1820938517","loc":[-85.1233025,42.0776734]},"n1820938518":{"id":"n1820938518","loc":[-85.2047891,42.0429023]},"n1820938519":{"id":"n1820938519","loc":[-85.1475443,42.0648312]},"n1820938520":{"id":"n1820938520","loc":[-85.2644685,41.9990891]},"n1820938521":{"id":"n1820938521","loc":[-85.1056281,42.0872553]},"n1820938522":{"id":"n1820938522","loc":[-85.4813184,41.9930105]},"n1820938523":{"id":"n1820938523","loc":[-85.321551,41.9722936]},"n1820938524":{"id":"n1820938524","loc":[-85.1564664,42.0631211]},"n1820938525":{"id":"n1820938525","loc":[-85.4149885,42.0079144]},"n1820938527":{"id":"n1820938527","loc":[-85.2861888,41.9803653]},"n1820938528":{"id":"n1820938528","loc":[-85.1301379,42.0682178]},"n1820938529":{"id":"n1820938529","loc":[-85.4156537,42.0084247]},"n1820938530":{"id":"n1820938530","loc":[-85.245151,42.0176082]},"n1820938531":{"id":"n1820938531","loc":[-85.457818,42.0001651]},"n1820938532":{"id":"n1820938532","loc":[-85.310951,41.9694538]},"n1820938533":{"id":"n1820938533","loc":[-85.1509089,42.0611298]},"n1820938534":{"id":"n1820938534","loc":[-85.1108249,42.086321]},"n1820938535":{"id":"n1820938535","loc":[-85.1260344,42.0740687]},"n1820938536":{"id":"n1820938536","loc":[-85.4561228,42.0042791]},"n1820938537":{"id":"n1820938537","loc":[-85.2805082,41.9945761]},"n1820938538":{"id":"n1820938538","loc":[-85.273352,41.9981921]},"n1820938539":{"id":"n1820938539","loc":[-85.1084216,42.0864364]},"n1820938540":{"id":"n1820938540","loc":[-85.5009737,41.9773637]},"n1820938541":{"id":"n1820938541","loc":[-85.3960843,42.0051879]},"n1820938542":{"id":"n1820938542","loc":[-85.3425088,41.9865034]},"n1820938545":{"id":"n1820938545","loc":[-84.9937907,42.0860849]},"n1820938546":{"id":"n1820938546","loc":[-85.1084176,42.086065]},"n1820938547":{"id":"n1820938547","loc":[-85.3492851,41.9924786]},"n1820938548":{"id":"n1820938548","loc":[-85.2512235,42.0101147]},"n1820938549":{"id":"n1820938549","loc":[-85.3717298,41.9979326]},"n1820938551":{"id":"n1820938551","loc":[-85.2573712,42.0064081]},"n1820938552":{"id":"n1820938552","loc":[-85.2514596,42.010139]},"n1820938553":{"id":"n1820938553","loc":[-85.416512,42.0088073]},"n1820938554":{"id":"n1820938554","loc":[-85.4365964,42.0061606]},"n1820938555":{"id":"n1820938555","loc":[-85.4552431,42.0057301]},"n1820938556":{"id":"n1820938556","loc":[-85.2916283,41.9778769]},"n1820938557":{"id":"n1820938557","loc":[-85.100709,42.0902968]},"n1820938558":{"id":"n1820938558","loc":[-85.4703064,41.9965771]},"n1820938559":{"id":"n1820938559","loc":[-85.3134722,41.9696134]},"n1820938560":{"id":"n1820938560","loc":[-85.4834213,41.9885768]},"n1820938561":{"id":"n1820938561","loc":[-85.2740641,41.9975236]},"n1820938562":{"id":"n1820938562","loc":[-85.148334,42.0623405]},"n1820938563":{"id":"n1820938563","loc":[-85.2358598,42.0263675]},"n1820938565":{"id":"n1820938565","loc":[-85.2902979,41.9790892]},"n1820938566":{"id":"n1820938566","loc":[-85.2528865,42.0112869]},"n1820938567":{"id":"n1820938567","loc":[-85.2595319,41.9973003]},"n1820938568":{"id":"n1820938568","loc":[-85.071151,42.105689]},"n1820938570":{"id":"n1820938570","loc":[-85.299278,41.9732188]},"n1820938571":{"id":"n1820938571","loc":[-85.0354669,42.1024771]},"n1820938583":{"id":"n1820938583","loc":[-85.3313937,41.972562]},"n1820938585":{"id":"n1820938585","loc":[-85.0756933,42.1058334]},"n1820938587":{"id":"n1820938587","loc":[-85.3130324,41.9694219]},"n1820938590":{"id":"n1820938590","loc":[-85.0934227,42.0931681]},"n1820938592":{"id":"n1820938592","loc":[-85.3517956,41.9922553]},"n1820938593":{"id":"n1820938593","loc":[-85.4023971,42.0065169]},"n1820938594":{"id":"n1820938594","loc":[-85.3506798,41.9925583]},"n1820938595":{"id":"n1820938595","loc":[-85.3673524,41.9971193]},"n1820938596":{"id":"n1820938596","loc":[-85.1073608,42.0853523]},"n1820938597":{"id":"n1820938597","loc":[-85.2976579,41.972477]},"n1820938598":{"id":"n1820938598","loc":[-85.5616517,41.9694295]},"n1820938599":{"id":"n1820938599","loc":[-85.3552074,41.9921915]},"n1820938600":{"id":"n1820938600","loc":[-85.4665126,41.9999953]},"n1820938601":{"id":"n1820938601","loc":[-85.2740695,41.9966226]},"n1820938602":{"id":"n1820938602","loc":[-85.279376,41.9886669]},"n1820938603":{"id":"n1820938603","loc":[-85.0771109,42.1040413]},"n1820938604":{"id":"n1820938604","loc":[-85.2636049,41.9977895]},"n1820938605":{"id":"n1820938605","loc":[-85.3762145,41.9976456]},"n1820938606":{"id":"n1820938606","loc":[-85.2321369,42.0289577]},"n1820938620":{"id":"n1820938620","loc":[-85.4947724,41.9776189]},"n1820938622":{"id":"n1820938622","loc":[-85.1547069,42.0622768]},"n1820938624":{"id":"n1820938624","loc":[-85.0005056,42.0880249]},"n1820938626":{"id":"n1820938626","loc":[-85.0735596,42.1059357]},"n1820938628":{"id":"n1820938628","loc":[-85.4665298,41.99932]},"n1820938629":{"id":"n1820938629","loc":[-85.434515,42.0065273]},"n1820938630":{"id":"n1820938630","loc":[-85.117462,42.0823823]},"n1820938631":{"id":"n1820938631","loc":[-85.0131777,42.0890707]},"n1820938632":{"id":"n1820938632","loc":[-85.0875326,42.0961934]},"n1820938634":{"id":"n1820938634","loc":[-85.6433839,41.9112042]},"n1820938635":{"id":"n1820938635","loc":[-85.1366181,42.064969]},"n1820938636":{"id":"n1820938636","loc":[-85.073109,42.1057925]},"n1820938638":{"id":"n1820938638","loc":[-85.161406,42.0632541]},"n1820938640":{"id":"n1820938640","loc":[-85.6343932,41.9188845]},"n1820938642":{"id":"n1820938642","loc":[-85.2500004,42.010306]},"n1820938644":{"id":"n1820938644","loc":[-85.291918,41.9753166]},"n1820938663":{"id":"n1820938663","loc":[-85.2841611,41.9916812]},"n1820938664":{"id":"n1820938664","loc":[-85.1052955,42.0868134]},"n1820938665":{"id":"n1820938665","loc":[-85.4606118,42.0005534]},"n1820938666":{"id":"n1820938666","loc":[-85.5672736,41.9642922]},"n1820938667":{"id":"n1820938667","loc":[-85.6348481,41.9316932]},"n1820938668":{"id":"n1820938668","loc":[-85.0224904,42.0909576]},"n1820938669":{"id":"n1820938669","loc":[-85.0133856,42.0899755]},"n1820938670":{"id":"n1820938670","loc":[-85.344779,41.991139]},"n1820938671":{"id":"n1820938671","loc":[-85.632874,41.9425313]},"n1820938673":{"id":"n1820938673","loc":[-85.4941501,41.9779698]},"n1820938675":{"id":"n1820938675","loc":[-85.0862559,42.0997519]},"n1820938676":{"id":"n1820938676","loc":[-85.0097874,42.0898032]},"n1820938678":{"id":"n1820938678","loc":[-84.9913553,42.0863675]},"n1820938680":{"id":"n1820938680","loc":[-85.0533666,42.1038315]},"n1820938682":{"id":"n1820938682","loc":[-85.2950294,41.9743914]},"n1820938684":{"id":"n1820938684","loc":[-85.2517385,42.0104499]},"n1820938686":{"id":"n1820938686","loc":[-85.0247971,42.0922514]},"n1820938688":{"id":"n1820938688","loc":[-85.0807037,42.1026017]},"n1820938690":{"id":"n1820938690","loc":[-85.52462,41.9722748]},"n1820938694":{"id":"n1820938694","loc":[-85.2586535,41.9988818]},"n1820938695":{"id":"n1820938695","loc":[-85.0931612,42.092948]},"n1820938697":{"id":"n1820938697","loc":[-85.2470822,42.016564]},"n1820938698":{"id":"n1820938698","loc":[-85.4143018,42.0075158]},"n1820938699":{"id":"n1820938699","loc":[-85.0771484,42.104487]},"n1820938700":{"id":"n1820938700","loc":[-85.0291208,42.0942775]},"n1820938701":{"id":"n1820938701","loc":[-85.6367964,41.9185971]},"n1820938702":{"id":"n1820938702","loc":[-85.085419,42.1010693]},"n1820938703":{"id":"n1820938703","loc":[-85.0583877,42.1040584]},"n1820938705":{"id":"n1820938705","loc":[-85.2573379,42.0003182]},"n1820938706":{"id":"n1820938706","loc":[-85.2655937,41.9981575]},"n1820938707":{"id":"n1820938707","loc":[-85.023181,42.0915758]},"n1820938708":{"id":"n1820938708","loc":[-85.2318687,42.0274674]},"n1820938709":{"id":"n1820938709","loc":[-85.1056389,42.0866184]},"n1820938710":{"id":"n1820938710","loc":[-85.5276265,41.9700978]},"n1820938711":{"id":"n1820938711","loc":[-85.0864128,42.0945761]},"n1820938712":{"id":"n1820938712","loc":[-84.9897071,42.0871888]},"n1820938714":{"id":"n1820938714","loc":[-85.1328845,42.0665611]},"n1820938715":{"id":"n1820938715","loc":[-85.0336537,42.0991377]},"n1820938716":{"id":"n1820938716","loc":[-85.087597,42.0986692]},"n1820938717":{"id":"n1820938717","loc":[-85.1241394,42.0761882]},"n1820938718":{"id":"n1820938718","loc":[-85.1176002,42.0847723]},"n1820938719":{"id":"n1820938719","loc":[-85.2423615,42.0216572]},"n1820938721":{"id":"n1820938721","loc":[-85.2196378,42.0387908]},"n1820938722":{"id":"n1820938722","loc":[-85.0164272,42.0890082]},"n1820938723":{"id":"n1820938723","loc":[-85.5917182,41.9451807]},"n1820938724":{"id":"n1820938724","loc":[-85.2458806,42.0086638]},"n1820938725":{"id":"n1820938725","loc":[-85.1264474,42.0740527]},"n1820938726":{"id":"n1820938726","loc":[-85.1961631,42.04738]},"n1820938727":{"id":"n1820938727","loc":[-85.2784643,41.9943648]},"n1820938728":{"id":"n1820938728","loc":[-85.2905554,41.9763216]},"n1820938729":{"id":"n1820938729","loc":[-85.2913386,41.9771511]},"n1820938730":{"id":"n1820938730","loc":[-85.0112519,42.0895683]},"n1820938732":{"id":"n1820938732","loc":[-85.4290261,42.0064531]},"n1820938733":{"id":"n1820938733","loc":[-85.3867073,42.0031629]},"n1820938734":{"id":"n1820938734","loc":[-85.4943647,41.9836005]},"n1820938735":{"id":"n1820938735","loc":[-85.4900303,41.9860728]},"n1820938736":{"id":"n1820938736","loc":[-85.0866153,42.0944539]},"n1820938737":{"id":"n1820938737","loc":[-85.0869532,42.0990911]},"n1820938738":{"id":"n1820938738","loc":[-85.6321659,41.9208851]},"n1820938739":{"id":"n1820938739","loc":[-85.5930485,41.9433453]},"n1820938740":{"id":"n1820938740","loc":[-85.0406851,42.102733]},"n1820938741":{"id":"n1820938741","loc":[-85.1051131,42.0869846]},"n1820938742":{"id":"n1820938742","loc":[-85.1377554,42.0648893]},"n1820938743":{"id":"n1820938743","loc":[-85.2795694,41.994604]},"n1820938745":{"id":"n1820938745","loc":[-85.4948153,41.9826594]},"n1820938746":{"id":"n1820938746","loc":[-85.4488916,42.0050923]},"n1820938747":{"id":"n1820938747","loc":[-85.1052526,42.0866144]},"n1820938748":{"id":"n1820938748","loc":[-85.1468749,42.0653991]},"n1820938749":{"id":"n1820938749","loc":[-85.0856886,42.1006104]},"n1820938750":{"id":"n1820938750","loc":[-85.2144022,42.0404004]},"n1820938751":{"id":"n1820938751","loc":[-85.277771,41.9907458]},"n1820938752":{"id":"n1820938752","loc":[-85.1474542,42.0636149]},"n1820938753":{"id":"n1820938753","loc":[-85.0820515,42.1028075]},"n1820938754":{"id":"n1820938754","loc":[-85.1122948,42.08525]},"n1820938756":{"id":"n1820938756","loc":[-85.0173352,42.0901933]},"n1820938757":{"id":"n1820938757","loc":[-85.2259721,42.0354018]},"n1820938758":{"id":"n1820938758","loc":[-85.0872389,42.0987795]},"n1820938759":{"id":"n1820938759","loc":[-85.2291436,42.031874]},"n1820938760":{"id":"n1820938760","loc":[-85.3802485,42.0016002]},"n1820938761":{"id":"n1820938761","loc":[-85.3945822,42.0057938]},"n1820938762":{"id":"n1820938762","loc":[-85.5273237,41.9713017]},"n1820938763":{"id":"n1820938763","loc":[-85.2868862,41.9798629]},"n1820938764":{"id":"n1820938764","loc":[-85.2516677,42.0107899]},"n1820938766":{"id":"n1820938766","loc":[-85.3183002,41.9693103]},"n1820938768":{"id":"n1820938768","loc":[-85.2159042,42.0401932]},"n1820938770":{"id":"n1820938770","loc":[-85.0094481,42.0911141]},"n1820938771":{"id":"n1820938771","loc":[-85.0244538,42.0922155]},"n1820938772":{"id":"n1820938772","loc":[-85.231697,42.028862]},"n1820938773":{"id":"n1820938773","loc":[-85.2102394,42.0390617]},"n1820938774":{"id":"n1820938774","loc":[-85.2463419,42.0151212]},"n1820938775":{"id":"n1820938775","loc":[-85.0726195,42.1056424]},"n1820938776":{"id":"n1820938776","loc":[-85.0060431,42.0883262]},"n1820938778":{"id":"n1820938778","loc":[-85.425889,42.0056982]},"n1820938779":{"id":"n1820938779","loc":[-85.1183042,42.0820638]},"n1820938780":{"id":"n1820938780","loc":[-85.441596,42.0058257]},"n1820938781":{"id":"n1820938781","loc":[-85.1124879,42.0847086]},"n1820938782":{"id":"n1820938782","loc":[-85.2452733,42.0153894]},"n1820938783":{"id":"n1820938783","loc":[-85.2741191,41.9969244]},"n1820938784":{"id":"n1820938784","loc":[-85.2829487,41.9822236]},"n1820938785":{"id":"n1820938785","loc":[-85.3202743,41.972142]},"n1820938786":{"id":"n1820938786","loc":[-85.2345402,42.0266465]},"n1820938787":{"id":"n1820938787","loc":[-85.3037626,41.9724611]},"n1820938789":{"id":"n1820938789","loc":[-85.2474792,42.0161973]},"n1820938790":{"id":"n1820938790","loc":[-85.2951045,41.9727323]},"n1820938791":{"id":"n1820938791","loc":[-85.322345,41.9712726]},"n1820938792":{"id":"n1820938792","loc":[-85.2402372,42.0110394]},"n1820938793":{"id":"n1820938793","loc":[-85.5135693,41.9698659]},"n1820938794":{"id":"n1820938794","loc":[-85.4695339,41.9967366]},"n1820938796":{"id":"n1820938796","loc":[-85.0418492,42.1011131]},"n1820938797":{"id":"n1820938797","loc":[-85.3334107,41.9806337]},"n1820938798":{"id":"n1820938798","loc":[-85.5625314,41.9711685]},"n1820938799":{"id":"n1820938799","loc":[-85.3755707,41.9973585]},"n1820938800":{"id":"n1820938800","loc":[-85.5227532,41.9722429]},"n1820938801":{"id":"n1820938801","loc":[-85.4267687,42.0052836]},"n1820938803":{"id":"n1820938803","loc":[-85.0284704,42.0940837]},"n1820938804":{"id":"n1820938804","loc":[-85.015585,42.0885305]},"n1820938805":{"id":"n1820938805","loc":[-85.0765905,42.1053865]},"n1820938806":{"id":"n1820938806","loc":[-85.2614953,41.9964551]},"n1820938808":{"id":"n1820938808","loc":[-85.0307355,42.0947313]},"n1820938810":{"id":"n1820938810","loc":[-85.3894753,42.0003565]},"n1820938812":{"id":"n1820938812","loc":[-85.0868848,42.095006]},"n1820938813":{"id":"n1820938813","loc":[-85.3854198,42.0009465]},"n1820938814":{"id":"n1820938814","loc":[-85.2659692,41.9993534]},"n1820938815":{"id":"n1820938815","loc":[-85.1234259,42.0765266]},"n1820938816":{"id":"n1820938816","loc":[-85.1426906,42.0648893]},"n1820938818":{"id":"n1820938818","loc":[-85.1014533,42.0893067]},"n1820938819":{"id":"n1820938819","loc":[-85.0883064,42.098067]},"n1820938820":{"id":"n1820938820","loc":[-85.0503156,42.102704]},"n1820938821":{"id":"n1820938821","loc":[-85.1179649,42.0821884]},"n1820938822":{"id":"n1820938822","loc":[-85.3484697,41.9921596]},"n1820938823":{"id":"n1820938823","loc":[-85.3732962,41.9970874]},"n1820938824":{"id":"n1820938824","loc":[-85.2784104,41.9898312]},"n1820938825":{"id":"n1820938825","loc":[-85.4441709,42.0052198]},"n1820938826":{"id":"n1820938826","loc":[-85.3925438,42.0038326]},"n1820938829":{"id":"n1820938829","loc":[-85.5717582,41.9621861]},"n1820938830":{"id":"n1820938830","loc":[-85.0866314,42.0995051]},"n1820938831":{"id":"n1820938831","loc":[-85.576672,41.9522769]},"n1820938832":{"id":"n1820938832","loc":[-85.1587238,42.0636205]},"n1820938833":{"id":"n1820938833","loc":[-85.3804245,41.9999155]},"n1820938834":{"id":"n1820938834","loc":[-85.280083,41.9948843]},"n1820938836":{"id":"n1820938836","loc":[-85.561892,41.9686693]},"n1820938837":{"id":"n1820938837","loc":[-85.0158975,42.0885253]},"n1820938838":{"id":"n1820938838","loc":[-85.4248204,42.007633]},"n1820938839":{"id":"n1820938839","loc":[-85.0352738,42.1039657]},"n1820938840":{"id":"n1820938840","loc":[-85.211956,42.0411812]},"n1820938841":{"id":"n1820938841","loc":[-85.4816575,41.9908997]},"n1820938842":{"id":"n1820938842","loc":[-85.3807635,42.0020308]},"n1820938843":{"id":"n1820938843","loc":[-85.0100865,42.0898521]},"n1820938844":{"id":"n1820938844","loc":[-85.0103936,42.0897434]},"n1820938848":{"id":"n1820938848","loc":[-85.2430052,42.0131363]},"n1820938849":{"id":"n1820938849","loc":[-85.112559,42.0853723]},"n1820938851":{"id":"n1820938851","loc":[-85.3641553,41.9952535]},"n1820938852":{"id":"n1820938852","loc":[-85.2087373,42.0390777]},"n1820938853":{"id":"n1820938853","loc":[-85.2473933,42.0148263]},"n1820938854":{"id":"n1820938854","loc":[-85.0213464,42.090509]},"n1820938855":{"id":"n1820938855","loc":[-85.0673208,42.1052353]},"n1820938856":{"id":"n1820938856","loc":[-85.1003053,42.0905528]},"n1820938857":{"id":"n1820938857","loc":[-85.2617367,41.9965389]},"n1820938858":{"id":"n1820938858","loc":[-85.280363,41.9916015]},"n1820938859":{"id":"n1820938859","loc":[-85.0038866,42.0873469]},"n1820938860":{"id":"n1820938860","loc":[-85.2476401,42.0151451]},"n1820938861":{"id":"n1820938861","loc":[-85.193717,42.0499294]},"n1820938862":{"id":"n1820938862","loc":[-85.3478689,41.9917609]},"n1820938863":{"id":"n1820938863","loc":[-85.5638017,41.9648881]},"n1820938864":{"id":"n1820938864","loc":[-85.4356308,42.0064476]},"n1820938865":{"id":"n1820938865","loc":[-85.0561722,42.1023509]},"n1820938867":{"id":"n1820938867","loc":[-85.2256031,42.0356034]},"n1820938868":{"id":"n1820938868","loc":[-85.6102576,41.9420844]},"n1820938869":{"id":"n1820938869","loc":[-85.2285213,42.0339938]},"n1820938870":{"id":"n1820938870","loc":[-85.0326238,42.0978003]},"n1820938871":{"id":"n1820938871","loc":[-85.0131389,42.0903736]},"n1820938872":{"id":"n1820938872","loc":[-85.2550859,42.0012259]},"n1820938873":{"id":"n1820938873","loc":[-85.1130029,42.0846966]},"n1820938874":{"id":"n1820938874","loc":[-85.1579041,42.06336]},"n1820938875":{"id":"n1820938875","loc":[-85.0430522,42.1020234]},"n1820938876":{"id":"n1820938876","loc":[-85.2786679,41.9865935]},"n1820938877":{"id":"n1820938877","loc":[-85.1221666,42.0788706]},"n1820938878":{"id":"n1820938878","loc":[-85.2554614,42.0103303]},"n1820938879":{"id":"n1820938879","loc":[-85.2349801,42.0265748]},"n1820938880":{"id":"n1820938880","loc":[-85.0997434,42.0907864]},"n1820938881":{"id":"n1820938881","loc":[-85.0045464,42.0878167]},"n1820938882":{"id":"n1820938882","loc":[-85.2728048,41.9982519]},"n1820938883":{"id":"n1820938883","loc":[-85.3111333,41.9691587]},"n1820938884":{"id":"n1820938884","loc":[-85.3219802,41.9721899]},"n1820938885":{"id":"n1820938885","loc":[-85.3091378,41.9699325]},"n1820938887":{"id":"n1820938887","loc":[-85.4242367,42.0085203]},"n1820938888":{"id":"n1820938888","loc":[-84.9968377,42.0874504]},"n1820938890":{"id":"n1820938890","loc":[-85.5443139,41.9714078]},"n1820938891":{"id":"n1820938891","loc":[-85.6404013,41.9154676]},"n1820938892":{"id":"n1820938892","loc":[-85.3644986,41.9962582]},"n1820938893":{"id":"n1820938893","loc":[-85.0496772,42.1018323]},"n1820938894":{"id":"n1820938894","loc":[-85.297261,41.9737373]},"n1820938895":{"id":"n1820938895","loc":[-85.0327096,42.098071]},"n1820938896":{"id":"n1820938896","loc":[-85.3856773,41.9996867]},"n1820938897":{"id":"n1820938897","loc":[-85.0493862,42.1015509]},"n1820938898":{"id":"n1820938898","loc":[-84.9969879,42.0876614]},"n1820938899":{"id":"n1820938899","loc":[-85.0848625,42.1013587]},"n1820938900":{"id":"n1820938900","loc":[-85.5853195,41.9479201]},"n1820938901":{"id":"n1820938901","loc":[-85.6329169,41.9387964]},"n1820938902":{"id":"n1820938902","loc":[-85.0843046,42.1029468]},"n1820938903":{"id":"n1820938903","loc":[-85.1228747,42.0778474]},"n1820938904":{"id":"n1820938904","loc":[-85.4855456,41.984095]},"n1820938905":{"id":"n1820938905","loc":[-85.0573269,42.1026801]},"n1820938906":{"id":"n1820938906","loc":[-85.2425868,42.0131523]},"n1820938907":{"id":"n1820938907","loc":[-85.1149622,42.0860053]},"n1820938908":{"id":"n1820938908","loc":[-85.4833097,41.9951578]},"n1820938909":{"id":"n1820938909","loc":[-85.075979,42.1056372]},"n1820938910":{"id":"n1820938910","loc":[-85.0338509,42.0977139]},"n1820938911":{"id":"n1820938911","loc":[-85.6384272,41.9115715]},"n1820938912":{"id":"n1820938912","loc":[-85.0458363,42.1004074]},"n1820938913":{"id":"n1820938913","loc":[-85.0592138,42.1048305]},"n1820938914":{"id":"n1820938914","loc":[-85.2807493,41.9916653]},"n1820938915":{"id":"n1820938915","loc":[-85.1103274,42.0864193]},"n1820938916":{"id":"n1820938916","loc":[-85.6267156,41.9404404]},"n1820938918":{"id":"n1820938918","loc":[-85.0331374,42.0982911]},"n1820938919":{"id":"n1820938919","loc":[-85.5637331,41.965409]},"n1820938920":{"id":"n1820938920","loc":[-85.5457515,41.9714237]},"n1820938922":{"id":"n1820938922","loc":[-85.082073,42.1030104]},"n1820938923":{"id":"n1820938923","loc":[-85.0780765,42.103102]},"n1820938924":{"id":"n1820938924","loc":[-85.4208035,42.0089508]},"n1820938925":{"id":"n1820938925","loc":[-85.3469934,41.9914795]},"n1820938926":{"id":"n1820938926","loc":[-85.0322,42.095619]},"n1820938927":{"id":"n1820938927","loc":[-85.4784431,41.9949401]},"n1820938928":{"id":"n1820938928","loc":[-85.1303095,42.0667523]},"n1820938929":{"id":"n1820938929","loc":[-85.2463784,42.0084781]},"n1820938930":{"id":"n1820938930","loc":[-85.6299986,41.9427707]},"n1820938931":{"id":"n1820938931","loc":[-85.6325907,41.9238499]},"n1820938932":{"id":"n1820938932","loc":[-85.4808464,41.9914476]},"n1820938934":{"id":"n1820938934","loc":[-85.2411599,42.0105292]},"n1820938935":{"id":"n1820938935","loc":[-85.0163213,42.0892379]},"n1820938936":{"id":"n1820938936","loc":[-85.3290934,41.9682322]},"n1820938937":{"id":"n1820938937","loc":[-85.4925623,41.9853231]},"n1820938938":{"id":"n1820938938","loc":[-85.0338294,42.09892]},"n1820938940":{"id":"n1820938940","loc":[-85.4174561,42.008903]},"n1820938941":{"id":"n1820938941","loc":[-85.1165595,42.0838845]},"n1820938942":{"id":"n1820938942","loc":[-85.2954585,41.9717192]},"n1820938943":{"id":"n1820938943","loc":[-85.6330199,41.9257338]},"n1820938944":{"id":"n1820938944","loc":[-85.2294654,42.0324478]},"n1820938945":{"id":"n1820938945","loc":[-85.5601282,41.9728914]},"n1820938946":{"id":"n1820938946","loc":[-85.1176324,42.08568]},"n1820938947":{"id":"n1820938947","loc":[-85.0210245,42.0906005]},"n1820938948":{"id":"n1820938948","loc":[-85.0251887,42.09253]},"n1820938949":{"id":"n1820938949","loc":[-85.0895832,42.0939551]},"n1820938950":{"id":"n1820938950","loc":[-84.9915109,42.085842]},"n1820938951":{"id":"n1820938951","loc":[-85.2187366,42.0393486]},"n1820938952":{"id":"n1820938952","loc":[-85.006605,42.087579]},"n1820938953":{"id":"n1820938953","loc":[-85.046641,42.1012393]},"n1820938954":{"id":"n1820938954","loc":[-85.052102,42.103695]},"n1820938955":{"id":"n1820938955","loc":[-85.283925,41.9912825]},"n1820938956":{"id":"n1820938956","loc":[-85.2326626,42.0316349]},"n1820938957":{"id":"n1820938957","loc":[-85.1174298,42.0859694]},"n1820938958":{"id":"n1820938958","loc":[-85.3802056,41.9994794]},"n1820938959":{"id":"n1820938959","loc":[-85.4586334,41.9999737]},"n1820938960":{"id":"n1820938960","loc":[-85.4302234,42.0069418]},"n1820938961":{"id":"n1820938961","loc":[-85.092201,42.0930674]},"n1820938962":{"id":"n1820938962","loc":[-85.3684511,41.9979382]},"n1820938963":{"id":"n1820938963","loc":[-85.4618735,42.0011856]},"n1820938964":{"id":"n1820938964","loc":[-85.4828205,41.9877793]},"n1820938965":{"id":"n1820938965","loc":[-85.0837789,42.1025726]},"n1820938966":{"id":"n1820938966","loc":[-85.0176195,42.090253]},"n1820938967":{"id":"n1820938967","loc":[-85.3801627,42.001074]},"n1820938968":{"id":"n1820938968","loc":[-85.4767007,41.994488]},"n1820938969":{"id":"n1820938969","loc":[-85.274268,41.9957495]},"n1820938970":{"id":"n1820938970","loc":[-85.2977438,41.9719506]},"n1820938971":{"id":"n1820938971","loc":[-85.2425546,42.0208682]},"n1820938972":{"id":"n1820938972","loc":[-85.2557082,42.002382]},"n1820938973":{"id":"n1820938973","loc":[-85.3187937,41.9691986]},"n1820938975":{"id":"n1820938975","loc":[-85.2448077,42.0153045]},"n1820938977":{"id":"n1820938977","loc":[-85.0343015,42.0997718]},"n1820938978":{"id":"n1820938978","loc":[-85.2449364,42.01874]},"n1820938979":{"id":"n1820938979","loc":[-85.2598391,41.9969602]},"n1820938980":{"id":"n1820938980","loc":[-85.4294724,42.0067665]},"n1820938981":{"id":"n1820938981","loc":[-85.428082,42.0055124]},"n1820938983":{"id":"n1820938983","loc":[-85.5436315,41.9717484]},"n1820938985":{"id":"n1820938985","loc":[-85.5978336,41.9407437]},"n1820938986":{"id":"n1820938986","loc":[-85.491661,41.9860249]},"n1820938987":{"id":"n1820938987","loc":[-85.4942789,41.9801392]},"n1820938988":{"id":"n1820938988","loc":[-85.0416306,42.1010841]},"n1820938989":{"id":"n1820938989","loc":[-85.2653644,41.9984433]},"n1820938990":{"id":"n1820938990","loc":[-85.1028266,42.0881124]},"n1820938991":{"id":"n1820938991","loc":[-85.0163146,42.0887932]},"n1820938992":{"id":"n1820938992","loc":[-85.5282209,41.9678112]},"n1820938993":{"id":"n1820938993","loc":[-85.5442752,41.9715888]},"n1820938994":{"id":"n1820938994","loc":[-85.5634327,41.9658558]},"n1820938995":{"id":"n1820938995","loc":[-85.0384227,42.1037627]},"n1820938996":{"id":"n1820938996","loc":[-85.1144258,42.0854439]},"n1820938997":{"id":"n1820938997","loc":[-85.1870651,42.0506305]},"n1820938998":{"id":"n1820938998","loc":[-85.1256159,42.0747376]},"n1820938999":{"id":"n1820938999","loc":[-85.3272695,41.9715836]},"n1820939000":{"id":"n1820939000","loc":[-85.0543067,42.103098]},"n1820939001":{"id":"n1820939001","loc":[-85.4678173,41.9973585]},"n1820939003":{"id":"n1820939003","loc":[-85.0266626,42.0933154]},"n1820939004":{"id":"n1820939004","loc":[-85.0353046,42.1019728]},"n1820939005":{"id":"n1820939005","loc":[-85.1237961,42.0762798]},"n1820939006":{"id":"n1820939006","loc":[-85.2812214,41.9826702]},"n1820939007":{"id":"n1820939007","loc":[-85.2927763,41.9747343]},"n1820939008":{"id":"n1820939008","loc":[-85.3270979,41.9720862]},"n1820939009":{"id":"n1820939009","loc":[-85.488657,41.9856581]},"n1820939010":{"id":"n1820939010","loc":[-85.3087301,41.9701399]},"n1820939011":{"id":"n1820939011","loc":[-85.0276939,42.093768]},"n1820939012":{"id":"n1820939012","loc":[-85.2956516,41.9748779]},"n1820939013":{"id":"n1820939013","loc":[-85.1298579,42.0726443]},"n1820939014":{"id":"n1820939014","loc":[-85.105144,42.0870893]},"n1820939015":{"id":"n1820939015","loc":[-85.0677486,42.1053917]},"n1820939016":{"id":"n1820939016","loc":[-85.0333681,42.0993459]},"n1820939017":{"id":"n1820939017","loc":[-85.6384272,41.910805]},"n1820939018":{"id":"n1820939018","loc":[-85.399496,42.006894]},"n1820939019":{"id":"n1820939019","loc":[-85.2648427,41.9998318]},"n1820939020":{"id":"n1820939020","loc":[-85.1237424,42.0766779]},"n1820939021":{"id":"n1820939021","loc":[-85.2515025,42.0109442]},"n1820939022":{"id":"n1820939022","loc":[-85.5566306,41.9718385]},"n1820939023":{"id":"n1820939023","loc":[-85.090644,42.0938369]},"n1820939024":{"id":"n1820939024","loc":[-85.1245525,42.074914]},"n1820939025":{"id":"n1820939025","loc":[-85.1099934,42.0863926]},"n1820939026":{"id":"n1820939026","loc":[-85.1251653,42.0744589]},"n1820939027":{"id":"n1820939027","loc":[-85.401792,42.0068143]},"n1820939028":{"id":"n1820939028","loc":[-85.0094763,42.0899584]},"n1820939029":{"id":"n1820939029","loc":[-85.1330779,42.0705605]},"n1820939030":{"id":"n1820939030","loc":[-85.4935064,41.984398]},"n1820939031":{"id":"n1820939031","loc":[-85.5713334,41.9613939]},"n1820939032":{"id":"n1820939032","loc":[-85.0873945,42.0964669]},"n1820939033":{"id":"n1820939033","loc":[-85.0886497,42.0986481]},"n1820939034":{"id":"n1820939034","loc":[-85.3276343,41.9758897]},"n1820939035":{"id":"n1820939035","loc":[-85.1304386,42.0727387]},"n1820939036":{"id":"n1820939036","loc":[-85.2551932,42.0052999]},"n1820939037":{"id":"n1820939037","loc":[-85.2206936,42.0384458]},"n1820939038":{"id":"n1820939038","loc":[-85.2313645,42.0286389]},"n1820939039":{"id":"n1820939039","loc":[-85.0754586,42.1059835]},"n1820939040":{"id":"n1820939040","loc":[-85.0663324,42.1050812]},"n1820939041":{"id":"n1820939041","loc":[-85.2406234,42.0106887]},"n1820939042":{"id":"n1820939042","loc":[-85.0685962,42.1058175]},"n1820939043":{"id":"n1820939043","loc":[-85.0689462,42.1059437]},"n1820939044":{"id":"n1820939044","loc":[-85.0586144,42.1046144]},"n1820939045":{"id":"n1820939045","loc":[-85.3650565,41.9965452]},"n1820939047":{"id":"n1820939047","loc":[-85.5752558,41.9536014]},"n1820939048":{"id":"n1820939048","loc":[-85.5110159,41.9710624]},"n1820939050":{"id":"n1820939050","loc":[-85.2832641,41.9926477]},"n1820939051":{"id":"n1820939051","loc":[-85.0078402,42.0898947]},"n1820939052":{"id":"n1820939052","loc":[-85.3882737,42.0017916]},"n1820939053":{"id":"n1820939053","loc":[-85.1718945,42.0564937]},"n1820939054":{"id":"n1820939054","loc":[-85.0947048,42.0929293]},"n1820939055":{"id":"n1820939055","loc":[-85.4456944,42.0051082]},"n1820939056":{"id":"n1820939056","loc":[-85.3139872,41.9706903]},"n1820939057":{"id":"n1820939057","loc":[-85.3893895,42.0034021]},"n1820939058":{"id":"n1820939058","loc":[-85.2425332,42.0106089]},"n1820939059":{"id":"n1820939059","loc":[-85.6085624,41.9420844]},"n1820939060":{"id":"n1820939060","loc":[-85.210411,42.0397789]},"n1820939061":{"id":"n1820939061","loc":[-85.2762542,41.9960473]},"n1820939062":{"id":"n1820939062","loc":[-85.4686584,41.9969973]},"n1820939063":{"id":"n1820939063","loc":[-85.3860421,42.0018394]},"n1820939064":{"id":"n1820939064","loc":[-85.5636944,41.9644414]},"n1820939065":{"id":"n1820939065","loc":[-85.3267331,41.9766554]},"n1820939066":{"id":"n1820939066","loc":[-85.0868996,42.0943822]},"n1820939067":{"id":"n1820939067","loc":[-85.104861,42.0880038]},"n1820939068":{"id":"n1820939068","loc":[-85.5537123,41.9695093]},"n1820939069":{"id":"n1820939069","loc":[-85.6325092,41.9396743]},"n1820939070":{"id":"n1820939070","loc":[-85.3869648,42.0024454]},"n1820939071":{"id":"n1820939071","loc":[-85.2775349,41.9957335]},"n1820939072":{"id":"n1820939072","loc":[-85.2055616,42.0421533]},"n1820939073":{"id":"n1820939073","loc":[-85.4731431,41.9946531]},"n1820939074":{"id":"n1820939074","loc":[-85.0399609,42.1030833]},"n1820939075":{"id":"n1820939075","loc":[-85.3055758,41.9725169]},"n1820939076":{"id":"n1820939076","loc":[-85.4834599,41.994488]},"n1820939077":{"id":"n1820939077","loc":[-85.3819866,42.0023018]},"n1820939078":{"id":"n1820939078","loc":[-85.1218756,42.0789992]},"n1820939079":{"id":"n1820939079","loc":[-85.2793159,41.9944458]},"n1820939080":{"id":"n1820939080","loc":[-85.2495498,42.0101466]},"n1820939081":{"id":"n1820939081","loc":[-85.0035969,42.0872434]},"n1820939082":{"id":"n1820939082","loc":[-85.1054243,42.0865626]},"n1820939083":{"id":"n1820939083","loc":[-85.0917665,42.0934774]},"n1820939084":{"id":"n1820939084","loc":[-85.3442211,41.988938]},"n1820939086":{"id":"n1820939086","loc":[-85.273989,41.9953588]},"n1820939087":{"id":"n1820939087","loc":[-85.1142541,42.0852488]},"n1820939089":{"id":"n1820939089","loc":[-85.1526684,42.0615758]},"n1820939090":{"id":"n1820939090","loc":[-85.2538843,42.0110159]},"n1820939091":{"id":"n1820939091","loc":[-85.28341,41.9909635]},"n1820939092":{"id":"n1820939092","loc":[-85.3963178,42.0050217]},"n1820939093":{"id":"n1820939093","loc":[-85.0851682,42.1012472]},"n1820939095":{"id":"n1820939095","loc":[-85.2811784,41.986243]},"n1820939096":{"id":"n1820939096","loc":[-85.4274125,42.0052995]},"n1820939097":{"id":"n1820939097","loc":[-85.0871262,42.0951652]},"n1820939099":{"id":"n1820939099","loc":[-85.1314253,42.0671665]},"n1820939100":{"id":"n1820939100","loc":[-85.2778997,41.991001]},"n1820939101":{"id":"n1820939101","loc":[-85.112107,42.0862812]},"n1820939102":{"id":"n1820939102","loc":[-85.299911,41.9729955]},"n1820939103":{"id":"n1820939103","loc":[-85.639822,41.9094796]},"n1820939104":{"id":"n1820939104","loc":[-85.122294,42.0785334]},"n1820939105":{"id":"n1820939105","loc":[-85.2476294,42.015719]},"n1820939106":{"id":"n1820939106","loc":[-85.4946007,41.9814631]},"n1820939107":{"id":"n1820939107","loc":[-85.0879524,42.0986919]},"n1820939108":{"id":"n1820939108","loc":[-85.0342814,42.098274]},"n1820939109":{"id":"n1820939109","loc":[-85.2450695,42.0095463]},"n1820939110":{"id":"n1820939110","loc":[-85.3847546,42.0024135]},"n1820939111":{"id":"n1820939111","loc":[-85.2961344,41.9742558]},"n1820939112":{"id":"n1820939112","loc":[-85.27899,41.994317]},"n1820939114":{"id":"n1820939114","loc":[-85.1017644,42.0886618]},"n1820939115":{"id":"n1820939115","loc":[-85.076215,42.1056333]},"n1820939116":{"id":"n1820939116","loc":[-85.1198009,42.0805349]},"n1820939117":{"id":"n1820939117","loc":[-85.11988,42.0798513]},"n1820939118":{"id":"n1820939118","loc":[-85.147819,42.0625476]},"n1820939119":{"id":"n1820939119","loc":[-85.0585969,42.1029042]},"n1820939120":{"id":"n1820939120","loc":[-85.1248596,42.0745744]},"n1820939121":{"id":"n1820939121","loc":[-85.3023786,41.9725249]},"n1820939123":{"id":"n1820939123","loc":[-85.0119332,42.0900699]},"n1820939124":{"id":"n1820939124","loc":[-85.2466852,42.0170343]},"n1820939125":{"id":"n1820939125","loc":[-85.0033019,42.0872792]},"n1820939126":{"id":"n1820939126","loc":[-85.0042084,42.0875778]},"n1820939128":{"id":"n1820939128","loc":[-85.0052961,42.0885424]},"n1820939130":{"id":"n1820939130","loc":[-85.0647942,42.10508]},"n1820939131":{"id":"n1820939131","loc":[-85.2824123,41.9825107]},"n1820939132":{"id":"n1820939132","loc":[-85.3210039,41.9723255]},"n1820939133":{"id":"n1820939133","loc":[-85.0491033,42.1014184]},"n1820939134":{"id":"n1820939134","loc":[-85.1127776,42.0855168]},"n1820939135":{"id":"n1820939135","loc":[-85.1243768,42.0759322]},"n1820939137":{"id":"n1820939137","loc":[-85.125974,42.0747547]},"n1820939138":{"id":"n1820939138","loc":[-85.1071248,42.0859973]},"n1820939139":{"id":"n1820939139","loc":[-85.5326175,41.9674833]},"n1820939140":{"id":"n1820939140","loc":[-85.1338715,42.0660833]},"n1820939142":{"id":"n1820939142","loc":[-85.649671,41.9135675]},"n1820939144":{"id":"n1820939144","loc":[-85.0236545,42.0920444]},"n1820939145":{"id":"n1820939145","loc":[-85.1084391,42.0859376]},"n1820939146":{"id":"n1820939146","loc":[-85.1539988,42.0618626]},"n1820939147":{"id":"n1820939147","loc":[-85.2354521,42.026511]},"n1820939148":{"id":"n1820939148","loc":[-85.2362246,42.0260408]},"n1820939149":{"id":"n1820939149","loc":[-85.2401342,42.0115233]},"n1820939150":{"id":"n1820939150","loc":[-85.295319,41.9747423]},"n1820939151":{"id":"n1820939151","loc":[-85.1164696,42.0835409]},"n1820939152":{"id":"n1820939152","loc":[-85.3232891,41.9712885]},"n1820939153":{"id":"n1820939153","loc":[-85.2574463,42.0068944]},"n1820939155":{"id":"n1820939155","loc":[-85.5704064,41.9598246]},"n1820939156":{"id":"n1820939156","loc":[-85.0349077,42.0998116]},"n1820939157":{"id":"n1820939157","loc":[-85.0949529,42.0925619]},"n1820939159":{"id":"n1820939159","loc":[-85.0179829,42.0902343]},"n1820939160":{"id":"n1820939160","loc":[-85.0405832,42.1016942]},"n1820939161":{"id":"n1820939161","loc":[-85.2534015,42.0111833]},"n1820939162":{"id":"n1820939162","loc":[-85.0839881,42.102708]},"n1820939163":{"id":"n1820939163","loc":[-85.0341996,42.1008385]},"n1820939164":{"id":"n1820939164","loc":[-85.1037761,42.0879731]},"n1820939173":{"id":"n1820939173","loc":[-85.0460616,42.1005786]},"n1820939177":{"id":"n1820939177","loc":[-85.0061651,42.0878059]},"n1820939181":{"id":"n1820939181","loc":[-85.1456775,42.0654684]},"n1820939183":{"id":"n1820939183","loc":[-85.1325508,42.0718439]},"n1820939185":{"id":"n1820939185","loc":[-85.2485842,42.008329]},"n1820939187":{"id":"n1820939187","loc":[-85.2744128,41.9949322]},"n1820939189":{"id":"n1820939189","loc":[-85.2579025,41.9999542]},"n1820939191":{"id":"n1820939191","loc":[-85.3358998,41.9828987]},"n1820939193":{"id":"n1820939193","loc":[-85.3192658,41.9716714]},"n1820939194":{"id":"n1820939194","loc":[-85.6400795,41.9130725]},"n1820939195":{"id":"n1820939195","loc":[-85.3278489,41.9780591]},"n1820939196":{"id":"n1820939196","loc":[-85.2800197,41.983061]},"n1820939197":{"id":"n1820939197","loc":[-85.3278167,41.9692943]},"n1820939198":{"id":"n1820939198","loc":[-85.3366894,41.9838653]},"n1820939199":{"id":"n1820939199","loc":[-85.0328383,42.0969923]},"n1820939201":{"id":"n1820939201","loc":[-85.3259284,41.9720383]},"n1820939217":{"id":"n1820939217","loc":[-85.1840181,42.0503277]},"n1820939220":{"id":"n1820939220","loc":[-85.422563,42.0089986]},"n1820939222":{"id":"n1820939222","loc":[-85.555386,41.9707856]},"n1820939224":{"id":"n1820939224","loc":[-85.3830809,42.002254]},"n1820939226":{"id":"n1820939226","loc":[-84.9917938,42.0857517]},"n1820939227":{"id":"n1820939227","loc":[-85.2936775,41.9740484]},"n1820939228":{"id":"n1820939228","loc":[-85.2632133,41.9975024]},"n1820939229":{"id":"n1820939229","loc":[-85.2809424,41.9853259]},"n1820939230":{"id":"n1820939230","loc":[-85.242104,42.0131204]},"n1820939232":{"id":"n1820939232","loc":[-85.2610246,41.9963901]},"n1820939233":{"id":"n1820939233","loc":[-85.2335531,42.0268378]},"n1820939234":{"id":"n1820939234","loc":[-85.3188839,41.9713575]},"n1820939235":{"id":"n1820939235","loc":[-85.2413637,42.0225658]},"n1820939237":{"id":"n1820939237","loc":[-85.0010796,42.0887215]},"n1820939239":{"id":"n1820939239","loc":[-85.2241697,42.0362624]},"n1820939243":{"id":"n1820939243","loc":[-85.0368456,42.1040134]},"n1820939244":{"id":"n1820939244","loc":[-85.1327986,42.069524]},"n1820939260":{"id":"n1820939260","loc":[-85.5408163,41.9711206]},"n1820939261":{"id":"n1820939261","loc":[-85.2959199,41.9746546]},"n1820939262":{"id":"n1820939262","loc":[-85.3298659,41.9683598]},"n1820939263":{"id":"n1820939263","loc":[-85.2240581,42.0358425]},"n1820939264":{"id":"n1820939264","loc":[-85.2438206,42.0101944]},"n1820939265":{"id":"n1820939265","loc":[-85.3984489,42.0059589]},"n1820939266":{"id":"n1820939266","loc":[-85.2330811,42.0294279]},"n1820939268":{"id":"n1820939268","loc":[-85.1126877,42.0857704]},"n1820939271":{"id":"n1820939271","loc":[-85.254925,42.0106253]},"n1820939273":{"id":"n1820939273","loc":[-85.4328046,42.0064662]},"n1820939277":{"id":"n1820939277","loc":[-85.289622,41.9789616]},"n1820939279":{"id":"n1820939279","loc":[-85.4574532,42.0004043]},"n1820939281":{"id":"n1820939281","loc":[-85.4803486,41.9867211]},"n1820939283":{"id":"n1820939283","loc":[-85.157475,42.0631848]},"n1820939285":{"id":"n1820939285","loc":[-85.2571458,42.0059935]},"n1820939287":{"id":"n1820939287","loc":[-85.2818544,41.9825984]},"n1820939289":{"id":"n1820939289","loc":[-85.2298302,42.0328781]},"n1820939291":{"id":"n1820939291","loc":[-85.4819523,41.984821]},"n1820939301":{"id":"n1820939301","loc":[-85.3139765,41.9701159]},"n1820939304":{"id":"n1820939304","loc":[-85.0424447,42.101742]},"n1820939306":{"id":"n1820939306","loc":[-85.6360283,41.9338482]},"n1820939310":{"id":"n1820939310","loc":[-85.3463025,41.9913622]},"n1820939312":{"id":"n1820939312","loc":[-85.4664869,41.9988097]},"n1820939314":{"id":"n1820939314","loc":[-85.149364,42.0622449]},"n1820939316":{"id":"n1820939316","loc":[-85.2460415,42.0153125]},"n1820939318":{"id":"n1820939318","loc":[-85.4806103,41.9924523]},"n1820939320":{"id":"n1820939320","loc":[-85.2449042,42.0190987]},"n1820939322":{"id":"n1820939322","loc":[-85.5280165,41.9689263]},"n1820939324":{"id":"n1820939324","loc":[-85.0051204,42.0882625]},"n1820939326":{"id":"n1820939326","loc":[-85.1240925,42.0771546]},"n1820939329":{"id":"n1820939329","loc":[-85.2261653,42.0342225]},"n1820939331":{"id":"n1820939331","loc":[-85.5259933,41.972211]},"n1820939333":{"id":"n1820939333","loc":[-85.0074754,42.0883183]},"n1820939335":{"id":"n1820939335","loc":[-85.0764014,42.1055549]},"n1820939336":{"id":"n1820939336","loc":[-85.2908773,41.9769597]},"n1820939337":{"id":"n1820939337","loc":[-85.4095382,42.0083449]},"n1820939346":{"id":"n1820939346","loc":[-85.2514166,42.0111753]},"n1820939348":{"id":"n1820939348","loc":[-85.0030377,42.0873799]},"n1820939350":{"id":"n1820939350","loc":[-85.3659362,41.9964974]},"n1820939352":{"id":"n1820939352","loc":[-85.226058,42.0348281]},"n1820939355":{"id":"n1820939355","loc":[-85.1902408,42.0507101]},"n1820939357":{"id":"n1820939357","loc":[-85.2781854,41.9946001]},"n1820939359":{"id":"n1820939359","loc":[-85.2139988,42.0405175]},"n1820939361":{"id":"n1820939361","loc":[-85.0086609,42.0908262]},"n1820939363":{"id":"n1820939363","loc":[-85.0627128,42.1043398]},"n1820939365":{"id":"n1820939365","loc":[-85.1311346,42.072501]},"n1820939369":{"id":"n1820939369","loc":[-85.248198,42.0082652]},"n1820939370":{"id":"n1820939370","loc":[-84.99792,42.087794]},"n1820939371":{"id":"n1820939371","loc":[-85.2786775,41.9942783]},"n1820939372":{"id":"n1820939372","loc":[-85.0342103,42.1013957]},"n1820939373":{"id":"n1820939373","loc":[-85.2022357,42.0444799]},"n1820939374":{"id":"n1820939374","loc":[-85.2279205,42.0337388]},"n1820939375":{"id":"n1820939375","loc":[-85.1337699,42.0712614]},"n1820939376":{"id":"n1820939376","loc":[-85.317517,41.9707062]},"n1820939377":{"id":"n1820939377","loc":[-85.1326326,42.070218]},"n1820939394":{"id":"n1820939394","loc":[-85.0197746,42.0899118]},"n1820939397":{"id":"n1820939397","loc":[-85.2590076,41.9984632]},"n1820939399":{"id":"n1820939399","loc":[-85.2469964,42.0083449]},"n1820939400":{"id":"n1820939400","loc":[-85.2470929,42.0146668]},"n1820939401":{"id":"n1820939401","loc":[-84.9984095,42.0878087]},"n1820939402":{"id":"n1820939402","loc":[-85.2372653,42.0243273]},"n1820939403":{"id":"n1820939403","loc":[-85.2454986,42.0091955]},"n1820939404":{"id":"n1820939404","loc":[-85.0539205,42.1035995]},"n1820939405":{"id":"n1820939405","loc":[-85.550601,41.9706101]},"n1820939406":{"id":"n1820939406","loc":[-85.0351343,42.0999656]},"n1820939407":{"id":"n1820939407","loc":[-85.0082908,42.0905755]},"n1820939408":{"id":"n1820939408","loc":[-85.0132904,42.0902251]},"n1820939410":{"id":"n1820939410","loc":[-85.0892546,42.094012]},"n1820939412":{"id":"n1820939412","loc":[-85.0350793,42.1030315]},"n1820939416":{"id":"n1820939416","loc":[-85.0012406,42.0886777]},"n1820939418":{"id":"n1820939418","loc":[-85.0577453,42.1029229]},"n1820939420":{"id":"n1820939420","loc":[-85.1230786,42.0776722]},"n1820939422":{"id":"n1820939422","loc":[-85.571136,41.9649304]},"n1820939436":{"id":"n1820939436","loc":[-85.1137968,42.0848997]},"n1820939437":{"id":"n1820939437","loc":[-85.3559584,41.9925105]},"n1820939438":{"id":"n1820939438","loc":[-85.0080172,42.0903565]},"n1820939439":{"id":"n1820939439","loc":[-85.0048897,42.0880913]},"n1820939441":{"id":"n1820939441","loc":[-85.0406959,42.1018574]},"n1820939443":{"id":"n1820939443","loc":[-85.3897328,42.0029078]},"n1820939445":{"id":"n1820939445","loc":[-85.122349,42.0782814]},"n1820939448":{"id":"n1820939448","loc":[-85.4872193,41.985036]},"n1820939450":{"id":"n1820939450","loc":[-85.0120459,42.0904919]},"n1820939452":{"id":"n1820939452","loc":[-85.6320543,41.921982]},"n1820939456":{"id":"n1820939456","loc":[-85.0844749,42.1036843]},"n1820939458":{"id":"n1820939458","loc":[-85.0968037,42.091296]},"n1820939463":{"id":"n1820939463","loc":[-85.5339747,41.9681841]},"n1820939465":{"id":"n1820939465","loc":[-85.4125423,42.0072129]},"n1820939467":{"id":"n1820939467","loc":[-85.6335563,41.9303626]},"n1820939469":{"id":"n1820939469","loc":[-85.2821014,41.9932126]},"n1820939471":{"id":"n1820939471","loc":[-85.374691,41.9969917]},"n1820939485":{"id":"n1820939485","loc":[-85.4471321,42.0049806]},"n1820939487":{"id":"n1820939487","loc":[-85.3752532,41.9972206]},"n1820939489":{"id":"n1820939489","loc":[-85.4517283,42.005927]},"n1820939492":{"id":"n1820939492","loc":[-85.4662552,42.0005693]},"n1820939494":{"id":"n1820939494","loc":[-85.0120083,42.0902928]},"n1820939496":{"id":"n1820939496","loc":[-85.044463,42.1004631]},"n1820939498":{"id":"n1820939498","loc":[-85.418293,42.0089667]},"n1820939500":{"id":"n1820939500","loc":[-85.0554762,42.1027358]},"n1820939504":{"id":"n1820939504","loc":[-85.1246289,42.0746858]},"n1820939507":{"id":"n1820939507","loc":[-85.0408139,42.1021838]},"n1820939508":{"id":"n1820939508","loc":[-85.1236204,42.0775169]},"n1820939509":{"id":"n1820939509","loc":[-85.0350109,42.1037428]},"n1820939510":{"id":"n1820939510","loc":[-85.0551583,42.1029878]},"n1820939511":{"id":"n1820939511","loc":[-85.0956771,42.0916662]},"n1820939512":{"id":"n1820939512","loc":[-85.2323408,42.0273638]},"n1820939513":{"id":"n1820939513","loc":[-85.1232771,42.0762388]},"n1820939531":{"id":"n1820939531","loc":[-85.264608,41.9997828]},"n1820939533":{"id":"n1820939533","loc":[-85.4198808,42.0087914]},"n1820939535":{"id":"n1820939535","loc":[-85.3080864,41.9715677]},"n1820939536":{"id":"n1820939536","loc":[-85.1189426,42.0812596]},"n1820939537":{"id":"n1820939537","loc":[-85.2642741,41.9996764]},"n1820939538":{"id":"n1820939538","loc":[-85.2572531,42.0079627]},"n1820939539":{"id":"n1820939539","loc":[-85.2907807,41.9790174]},"n1820939540":{"id":"n1820939540","loc":[-85.3171415,41.9707301]},"n1820939541":{"id":"n1820939541","loc":[-85.08777,42.0953841]},"n1820939542":{"id":"n1820939542","loc":[-85.1239262,42.0773218]},"n1820939543":{"id":"n1820939543","loc":[-84.9973956,42.0877968]},"n1820939544":{"id":"n1820939544","loc":[-85.011606,42.0896161]},"n1820939545":{"id":"n1820939545","loc":[-85.4077358,42.0082971]},"n1820939546":{"id":"n1820939546","loc":[-85.3614945,41.9933717]},"n1820939547":{"id":"n1820939547","loc":[-85.3189118,41.9697649]},"n1820939550":{"id":"n1820939550","loc":[-85.1262691,42.0740221]},"n1820939551":{"id":"n1820939551","loc":[-85.3863639,41.9994635]},"n1820939552":{"id":"n1820939552","loc":[-85.2836034,41.9923953]},"n1820939554":{"id":"n1820939554","loc":[-85.3222377,41.9715916]},"n1820939555":{"id":"n1820939555","loc":[-85.0122658,42.0906312]},"n1820939556":{"id":"n1820939556","loc":[-85.0022652,42.0877581]},"n1820939557":{"id":"n1820939557","loc":[-85.1011314,42.0899954]},"n1820939559":{"id":"n1820939559","loc":[-85.0008181,42.0885293]},"n1820939561":{"id":"n1820939561","loc":[-85.3637046,41.9942488]},"n1820939562":{"id":"n1820939562","loc":[-85.4500117,42.0052892]},"n1820939563":{"id":"n1820939563","loc":[-85.0537636,42.1036365]},"n1820939565":{"id":"n1820939565","loc":[-85.2367503,42.0246939]},"n1820939566":{"id":"n1820939566","loc":[-85.0448479,42.1002653]},"n1820939567":{"id":"n1820939567","loc":[-85.6337065,41.9295006]},"n1820939568":{"id":"n1820939568","loc":[-85.0879792,42.095623]},"n1820939569":{"id":"n1820939569","loc":[-85.6347623,41.9352369]},"n1820939570":{"id":"n1820939570","loc":[-85.1497931,42.0620378]},"n1820939571":{"id":"n1820939571","loc":[-85.5676169,41.9656324]},"n1820939572":{"id":"n1820939572","loc":[-85.638041,41.9166971]},"n1820939573":{"id":"n1820939573","loc":[-85.4993429,41.9781293]},"n1820939574":{"id":"n1820939574","loc":[-85.5352831,41.9692127]},"n1820939575":{"id":"n1820939575","loc":[-84.9924429,42.0857118]},"n1820939577":{"id":"n1820939577","loc":[-85.0581101,42.1026721]},"n1820939578":{"id":"n1820939578","loc":[-85.641088,41.9094477]},"n1820939579":{"id":"n1820939579","loc":[-85.2548821,42.0052282]},"n1820939580":{"id":"n1820939580","loc":[-85.1124463,42.0859734]},"n1820939581":{"id":"n1820939581","loc":[-85.1083479,42.0857624]},"n1820939583":{"id":"n1820939583","loc":[-85.1387424,42.0648893]},"n1820939584":{"id":"n1820939584","loc":[-85.5152645,41.9700892]},"n1820939585":{"id":"n1820939585","loc":[-85.5463738,41.9713439]},"n1820939586":{"id":"n1820939586","loc":[-85.360207,41.9933717]},"n1820939587":{"id":"n1820939587","loc":[-85.2402372,42.0120917]},"n1820939588":{"id":"n1820939588","loc":[-85.3936381,42.0047255]},"n1820939589":{"id":"n1820939589","loc":[-85.3310246,41.973784]},"n1820939590":{"id":"n1820939590","loc":[-85.0329403,42.096642]},"n1820939591":{"id":"n1820939591","loc":[-85.0097271,42.0910981]},"n1820939593":{"id":"n1820939593","loc":[-85.0446562,42.1003437]},"n1820939595":{"id":"n1820939595","loc":[-85.0856671,42.1008452]},"n1820939596":{"id":"n1820939596","loc":[-85.4087228,42.0083449]},"n1820939597":{"id":"n1820939597","loc":[-85.0609519,42.1052564]},"n1820939598":{"id":"n1820939598","loc":[-85.3432126,41.9874548]},"n1820939599":{"id":"n1820939599","loc":[-85.4041738,42.0067027]},"n1820939600":{"id":"n1820939600","loc":[-85.0825437,42.1035768]},"n1820939601":{"id":"n1820939601","loc":[-85.048422,42.101498]},"n1820939602":{"id":"n1820939602","loc":[-85.0336256,42.0999031]},"n1820939603":{"id":"n1820939603","loc":[-85.046818,42.1014104]},"n1820939605":{"id":"n1820939605","loc":[-85.2856524,41.98078]},"n1820939607":{"id":"n1820939607","loc":[-85.1118173,42.0864245]},"n1820939609":{"id":"n1820939609","loc":[-85.0443397,42.1006263]},"n1820939610":{"id":"n1820939610","loc":[-85.0336698,42.0978361]},"n1820939611":{"id":"n1820939611","loc":[-85.4630322,42.0014248]},"n1820939612":{"id":"n1820939612","loc":[-85.0613127,42.1052353]},"n1820939613":{"id":"n1820939613","loc":[-85.0137571,42.0887801]},"n1820939614":{"id":"n1820939614","loc":[-85.272487,41.9982013]},"n1820939616":{"id":"n1820939616","loc":[-85.4665727,41.9983791]},"n1820939617":{"id":"n1820939617","loc":[-85.1288078,42.0725476]},"n1820939618":{"id":"n1820939618","loc":[-85.4653282,42.00109]},"n1820939619":{"id":"n1820939619","loc":[-85.2314717,42.0276746]},"n1820939620":{"id":"n1820939620","loc":[-85.255982,42.0003569]},"n1820939621":{"id":"n1820939621","loc":[-85.2886779,41.9787223]},"n1820939622":{"id":"n1820939622","loc":[-85.22438,42.0367509]},"n1820939623":{"id":"n1820939623","loc":[-85.0334713,42.0998382]},"n1820939624":{"id":"n1820939624","loc":[-85.2236504,42.037484]},"n1820939625":{"id":"n1820939625","loc":[-85.636908,41.9175162]},"n1820939627":{"id":"n1820939627","loc":[-85.2669187,41.9989707]},"n1820939628":{"id":"n1820939628","loc":[-85.3247268,41.9720702]},"n1820939629":{"id":"n1820939629","loc":[-85.3785104,41.9987299]},"n1820939630":{"id":"n1820939630","loc":[-85.5267658,41.9720515]},"n1820939631":{"id":"n1820939631","loc":[-85.2445116,42.0098811]},"n1820939632":{"id":"n1820939632","loc":[-85.1271448,42.0725077]},"n1820939633":{"id":"n1820939633","loc":[-85.0345751,42.099724]},"n1820939634":{"id":"n1820939634","loc":[-85.4217476,42.0089986]},"n1820939635":{"id":"n1820939635","loc":[-85.3121848,41.9689433]},"n1820939636":{"id":"n1820939636","loc":[-85.2826419,41.9929985]},"n1820939637":{"id":"n1820939637","loc":[-85.3160257,41.9706344]},"n1820939638":{"id":"n1820939638","loc":[-85.5684967,41.9657919]},"n1820939640":{"id":"n1820939640","loc":[-85.225131,42.0356194]},"n1820939642":{"id":"n1820939642","loc":[-85.1324124,42.0693328]},"n1820939644":{"id":"n1820939644","loc":[-84.9994073,42.0878843]},"n1820939645":{"id":"n1820939645","loc":[-85.1087596,42.0863329]},"n1820939646":{"id":"n1820939646","loc":[-85.2915532,41.9782996]},"n1820939647":{"id":"n1820939647","loc":[-84.9988708,42.0877808]},"n1820939648":{"id":"n1820939648","loc":[-85.2243628,42.0356728]},"n1820939649":{"id":"n1820939649","loc":[-85.0427397,42.1020524]},"n1820939650":{"id":"n1820939650","loc":[-85.6388392,41.9100752]},"n1820939651":{"id":"n1820939651","loc":[-85.0133709,42.0888557]},"n1820939652":{"id":"n1820939652","loc":[-85.318798,41.9701211]},"n1820939653":{"id":"n1820939653","loc":[-85.6335778,41.9190602]},"n1820939654":{"id":"n1820939654","loc":[-85.6338396,41.9370247]},"n1820939655":{"id":"n1820939655","loc":[-85.0939069,42.0931988]},"n1820939656":{"id":"n1820939656","loc":[-85.5702347,41.9651378]},"n1820939657":{"id":"n1820939657","loc":[-85.4235286,42.0088392]},"n1820939658":{"id":"n1820939658","loc":[-85.2740856,41.9972206]},"n1820939659":{"id":"n1820939659","loc":[-85.4824299,41.9934195]},"n1820939660":{"id":"n1820939660","loc":[-85.3857846,42.0014408]},"n1820939661":{"id":"n1820939661","loc":[-85.0451658,42.10028]},"n1820939662":{"id":"n1820939662","loc":[-85.3893036,42.001377]},"n1820939664":{"id":"n1820939664","loc":[-85.2455845,42.0088607]},"n1820939665":{"id":"n1820939665","loc":[-85.2741071,41.9951116]},"n1820939666":{"id":"n1820939666","loc":[-85.1298375,42.0677718]},"n1820939667":{"id":"n1820939667","loc":[-85.5491848,41.9707377]},"n1820939669":{"id":"n1820939669","loc":[-85.2780298,41.995238]},"n1820939670":{"id":"n1820939670","loc":[-85.1330068,42.0716926]},"n1820939671":{"id":"n1820939671","loc":[-85.0811342,42.1025129]},"n1820939672":{"id":"n1820939672","loc":[-85.2325124,42.0290135]},"n1820939673":{"id":"n1820939673","loc":[-85.2975077,41.9716953]},"n1820939674":{"id":"n1820939674","loc":[-85.0951729,42.0922394]},"n1820939676":{"id":"n1820939676","loc":[-85.0363252,42.1043119]},"n1820939677":{"id":"n1820939677","loc":[-85.2960057,41.97349]},"n1820939678":{"id":"n1820939678","loc":[-85.3701849,41.9982515]},"n1820939679":{"id":"n1820939679","loc":[-85.3381486,41.9848861]},"n1820939680":{"id":"n1820939680","loc":[-85.2058448,42.0417286]},"n1820939682":{"id":"n1820939682","loc":[-85.0819335,42.1034443]},"n1820939683":{"id":"n1820939683","loc":[-85.3872223,41.9993359]},"n1820939684":{"id":"n1820939684","loc":[-85.095366,42.091909]},"n1820939685":{"id":"n1820939685","loc":[-85.2327914,42.0291888]},"n1820939686":{"id":"n1820939686","loc":[-85.0433459,42.1018773]},"n1820939687":{"id":"n1820939687","loc":[-85.0585339,42.1027318]},"n1820939688":{"id":"n1820939688","loc":[-85.0062885,42.0876347]},"n1820939689":{"id":"n1820939689","loc":[-85.246299,42.017377]},"n1820939690":{"id":"n1820939690","loc":[-85.2932376,41.9742877]},"n1820939691":{"id":"n1820939691","loc":[-85.2962846,41.9736815]},"n1820939692":{"id":"n1820939692","loc":[-85.6052365,41.9409193]},"n1820939693":{"id":"n1820939693","loc":[-85.2570536,42.0003341]},"n1820939694":{"id":"n1820939694","loc":[-85.0488458,42.1014064]},"n1820939695":{"id":"n1820939695","loc":[-85.4050321,42.0069578]},"n1820939696":{"id":"n1820939696","loc":[-85.4847517,41.9845894]},"n1820939697":{"id":"n1820939697","loc":[-85.0844655,42.1013826]},"n1820939698":{"id":"n1820939698","loc":[-85.1437206,42.0650008]},"n1820939699":{"id":"n1820939699","loc":[-85.1168183,42.0864034]},"n1820939700":{"id":"n1820939700","loc":[-85.5479831,41.9711366]},"n1820939701":{"id":"n1820939701","loc":[-85.0349948,42.1034124]},"n1820939702":{"id":"n1820939702","loc":[-85.0835589,42.1038821]},"n1820939703":{"id":"n1820939703","loc":[-85.0203875,42.0902649]},"n1820939704":{"id":"n1820939704","loc":[-85.0371191,42.1038184]},"n1820939705":{"id":"n1820939705","loc":[-85.1273312,42.0735681]},"n1820939707":{"id":"n1820939707","loc":[-85.1272239,42.0730226]},"n1820939710":{"id":"n1820939710","loc":[-85.0349881,42.1019012]},"n1820939712":{"id":"n1820939712","loc":[-85.2440459,42.0178313]},"n1820939713":{"id":"n1820939713","loc":[-85.2444751,42.0182618]},"n1820939714":{"id":"n1820939714","loc":[-85.0539996,42.1032863]},"n1820939715":{"id":"n1820939715","loc":[-85.2215905,42.0373246]},"n1820939716":{"id":"n1820939716","loc":[-85.0649712,42.1051994]},"n1820939717":{"id":"n1820939717","loc":[-85.0927146,42.0927581]},"n1820939718":{"id":"n1820939718","loc":[-85.3884668,42.0042312]},"n1820939719":{"id":"n1820939719","loc":[-85.0840672,42.1013241]},"n1820939720":{"id":"n1820939720","loc":[-85.304739,41.9725408]},"n1820939721":{"id":"n1820939721","loc":[-85.2243585,42.0371334]},"n1820939722":{"id":"n1820939722","loc":[-85.0599823,42.1049686]},"n1820939723":{"id":"n1820939723","loc":[-85.0298825,42.0944288]},"n1820939724":{"id":"n1820939724","loc":[-85.0366095,42.1042443]},"n1820939725":{"id":"n1820939725","loc":[-85.0698783,42.1058135]},"n1820939726":{"id":"n1820939726","loc":[-85.1054551,42.0873361]},"n1820939727":{"id":"n1820939727","loc":[-84.9952324,42.0864285]},"n1820939728":{"id":"n1820939728","loc":[-85.3442211,41.9897993]},"n1820939729":{"id":"n1820939729","loc":[-85.4386134,42.0056822]},"n1820939730":{"id":"n1820939730","loc":[-85.2438528,42.0146589]},"n1820939731":{"id":"n1820939731","loc":[-85.0355581,42.1041846]},"n1820939732":{"id":"n1820939732","loc":[-85.557682,41.9724447]},"n1820939734":{"id":"n1820939734","loc":[-85.2299418,42.033314]},"n1820939735":{"id":"n1820939735","loc":[-85.6297412,41.9419088]},"n1820939736":{"id":"n1820939736","loc":[-85.2645101,41.9980259]},"n1820939738":{"id":"n1820939738","loc":[-85.082195,42.1035649]},"n1820939739":{"id":"n1820939739","loc":[-85.234272,42.0267102]},"n1820939740":{"id":"n1820939740","loc":[-85.0130758,42.0895006]},"n1820939741":{"id":"n1820939741","loc":[-85.4594702,42.0000375]},"n1820939742":{"id":"n1820939742","loc":[-84.9946745,42.0863687]},"n1820939743":{"id":"n1820939743","loc":[-85.6438775,41.9120186]},"n1820939744":{"id":"n1820939744","loc":[-85.6372685,41.9168089]},"n1820939745":{"id":"n1820939745","loc":[-85.2789468,41.9893208]},"n1820939747":{"id":"n1820939747","loc":[-85.3775019,41.998427]},"n1820939749":{"id":"n1820939749","loc":[-85.0993571,42.0909178]},"n1820939750":{"id":"n1820939750","loc":[-85.1308503,42.0669339]},"n1820939751":{"id":"n1820939751","loc":[-85.4802566,41.9856659]},"n1820939752":{"id":"n1820939752","loc":[-85.2543563,42.0108804]},"n1820939753":{"id":"n1820939753","loc":[-85.1041033,42.0878815]},"n1820939755":{"id":"n1820939755","loc":[-85.4000969,42.0071651]},"n1820939757":{"id":"n1820939757","loc":[-85.3858275,42.0022381]},"n1820939758":{"id":"n1820939758","loc":[-85.3653998,41.996609]},"n1820939759":{"id":"n1820939759","loc":[-85.2432949,42.0202305]},"n1820939760":{"id":"n1820939760","loc":[-85.3878874,42.0042472]},"n1820939761":{"id":"n1820939761","loc":[-85.2516741,42.0114145]},"n1820939762":{"id":"n1820939762","loc":[-85.2788825,41.9865142]},"n1820939763":{"id":"n1820939763","loc":[-85.0009147,42.0886686]},"n1820939764":{"id":"n1820939764","loc":[-85.3918142,42.003434]},"n1820939765":{"id":"n1820939765","loc":[-85.5532832,41.9696848]},"n1820939766":{"id":"n1820939766","loc":[-85.5545063,41.969254]},"n1820939768":{"id":"n1820939768","loc":[-85.1327989,42.0704769]},"n1820939770":{"id":"n1820939770","loc":[-85.0588558,42.1047696]},"n1820939772":{"id":"n1820939772","loc":[-85.555798,41.9713017]},"n1820939773":{"id":"n1820939773","loc":[-85.0565853,42.1023589]},"n1820939774":{"id":"n1820939774","loc":[-85.2582941,41.9992765]},"n1820939775":{"id":"n1820939775","loc":[-85.3007264,41.9727642]},"n1820939776":{"id":"n1820939776","loc":[-85.2477045,42.0082652]},"n1820939777":{"id":"n1820939777","loc":[-85.2415247,42.0104973]},"n1821006698":{"id":"n1821006698","loc":[-85.6345227,41.9382009]},"n1821006700":{"id":"n1821006700","loc":[-85.6344894,41.938975]},"n1821006704":{"id":"n1821006704","loc":[-85.6351181,41.9370157]},"n1821006706":{"id":"n1821006706","loc":[-85.6357554,41.9361657]},"n1821006708":{"id":"n1821006708","loc":[-85.6351235,41.9368481]},"n1821006710":{"id":"n1821006710","loc":[-85.6352844,41.9364211]},"n1821006712":{"id":"n1821006712","loc":[-85.6351503,41.937307]},"n1821006716":{"id":"n1821006716","loc":[-85.6350366,41.9379774]},"n1821006725":{"id":"n1821006725","loc":[-85.6352147,41.9375903]},"n1821137607":{"id":"n1821137607","loc":[-85.5297057,41.9669915]},"n1821137608":{"id":"n1821137608","loc":[-85.5288598,41.9673094]},"n1821139530":{"id":"n1821139530","loc":[-85.4832228,41.9881686]},"n1821139531":{"id":"n1821139531","loc":[-85.4812101,41.9851258]},"n1821139532":{"id":"n1821139532","loc":[-85.4799127,41.9860244]},"n1821139533":{"id":"n1821139533","loc":[-85.4800313,41.9865555]},"n1841425201":{"id":"n1841425201","loc":[-85.4334577,42.0063713]},"n1841425222":{"id":"n1841425222","loc":[-85.4382449,42.0055785]},"n1914861007":{"id":"n1914861007","loc":[-85.394959,42.0057472]},"n1914861057":{"id":"n1914861057","loc":[-85.3967185,42.0049695]},"n1914861112":{"id":"n1914861112","loc":[-85.394179,42.0056906]},"n1914861306":{"id":"n1914861306","loc":[-85.3900226,42.0028488]},"n2114807565":{"id":"n2114807565","loc":[-85.6385979,41.9577824]},"n2114807568":{"id":"n2114807568","loc":[-85.6325097,41.9775713]},"n2114807572":{"id":"n2114807572","loc":[-85.6328996,41.9980965]},"n2114807578":{"id":"n2114807578","loc":[-85.6344818,41.9696956]},"n2114807583":{"id":"n2114807583","loc":[-85.6326289,41.9757853]},"n2114807593":{"id":"n2114807593","loc":[-85.6360828,41.9650674]},"n2130304159":{"id":"n2130304159","loc":[-85.6352537,41.9450015],"tags":{"railway":"level_crossing"}},"n2139795852":{"id":"n2139795852","loc":[-85.6374708,41.9311633]},"n2139858882":{"id":"n2139858882","loc":[-85.635178,41.9356158]},"n2139858883":{"id":"n2139858883","loc":[-85.63533,41.9355886]},"n2139858884":{"id":"n2139858884","loc":[-85.6353819,41.93556]},"n2139858885":{"id":"n2139858885","loc":[-85.6353665,41.9355157]},"n2139858886":{"id":"n2139858886","loc":[-85.6353165,41.9354971]},"n2139858887":{"id":"n2139858887","loc":[-85.6352454,41.9355328]},"n2139858888":{"id":"n2139858888","loc":[-85.6350184,41.9357846]},"n2139858889":{"id":"n2139858889","loc":[-85.634978,41.9359448]},"n2139858890":{"id":"n2139858890","loc":[-85.6347723,41.9361523]},"n2139858891":{"id":"n2139858891","loc":[-85.6347165,41.9362667]},"n2139858892":{"id":"n2139858892","loc":[-85.6346992,41.9364312]},"n2139858893":{"id":"n2139858893","loc":[-85.634603,41.9366329]},"n2139858894":{"id":"n2139858894","loc":[-85.6345973,41.9367488]},"n2139858895":{"id":"n2139858895","loc":[-85.6345127,41.9369734]},"n2139858896":{"id":"n2139858896","loc":[-85.634478,41.9371923]},"n2139858897":{"id":"n2139858897","loc":[-85.6344838,41.9373768]},"n2139858898":{"id":"n2139858898","loc":[-85.6346242,41.9375299]},"n2139858899":{"id":"n2139858899","loc":[-85.6347723,41.9376357]},"n2139858900":{"id":"n2139858900","loc":[-85.6347607,41.9377788]},"n2139858901":{"id":"n2139858901","loc":[-85.6346204,41.9379533]},"n2139858902":{"id":"n2139858902","loc":[-85.6344184,41.9380105]},"n2139858903":{"id":"n2139858903","loc":[-85.6341627,41.9380406]},"n2139858904":{"id":"n2139858904","loc":[-85.634005,41.9381679]},"n2139858905":{"id":"n2139858905","loc":[-85.63393,41.9383353]},"n2139858906":{"id":"n2139858906","loc":[-85.6338588,41.9384597]},"n2139858907":{"id":"n2139858907","loc":[-85.6336627,41.9387759]},"n2139858908":{"id":"n2139858908","loc":[-85.6335127,41.9389361]},"n2139858933":{"id":"n2139858933","loc":[-85.6353118,41.9432646]},"n2139858934":{"id":"n2139858934","loc":[-85.6353952,41.9433002]},"n2139858935":{"id":"n2139858935","loc":[-85.6356496,41.9433255]},"n2139858936":{"id":"n2139858936","loc":[-85.6363128,41.9433373]},"n2139858937":{"id":"n2139858937","loc":[-85.6365467,41.9433779]},"n2139858938":{"id":"n2139858938","loc":[-85.6368692,41.9435265]},"n2139858939":{"id":"n2139858939","loc":[-85.6370986,41.9437039]},"n2139858940":{"id":"n2139858940","loc":[-85.6372371,41.9437732]},"n2139858941":{"id":"n2139858941","loc":[-85.6374756,41.9438171]},"n2139858942":{"id":"n2139858942","loc":[-85.6376164,41.9439286]},"n2139858943":{"id":"n2139858943","loc":[-85.6377504,41.944138]},"n2139858944":{"id":"n2139858944","loc":[-85.6384204,41.9443137]},"n2139858945":{"id":"n2139858945","loc":[-85.6385726,41.9444506]},"n2139858946":{"id":"n2139858946","loc":[-85.638702,41.9445739]},"n2139858947":{"id":"n2139858947","loc":[-85.6387179,41.9446516]},"n2139858948":{"id":"n2139858948","loc":[-85.6387088,41.9447985]},"n2139858949":{"id":"n2139858949","loc":[-85.6387656,41.9449877]},"n2139858950":{"id":"n2139858950","loc":[-85.638777,41.9451448]},"n2139858951":{"id":"n2139858951","loc":[-85.6387088,41.9452631]},"n2139858964":{"id":"n2139858964","loc":[-85.6383346,41.9442912]},"n2139858966":{"id":"n2139858966","loc":[-85.6384724,41.9443605]},"n2139858967":{"id":"n2139858967","loc":[-85.6354078,41.9434285]},"n2139858968":{"id":"n2139858968","loc":[-85.635271,41.943654]},"n2139858969":{"id":"n2139858969","loc":[-85.6352657,41.9437437]},"n2139858970":{"id":"n2139858970","loc":[-85.635271,41.9438195]},"n2139858971":{"id":"n2139858971","loc":[-85.6351563,41.9438906]},"n2139858972":{"id":"n2139858972","loc":[-85.6351384,41.9438882]},"n2139858973":{"id":"n2139858973","loc":[-85.6351514,41.9438034]},"n2139858974":{"id":"n2139858974","loc":[-85.6351237,41.9436641]},"n2139858975":{"id":"n2139858975","loc":[-85.6351498,41.9436108]},"n2139858976":{"id":"n2139858976","loc":[-85.6351058,41.9435345]},"n2139858977":{"id":"n2139858977","loc":[-85.6349641,41.9432051]},"n2139858986":{"id":"n2139858986","loc":[-85.6341205,41.9380746]},"n2139858990":{"id":"n2139858990","loc":[-85.6345671,41.9381816]},"n2139858995":{"id":"n2139858995","loc":[-85.6339783,41.9382273]},"n2139859003":{"id":"n2139859003","loc":[-85.6340477,41.9373489]},"n2139859004":{"id":"n2139859004","loc":[-85.6339784,41.9374752]},"n2139870406":{"id":"n2139870406","loc":[-85.6342265,41.9432605]},"n2139877106":{"id":"n2139877106","loc":[-85.6346323,41.9438746]},"n2139982399":{"id":"n2139982399","loc":[-85.6324055,41.9408537]},"n2139982400":{"id":"n2139982400","loc":[-85.632488,41.941063],"tags":{"leisure":"slipway"}},"n2139982401":{"id":"n2139982401","loc":[-85.6327261,41.9415366]},"n2139982402":{"id":"n2139982402","loc":[-85.6326391,41.9413598]},"n2139982403":{"id":"n2139982403","loc":[-85.6327041,41.9414391]},"n2139982405":{"id":"n2139982405","loc":[-85.6322891,41.9406009]},"n2139982406":{"id":"n2139982406","loc":[-85.6325412,41.9425257]},"n2139989333":{"id":"n2139989333","loc":[-85.6340584,41.9431731]},"n2140006331":{"id":"n2140006331","loc":[-85.6361751,41.9459744]},"n2140006334":{"id":"n2140006334","loc":[-85.636528,41.9459751]},"n2140006336":{"id":"n2140006336","loc":[-85.6370918,41.9458926]},"n2140006338":{"id":"n2140006338","loc":[-85.6378806,41.9456474]},"n2140006340":{"id":"n2140006340","loc":[-85.6385831,41.9454343]},"n2140006342":{"id":"n2140006342","loc":[-85.639341,41.945157]},"n2140006344":{"id":"n2140006344","loc":[-85.6393497,41.9450232]},"n2140006346":{"id":"n2140006346","loc":[-85.6388245,41.9450145]},"n2140006348":{"id":"n2140006348","loc":[-85.6388167,41.9441739]},"n2140006351":{"id":"n2140006351","loc":[-85.6382915,41.9441797]},"n2140006353":{"id":"n2140006353","loc":[-85.63828,41.9438109]},"n2140006355":{"id":"n2140006355","loc":[-85.6381949,41.9436009]},"n2140006357":{"id":"n2140006357","loc":[-85.6371904,41.9435918]},"n2140006359":{"id":"n2140006359","loc":[-85.6366966,41.9432727]},"n2140006361":{"id":"n2140006361","loc":[-85.6353755,41.9432744]},"n2140006365":{"id":"n2140006365","loc":[-85.6350906,41.9435472]},"n2140006366":{"id":"n2140006366","loc":[-85.6343461,41.9441573]},"n2140006395":{"id":"n2140006395","loc":[-85.6351171,41.9437175]},"n2140006397":{"id":"n2140006397","loc":[-85.635352,41.9450206]},"n2140006399":{"id":"n2140006399","loc":[-85.6358194,41.9454937]},"n2140006401":{"id":"n2140006401","loc":[-85.6348693,41.9445739]},"n2140006431":{"id":"n2140006431","loc":[-85.6376737,41.9438023]},"n2140006437":{"id":"n2140006437","loc":[-85.6382631,41.9442724]},"n2189123379":{"id":"n2189123379","loc":[-85.6342671,41.9352665]},"w203974076":{"id":"w203974076","tags":{"highway":"footway"},"nodes":["n2139870442","n2139870457","n2139870458","n2139870459","n2139870460","n2139870452"]},"w170989131":{"id":"w170989131","tags":{"name":"St Joseph River","waterway":"river"},"nodes":["n1820938225","n1820938712","n1820937596","n1820937574","n1820938515","n1820938330","n1820938678","n1820938240","n1820938950","n1820939226","n1820939575","n1820937913","n1820938223","n1820937668","n1820938545","n1820937584","n1820939742","n1820939727","n1820937578","n1820938149","n1820938124","n1820938888","n1820938898","n1820937922","n1820939543","n1820939370","n1820939401","n1820939647","n1820938345","n1820939644","n1820938333","n1820938370","n1820938624","n1820938493","n1820939559","n1820939763","n1820939237","n1820939416","n1820937810","n1820938317","n1820938324","n1820937558","n1820939556","n1820938298","n1820939348","n1820939125","n1820939081","n1820938859","n1820939126","n1820938881","n1820939439","n1820939324","n1820939128","n1820938101","n1820937706","n1820938382","n1820938776","n1820937815","n1820939177","n1820939688","n1820938952","n1820938216","n1820938387","n1820939333","n1820938243","n1820938248","n1820937666","n1820939051","n1820938332","n1820939438","n1820939407","n1820939361","n1820937517","n1820938770","n1820939591","n1820937857","n1820938491","n1820937993","n1820938125","n1820938166","n1820937746","n1820939028","n1820937638","n1820938676","n1820938843","n1820938844","n1820937978","n1820938730","n1820939544","n1820938304","n1820939123","n1820939494","n1820939450","n1820939555","n1820938133","n1820938129","n1820938871","n1820939408","n1820938669","n1820938260","n1820939740","n1820937625","n1820938631","n1820939651","n1820939613","n1820937850","n1820938325","n1820937736","n1820938804","n1820938837","n1820938014","n1820938991","n1820938722","n1820938935","n1820937870","n1820938432","n1820937986","n1820938756","n1820938966","n1820939159","n1820937744","n1820938334","n1820937645","n1820939394","n1820937656","n1820938392","n1820939703","n1820938385","n1820938947","n1820938854","n1820938428","n1820938488","n1820938269","n1820938668","n1820938268","n1820938707","n1820937732","n1820939144","n1820938481","n1820938771","n1820938686","n1820938948","n1820937997","n1820937769","n1820939003","n1820938083","n1820939011","n1820938803","n1820938700","n1820939723","n1820938808","n1820938262","n1820938081","n1820938926","n1820938326","n1820938102","n1820938508","n1820939590","n1820939199","n1820938084","n1820938870","n1820938895","n1820937611","n1820938918","n1820938514","n1820939610","n1820938910","n1820937523","n1820938127","n1820939108","n1820937981","n1820938938","n1820938715","n1820939016","n1820938237","n1820939623","n1820939602","n1820937734","n1820938977","n1820939633","n1820939156","n1820939406","n1820938279","n1820938301","n1820937678","n1820937671","n1820939163","n1820938356","n1820939372","n1820937568","n1820937626","n1820939710","n1820939004","n1820938253","n1820938571","n1820937513","n1820939412","n1820939701","n1820939509","n1820938839","n1820939731","n1820937798","n1820939676","n1820939724","n1820939243","n1820939704","n1820937814","n1820937599","n1820938199","n1820938995","n1820938445","n1820938069","n1820938470","n1820939074","n1820938193","n1820938740","n1820938047","n1820939507","n1820939441","n1820939160","n1820937849","n1820937840","n1820938052","n1820938988","n1820938796","n1820937724","n1820937620","n1820939304","n1820938343","n1820939649","n1820938875","n1820939686","n1820938476","n1820937801","n1820937737","n1820938264","n1820939609","n1820939496","n1820939593","n1820939566","n1820939661","n1820937782","n1820938912","n1820939173","n1820937733","n1820938953","n1820939603","n1820937607","n1820938468","n1820939601","n1820939694","n1820939133","n1820938897","n1820938893","n1820937831","n1820937730","n1820938820","n1820938046","n1820938426","n1820938347","n1820937582","n1820938954","n1820938033","n1820938104","n1820938680","n1820939563","n1820939404","n1820939714","n1820939000","n1820937992","n1820938168","n1820939510","n1820939500","n1820937509","n1820938865","n1820939773","n1820938138","n1820938905","n1820937623","n1820939418","n1820937946","n1820939577","n1820937615","n1820939687","n1820939119","n1820937988","n1820938337","n1820937750","n1820938703","n1820938339","n1820939044","n1820939770","n1820938913","n1820937672","n1820939722","n1820937768","n1820939597","n1820939612","n1820937699","n1820937682","n1820937669","n1820937657","n1820939363","n1820937800","n1820938265","n1820937760","n1820938207","n1820938115","n1820939130","n1820939716","n1820938338","n1820938239","n1820939040","n1820938064","n1820938855","n1820939015","n1820938258","n1820939042","n1820939043","n1820938443","n1820939725","n1820937675","n1820938568","n1820938280","n1820937705","n1820938775","n1820938636","n1820938626","n1820937859","n1820938096","n1820937852","n1820939039","n1820938247","n1820938585","n1820937707","n1820938117","n1820938909","n1820939115","n1820939335","n1820938805","n1820937935","n1820937876","n1820938699","n1820937869","n1820938603","n1820938100","n1820938500","n1820938283","n1820938275","n1820938923","n1820938365","n1820938349","n1820937804","n1820937903","n1820937608","n1820938688","n1820939671","n1820938092","n1820937820","n1820938753","n1820938922","n1820937990","n1820939682","n1820939738","n1820939600","n1820938167","n1820937726","n1820939702","n1820938209","n1820939456","n1820937837","n1820938222","n1820938902","n1820939162","n1820938965","n1820938461","n1820937681","n1820937514","n1820937764","n1820939719","n1820939697","n1820938899","n1820939093","n1820938702","n1820939595","n1820938749","n1820938348","n1820937606","n1820938675","n1820938830","n1820938737","n1820938758","n1820938716","n1820939107","n1820937863","n1820939033","n1820938163","n1820937867","n1820938819","n1820938034","n1820938252","n1820937563","n1820937868","n1820939032","n1820938632","n1820937982","n1820937943","n1820939568","n1820939541","n1820938215","n1820939097","n1820938812","n1820937518","n1820937952","n1820938711","n1820938736","n1820939066","n1820937591","n1820938082","n1820938108","n1820938496","n1820939410","n1820938949","n1820938327","n1820937708","n1820939023","n1820937772","n1820938256","n1820939083","n1820938378","n1820938961","n1820937610","n1820939717","n1820938695","n1820938590","n1820939655","n1820938341","n1820939054","n1820939157","n1820939674","n1820939684","n1820939511","n1820937631","n1820939458","n1820937830","n1820937709","n1820937779","n1820939749","n1820938880","n1820938856","n1820938557","n1820939557","n1820938249","n1820938818","n1820937594","n1820939114","n1820938416","n1820937508","n1820938990","n1820938201","n1820937759","n1820937987","n1820939164","n1820939753","n1820938187","n1820939067","n1820937586","n1820937941","n1820938121","n1820937807","n1820938521","n1820939726","n1820938244","n1820939014","n1820938741","n1820937629","n1820938664","n1820938747","n1820939082","n1820938709","n1820938320","n1820938270","n1820937619","n1820937777","n1820937718","n1820939138","n1820938056","n1820938155","n1820938596","n1820937775","n1820938437","n1820938128","n1820939581","n1820939145","n1820938546","n1820938184","n1820937601","n1820937794","n1820938539","n1820939645","n1820938438","n1820938436","n1820939025","n1820938915","n1820938534","n1820937605","n1820939607","n1820939101","n1820939580","n1820939268","n1820939134","n1820938849","n1820938754","n1820938079","n1820937842","n1820938781","n1820938873","n1820938495","n1820938381","n1820938503","n1820939436","n1820938502","n1820939087","n1820938996","n1820938449","n1820938907","n1820937979","n1820937780","n1820937546","n1820939699","n1820937677","n1820938957","n1820938946","n1820937776","n1820937717","n1820938718","n1820937637","n1820938510","n1820937663","n1820938941","n1820939151","n1820937603","n1820938250","n1820937951","n1820938630","n1820938821","n1820938779","n1820938497","n1820938159","n1820939536","n1820938409","n1820938386","n1820939116","n1820938340","n1820939117","n1820938291","n1820938435","n1820937819","n1820938242","n1820939078","n1820938877","n1820939104","n1820939445","n1820938367","n1820938903","n1820939420","n1820938517","n1820939508","n1820939542","n1820939326","n1820938210","n1820939020","n1820938815","n1820937832","n1820939513","n1820937818","n1820939005","n1820938717","n1820939135","n1820938384","n1820937587","n1820939024","n1820939504","n1820939120","n1820939026","n1820938015","n1820938998","n1820937648","n1820939137","n1820937761","n1820938195","n1820938535","n1820939550","n1820938725","n1820938282","n1820937781","n1820937792","n1820939705","n1820937788","n1820939707","n1820937882","n1820939632","n1820938427","n1820938276","n1820939617","n1820939013","n1820939035","n1820937543","n1820939365","n1820937752","n1820937802","n1820939183","n1820939670","n1820938450","n1820939375","n1820937813","n1820937673","n1820937783","n1820939029","n1820939768","n1820939377","n1820937974","n1820939244","n1820939642","n1820937864","n1820938255","n1820938528","n1820939666","n1820938120","n1820937812","n1820938928","n1820939750","n1820939099","n1820938073","n1820938714","n1820939140","n1820938192","n1820937844","n1820938635","n1820938742","n1820939583","n1820937887","n1820938318","n1820938816","n1820939698","n1820938273","n1820939181","n1820937652","n1820938748","n1820937651","n1820938519","n1820938019","n1820938752","n1820938235","n1820939118","n1820938562","n1820939314","n1820939570","n1820938190","n1820938342","n1820938533","n1820937977","n1820939089","n1820939146","n1820938622","n1820938297","n1820938524","n1820939283","n1820938874","n1820938832","n1820937550","n1820937843","n1820938638","n1820938116","n1820938206","n1820938319","n1820939053","n1820937845","n1820938093","n1820939217","n1820938997","n1820939355","n1820938861","n1820938726","n1820938057","n1820939373","n1820937862","n1820938518","n1820939072","n1820939680","n1820938444","n1820938217","n1820938506","n1820938393","n1820938492","n1820938852","n1820938221","n1820938773","n1820937684","n1820939060","n1820938224","n1820938203","n1820938840","n1820937525","n1820938147","n1820938433","n1820938188","n1820939359","n1820938750","n1820938016","n1820938768","n1820937621","n1820937799","n1820938951","n1820938721","n1820939037","n1820937866","n1820939715","n1820938063","n1820938446","n1820937627","n1820939624","n1820938431","n1820939721","n1820939622","n1820939239","n1820939263","n1820939648","n1820939640","n1820938867","n1820938757","n1820938439","n1820939352","n1820937740","n1820939329","n1820938229","n1820937583","n1820938180","n1820938366","n1820937767","n1820937758","n1820939374","n1820938869","n1820938292","n1820938400","n1820938399","n1820939734","n1820939289","n1820938944","n1820937755","n1820938759","n1820938434","n1820937600","n1820937825","n1820937670","n1820937793","n1820938011","n1820938246","n1820938956","n1820937770","n1820937757","n1820938059","n1820937860","n1820937569","n1820939266","n1820939685","n1820939672","n1820938606","n1820938772","n1820939038","n1820938211","n1820938359","n1820939619","n1820938708","n1820939512","n1820938065","n1820939233","n1820939739","n1820938786","n1820938879","n1820939147","n1820938563","n1820939148","n1820937839","n1820937659","n1820937786","n1820938419","n1820939565","n1820939402","n1820937710","n1820938254","n1820938271","n1820938390","n1820937680","n1820938140","n1820937817","n1820938218","n1820937985","n1820939235","n1820938441","n1820938401","n1820938719","n1820937795","n1820938971","n1820938460","n1820939759","n1820937972","n1820937841","n1820938462","n1820939320","n1820938978","n1820938360","n1820939713","n1820937676","n1820939712","n1820937939","n1820938080","n1820937754","n1820937753","n1820938530","n1820937886","n1820939689","n1820939124","n1820938697","n1820938789","n1820939105","n1820938860","n1820938853","n1820939400","n1820937561","n1820938404","n1820938774","n1820939316","n1820937696","n1820938782","n1820938975","n1820937564","n1820939730","n1820938257","n1820937853","n1820938487","n1820938848","n1820938906","n1820939230","n1820938424","n1820938051","n1820937771","n1820939587","n1820939149","n1820938792","n1820939041","n1820938934","n1820939777","n1820937515","n1820939058","n1820938312","n1820939264","n1820939631","n1820939109","n1820939403","n1820939664","n1820938724","n1820938929","n1820939399","n1820939776","n1820939369","n1820939185","n1820937701","n1820938126","n1820938336","n1820938219","n1820939080","n1820938642","n1820938043","n1820937725","n1820938548","n1820938552","n1820938035","n1820938684","n1820937778","n1820938764","n1820939021","n1820939346","n1820937712","n1820939761","n1820938397","n1820937747","n1820938566","n1820939161","n1820939090","n1820939752","n1820939271","n1820938878","n1820938110","n1820938346","n1820938499","n1820938151","n1820939538","n1820938281","n1820939153","n1820938551","n1820939285","n1820938197","n1820938408","n1820938482","n1820939036","n1820939579","n1820938489","n1820938483","n1820938189","n1820938123","n1820938087","n1820937741","n1820938485","n1820937590","n1820938972","n1820937773","n1820937520","n1820938872","n1820938131","n1820938452","n1820938328","n1820939620","n1820937641","n1820938353","n1820939693","n1820938705","n1820937640","n1820939189","n1820938144","n1820939774","n1820938694","n1820938238","n1820939397","n1820937917","n1820938454","n1820938567","n1820938979","n1820938060","n1820938204","n1820937828","n1820939232","n1820938806","n1820938857","n1820938078","n1820938105","n1820939228","n1820938604","n1820937763","n1820937854","n1820938289","n1820939736","n1820937937","n1820937714","n1820938278","n1820938058","n1820938706","n1820938989","n1820938313","n1820938520","n1820938288","n1820937689","n1820939537","n1820939531","n1820939019","n1820937527","n1820938455","n1820938814","n1820938045","n1820939627","n1820938213","n1820938161","n1820938331","n1820938024","n1820938220","n1820938062","n1820938178","n1820937796","n1820937644","n1820938490","n1820937589","n1820937879","n1820939614","n1820938882","n1820938039","n1820938538","n1820937667","n1820937719","n1820938561","n1820939658","n1820938783","n1820938601","n1820938198","n1820938388","n1820938969","n1820937687","n1820939086","n1820939665","n1820939187","n1820938498","n1820938261","n1820937983","n1820938068","n1820938136","n1820939061","n1820938137","n1820938186","n1820939071","n1820937592","n1820939669","n1820937553","n1820939357","n1820938727","n1820939371","n1820939112","n1820939079","n1820938743","n1820938467","n1820938834","n1820938022","n1820938537","n1820938122","n1820938516","n1820937614","n1820937612","n1820939469","n1820939636","n1820939050","n1820939552","n1820938157","n1820938663","n1820938955","n1820939091","n1820938430","n1820938471","n1820937809","n1820938074","n1820938208","n1820938914","n1820938858","n1820938417","n1820937531","n1820938107","n1820939100","n1820938751","n1820937711","n1820938824","n1820939745","n1820937572","n1820938602","n1820938212","n1820938097","n1820937921","n1820938090","n1820938511","n1820938876","n1820939762","n1820938234","n1820938048","n1820937774","n1820937856","n1820937749","n1820937765","n1820938286","n1820939095","n1820938480","n1820939229","n1820938277","n1820937617","n1820938311","n1820937622","n1820939196","n1820937690","n1820939006","n1820939287","n1820939131","n1820938106","n1820938784","n1820938335","n1820938095","n1820938182","n1820937715","n1820937683","n1820938070","n1820939605","n1820938527","n1820938763","n1820938398","n1820937686","n1820939621","n1820937664","n1820939277","n1820938565","n1820939539","n1820938099","n1820939646","n1820938556","n1820937548","n1820938729","n1820939336","n1820938259","n1820938728","n1820938361","n1820937643","n1820938644","n1820939007","n1820939690","n1820939227","n1820937635","n1820937950","n1820938682","n1820939150","n1820939012","n1820939261","n1820939111","n1820937805","n1820939691","n1820939677","n1820937628","n1820937811","n1820938790","n1820938251","n1820938226","n1820938942","n1820937633","n1820937984","n1820937751","n1820939673","n1820938970","n1820938415","n1820938597","n1820938309","n1820938111","n1820938472","n1820938894","n1820938402","n1820937593","n1820938570","n1820939102","n1820939775","n1820937948","n1820939121","n1820937511","n1820938787","n1820939720","n1820939075","n1820937880","n1820937742","n1820937721","n1820939535","n1820938486","n1820938354","n1820937632","n1820939010","n1820938885","n1820938089","n1820937613","n1820938442","n1820938245","n1820938272","n1820937566","n1820938295","n1820938532","n1820938883","n1820937713","n1820937674","n1820939635","n1820938448","n1820938355","n1820938587","n1820938559","n1820937787","n1820939301","n1820937723","n1820939056","n1820937560","n1820938323","n1820938230","n1820938453","n1820938377","n1820938357","n1820939637","n1820938017","n1820939540","n1820939376","n1820937639","n1820937642","n1820938075","n1820938351","n1820938766","n1820937897","n1820938973","n1820938066","n1820939547","n1820939652","n1820937944","n1820937748","n1820939234","n1820939193","n1820937891","n1820938785","n1820939132","n1820938523","n1820938884","n1820938411","n1820939554","n1820938791","n1820937655","n1820938368","n1820939152","n1820938030","n1820938447","n1820937580","n1820939628","n1820937588","n1820937894","n1820939201","n1820938086","n1820937650","n1820938379","n1820939008","n1820938999","n1820937524","n1820937872","n1820938389","n1820939197","n1820938422","n1820938936","n1820939262","n1820937634","n1820938583","n1820939589","n1820937901","n1820939034","n1820939065","n1820938290","n1820939195","n1820938228","n1820937884","n1820938797","n1820938191","n1820939191","n1820939198","n1820937892","n1820939679","n1820938507","n1820937647","n1820937909","n1820938542","n1820939598","n1820937851","n1820939084","n1820939728","n1820937688","n1820938263","n1820938670","n1820937762","n1820939310","n1820938925","n1820938862","n1820938822","n1820938547","n1820937731","n1820938594","n1820938592","n1820938214","n1820938284","n1820937835","n1820938599","n1820939437","n1820937834","n1820937576","n1820937692","n1820939586","n1820939546","n1820938403","n1820937970","n1820939561","n1820938098","n1820938851","n1820938477","n1820938892","n1820939045","n1820939758","n1820939350","n1820938321","n1820938440","n1820938595","n1820938364","n1820938962","n1820938118","n1820939678","n1820938406","n1820938549","n1820937555","n1820938823","n1820937521","n1820939471","n1820939487","n1820938799","n1820938605","n1820937928","n1820938373","n1820939747","n1820939629","n1820937557","n1820937526","n1820938958","n1820938833","n1820937636","n1820938967","n1820938760","n1820938842","n1820938067","n1820939077","n1820939224","n1820938185","n1820939110","n1820938372","n1820939757","n1820939063","n1820939660","n1820938813","n1820937528","n1820938369","n1820938896","n1820939551","n1820939683","n1820937660","n1820937873","n1820938810","n1820938478","n1820939662","n1820937595","n1820939052","n1820938113","n1820939070","n1820938733","n1820937878","n1820938300","n1820939760","n1820939718","n1820937646","n1820939057","n1820939443","n1914861306","n1820938013","n1820937529","n1820939764","n1820938826","n1820937885","n1820939588","n1820937865","n1820937833","n1914861112","n1820938761","n1914861007","n1820937905","n1820938541","n1820939092","n1914861057","n1820938153","n1820938267","n1820939265","n1820938085","n1820939018","n1820939755","n1820938474","n1820939027","n1820938593","n1820938202","n1820939599","n1820939695","n1820938077","n1820938012","n1820939545","n1820939596","n1820939337","n1820938227","n1820937698","n1820938475","n1820939465","n1820938165","n1820938698","n1820938525","n1820938529","n1820938553","n1820938940","n1820939498","n1820938501","n1820939533","n1820938924","n1820939634","n1820939220","n1820939657","n1820938887","n1820938838","n1820938114","n1820937823","n1820938778","n1820938801","n1820939096","n1820938981","n1820937953","n1820938732","n1820938980","n1820938960","n1820937949","n1820938026","n1820939273","n1841425201","n1820938629","n1820938864","n1820938554","n1820938088","n1820937685","n1841425222","n1820939729","n1820937665","n1820937838","n1820937739","n1820938780","n1820937821","n1820938825","n1820939055","n1820939485","n1820938041","n1820938746","n1820939562","n1820938459","n1820939489","n1820938050","n1820937980","n1820937695","n1820938413","n1820938555","n1820937703","n1820938536","n1820938196","n1820938287","n1820938169","n1820939279","n1820938531","n1820938959","n1820939741","n1820938665","n1820938963","n1820939611","n1820937653","n1820939618","n1820939492","n1820938600","n1820938628","n1820939312","n1820939616","n1820937738","n1820939001","n1820939062","n1820938794","n1820938558","n1820937822","n1820937532","n1820939073","n1820938200","n1820938241","n1820938968","n1820938927","n1820938306","n1820937630","n1820938456","n1820937694","n1820938908","n1820939076","n1820937522","n1820939659","n1820938522","n1820939318","n1820938932","n1820938841","n1820937579","n1820937540","n1820938560","n1821139530","n1820938964","n1820937662","n1820939281","n1821139533","n1820937797","n1821139532","n1820939751","n1821139531","n1820939291","n1820938420","n1820939696","n1820938904","n1820938484","n1820939448","n1820939009","n1820938735","n1820938986","n1820938937","n1820939030","n1820938734","n1820938745","n1820939106","n1820938987","n1820937858","n1820938673","n1820938620","n1820937808","n1820937700","n1820939573","n1820938540","n1820937661","n1820937570","n1820938396","n1820937875","n1820939048","n1820938233","n1820938793","n1820939584","n1820938412","n1820938394","n1820937846","n1820938800","n1820938690","n1820939331","n1820939630","n1820938762","n1820938710","n1820939322","n1820938992","n1821137608","n1821137607","n1820937924","n1820939139","n1820939463","n1820939574","n1820938294","n1820938071","n1820938307","n1820938061","n1820939260","n1820937899","n1820938310","n1820938983","n1820937530","n1820938993","n1820938890","n1820937915","n1820938231","n1820938040","n1820938920","n1820939585","n1820938135","n1820939700","n1820937824","n1820939667","n1820937930","n1820938134","n1820937551","n1820939405","n1820938232","n1820937716","n1820937848","n1820939765","n1820939068","n1820939766","n1820937933","n1820937720","n1820939222","n1820939772","n1820939022","n1820939732","n1820937702","n1820937691","n1820938945","n1820937756","n1820938451","n1820938410","n1820938798","n1820937945","n1820937654","n1820938598","n1820938836","n1820937571","n1820937556","n1820938994","n1820938919","n1820938863","n1820939064","n1820938018","n1820937658","n1820937537","n1820938142","n1820938666","n1820937535","n1820939571","n1820938465","n1820939638","n1820937533","n1820939656","n1820939422","n1820938109","n1820938405","n1820938028","n1820937649","n1820938829","n1820939031","n1820939155","n1820938350","n1820938463","n1820938425","n1820939047","n1820938831","n1820938494","n1820937697","n1820938504","n1820938900","n1820937784","n1820938414","n1820938076","n1820938723","n1820937722","n1820938739","n1820937791","n1820938985","n1820938352","n1820938293","n1820938274","n1820939692","n1820937871","n1820939059","n1820938868","n1820937877","n1820937743","n1820938429","n1820937545","n1820937575","n1820938302","n1820938505","n1820938916","n1820938374","n1820938329","n1820937790","n1820939735","n1820938930","n1820937995","n1820938512","n1820938130","n1820938194","n1820938671","n1820938802","n1820937542","n1820937602","n1820939069","n1820938901","n1820939654","n1820937727","n1820939569","n1820938375","n1820939306","n1820938479","n1820938376","n1820938667","n1820937766","n1820939467","n1820939567","n1820937806","n1820938943","n1820938931","n1820937745","n1820939452","n1820938738","n1820938053","n1820939653","n1820938640","n1820937604","n1820937536","n1820938701","n1820939625","n1820939744","n1820939572","n1820937577","n1820937541","n1820938891","n1820937597","n1820938469","n1820939194","n1820937539","n1820938911","n1820939017","n1820939650","n1820939103","n1820939578","n1820938132","n1820937549","n1820938634","n1820939743","n1820937544","n1820937826","n1820937598","n1820937547","n1820938032","n1820939142"]},"w17963021":{"id":"w17963021","tags":{"highway":"residential"},"nodes":["n185948706","n185948708","n185948710"]},"w203974069":{"id":"w203974069","tags":{"amenity":"shelter","area":"yes","building":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139870431","n2139870432","n2139870433","n2139870434","n2139870431"]},"w209816575":{"id":"w209816575","tags":{"area":"yes","building":"yes"},"nodes":["n2199856288","n2199856289","n2199856290","n2199856291","n2199856292","n2199856293","n2199856294","n2199856295","n2199856296","n2199856297","n2199856298","n2199856299","n2199856300","n2199856301","n2199856302","n2199856303","n2199856288"]},"w203841838":{"id":"w203841838","tags":{"area":"yes","natural":"water"},"nodes":["n2138493826","n2138493827","n2138493828","n2138493829","n2138493830","n2138493831","n2138493833","n2138493832","n2138493826"]},"w203972937":{"id":"w203972937","tags":{"highway":"path","name":"Riverwalk Trail","surface":"asphalt","width":"3"},"nodes":["n2139858882","n2139858883","n2139858884","n2139858885","n2139858886","n2139858887","n2139858882","n2139858888","n2139858889","n2139858890","n2139858891","n2139858892","n2139858893","n2139858894","n2139858895","n2139858896","n2139858897","n2139858898","n2139858899","n2139858900","n2139858901","n2139858902","n2139858903","n2139858986","n2139858904","n2139858995","n2139858905","n2139858906","n2139858907","n2139858908","n2139858909","n2139858910","n2139858911","n2139858912","n2139858913","n2139858914","n2139858915","n2139858916","n2139858917","n2139858918","n2139858919","n2139858920","n2139858921","n2139858922","n2139858923","n2139858924","n2139858925","n2139858926","n2139858927","n2139858982","n2139858928","n2139858929","n2139858930","n2139858931","n2139858932","n2139858981","n2139858933","n2139858934","n2139858935","n2139858936","n2139858937","n2139858938","n2139858939","n2139858940","n2139858941","n2139858942","n2139858943","n2140006437","n2139858964","n2139858944","n2139858966","n2139858945","n2139858946","n2139858947","n2139858948","n2139858949","n2139858950","n2139858951"]},"w17964015":{"id":"w17964015","tags":{"highway":"residential"},"nodes":["n185954680","n185954683","n185954685","n185954687","n185954689","n185954690","n185954691","n2139870379","n2139870456","n185954692","n185954693","n185954695"]},"w17967315":{"id":"w17967315","tags":{"highway":"residential","name":"South Andrews Street"},"nodes":["n185981999","n185974477","n185964963"]},"w203974071":{"id":"w203974071","tags":{"highway":"footway"},"nodes":["n2139870439","n2139870440","n2139870441","n2139870442","n2139870443","n2139870444","n2139870445","n2139870446","n2139870447","n2139870448","n2139870449"]},"w170848824":{"id":"w170848824","tags":{"name":"Rocky River","waterway":"river"},"nodes":["n1819858503","n1819858531","n1819858526","n1819858518","n1819858505","n1819858508","n1819858512","n1819858514","n1819858528","n1819858509","n1819858511","n1819858507","n1819858521"]},"w203986458":{"id":"w203986458","tags":{"amenity":"shelter","area":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139989357","n2139989359","n2139989360","n2139989362","n2139989357"]},"w170844917":{"id":"w170844917","tags":{"waterway":"riverbank"},"nodes":["n1819805911","n1819805690","n1819805812","n1819805766","n1819805802","n1819805885","n1819805626","n1819805842","n1819805715","n1819805694","n1819805618","n1819805629","n1819805731","n1819805636","n1819805878","n1819805718","n1819805798","n1819849057","n1819805666","n1819805852","n1819805805","n1819805789","n1819805868","n1819805680","n1819805918","n1819848888","n1819805762","n2139989328","n1819805907","n2139989330","n1819805915","n1819858521","n1819805854","n1819805876","n1819805864","n1819805922","n2139859004","n1819805702","n2139859003","n1819805614","n1819805792","n1819805786","n1819805777","n1819805645","n1819805838","n1819805889","n1819805795","n1819805707","n1819805774","n1819805808","n1819805810","n1819805724","n1819805676","n1819805728","n1819805783","n1819805687","n1819805727","n2189123379","n1819805632","n1819805641","n1819805760","n1819805887","n1819805861","n1819805722","n1819805880","n2139982405","n2139982399","n2139982400","n1819805770","n2139982402","n2139982403","n2139982401","n1819805780","n1819805834","n2139982406","n1819805698","n1819805647","n1819805870","n1819805683","n1819805622","n1819805639","n1819805858","n1819805643","n1819805673","n1819805925","n1819805849","n1819805711","n1819805846","n1819805669","n1819805883","n1819805814","n1819805873","n1819805911"]},"w17967326":{"id":"w17967326","tags":{"highway":"residential","name":"North Constantine Street"},"nodes":["n185985217","n185985219","n185985221","n185985222","n185985223","n185985225","n2140006431","n185985227","n185985229","n185985231","n185985233","n185985235","n185985238","n185985240","n2140018998","n185964965"]},"w134150789":{"id":"w134150789","tags":{"highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964971","n2139870406","n185964972"]},"w17966400":{"id":"w17966400","tags":{"highway":"tertiary","name":"South Constantine Street"},"nodes":["n185958672","n185964965"]},"w203974066":{"id":"w203974066","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139870417","n2139870418","n2139870420","n2139870419"]},"w17965998":{"id":"w17965998","tags":{"name":"Conrail Railroad","railway":"rail"},"nodes":["n185972775","n185972777","n185972779","n185972781","n185972783","n185972785","n185972787","n185972788","n185972789","n185972790","n185972791","n185972793","n185972795","n185972797","n185972798","n185972800","n185972802","n185972805","n185972807","n185972809","n185972811","n185972813","n185972814","n185972815","n185972816","n185972817","n185972819","n185972821","n185972824","n185972826","n185972830","n185972832","n185972834","n185972835","n185972836","n185972839","n185990434","n2114807572","n2114807568","n185972845","n2114807583","n185972847","n185972849","n185972851","n2114807578","n1475293254","n2114807593","n1475293226","n185972862","n2114807565","n185951869","n1475293234","n1475293252","n185972868","n1475293264","n1475293222","n185972878","n1475293261","n185972882","n185972885","n1475293260","n1475293240","n185972891","n185972895","n185972897","n185972899","n2130304159","n1475284023","n185972903"]},"w134150795":{"id":"w134150795","tags":{"bridge":"yes","highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964970","n185964971"]},"w203974067":{"id":"w203974067","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139870420","n2139870421"]},"w170995908":{"id":"w170995908","tags":{"highway":"residential","name":"Thomas Street"},"nodes":["n1821006702","n1821006700","n1821006698","n2139858990","n1821006716","n1821006725","n1821006712","n1821006704","n1821006708","n1821006710","n1821006706"]},"w17965834":{"id":"w17965834","tags":{"highway":"residential","name":"Spring Street"},"nodes":["n185971361","n185971364","n185971366","n185971368","n185954695","n185964968"]},"w203974070":{"id":"w203974070","tags":{"amenity":"shelter","area":"yes","building":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139870435","n2139870436","n2139870437","n2139870438","n2139870435"]},"w203989879":{"id":"w203989879","tags":{"highway":"service"},"nodes":["n2140018998","n2140018999","n2140019000"]},"w203974062":{"id":"w203974062","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139870387","n2139870388","n2139870389","n2139870390","n2139870391","n2139870392","n2139870397","n2139870393","n2139870396","n2139870395","n2139870394","n2139870387"]},"w203974061":{"id":"w203974061","tags":{"bridge":"yes","highway":"footway"},"nodes":["n2139870382","n2139870383"]},"w203049587":{"id":"w203049587","tags":{"area":"yes","name":"Scidmore Park Petting Zoo","tourism":"zoo","zoo":"petting_zoo"},"nodes":["n2130304133","n2130304136","n2130304138","n2130304140","n2130304142","n2130304144","n2130304146","n2130304147","n2130304148","n2130304149","n2130304150","n2130304151","n2130304133"]},"w203972941":{"id":"w203972941","tags":{"highway":"path"},"nodes":["n2139858982","n2139858983","n2139858984","n2139858985","n2139858927"]},"w203974065":{"id":"w203974065","tags":{"highway":"service"},"nodes":["n2139870406","n2139870407","n2139870408","n2139870417","n2139870409","n2139870410","n2139870411","n2139870412","n2139870426","n2139870413","n2139870414","n2139870415","n2139870419","n2139870416","n2139870421","n2139870408"]},"w203972940":{"id":"w203972940","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139858934","n2139858967","n2139858968","n2139858969","n2139858970","n2139858971","n2139858972","n2139858973","n2139858974","n2139858975","n2139858976","n2139858977","n2139858978","n2139858979","n2139858980","n2139858981"]},"w203974072":{"id":"w203974072","tags":{"highway":"footway"},"nodes":["n2139858925","n2139870450","n2139870453","n2139870451","n2139870452","n2139870441"]},"w203974074":{"id":"w203974074","tags":{"highway":"footway"},"nodes":["n2139870454","n2139870456","n2139870429"]},"w203974060":{"id":"w203974060","tags":{"highway":"footway"},"nodes":["n2139870383","n2139870384","n2139870422","n2139870385","n2139870386","n2139870388"]},"w203841837":{"id":"w203841837","tags":{"area":"yes","natural":"water"},"nodes":["n2138493807","n2138493808","n2138493809","n2138493810","n2138493811","n2138493812","n2138493813","n2138493814","n2138493815","n2138493816","n2138493825","n2138493817","n2138493824","n2138493818","n2138493819","n2138493820","n2138493821","n2138493822","n2138493823","n2138493807"]},"w134150845":{"id":"w134150845","tags":{"bridge":"yes","name":"Conrail Railroad","railway":"rail"},"nodes":["n185972903","n185972905"]},"w203974059":{"id":"w203974059","tags":{"highway":"footway"},"nodes":["n2139870430","n2139870439","n2139870429","n2139870428","n2139870379","n2139870455","n2139870380","n2139870381","n2139858925","n2139870382"]},"w203986457":{"id":"w203986457","tags":{"area":"yes","leisure":"park","name":"Scidmore Park"},"nodes":["n2139989333","n2139989335","n2139989337","n2139989339","n1819805762","n2139989328","n1819805907","n2139989330","n1819805915","n2139989341","n2139989344","n2139989346","n2139989348","n2139989350","n2139989351","n2139989353","n2139989355","n2139989333"]},"w170848331":{"id":"w170848331","tags":{"name":"Rocky River","waterway":"river"},"nodes":["n1819848937","n1819849104","n1819849076","n1819849183","n1819848928","n1819848972","n1819848948","n1819848971","n1819848859","n1819849008","n1819848889","n1819849026","n1819849094","n1819849083","n1819849079","n1819849187","n1819848992","n1819849060","n1819849056","n1819849071","n1819849067","n1819849048","n1819849036","n1819849150","n1819849075","n1819849051","n1819849062","n1819848926","n1819849035","n1819848987","n1819849012","n1819848933","n1819848996","n1819848990","n1819849005","n1819849021","n1819848892","n1819849092","n1819848863","n1819848922","n1819848858","n1819848855","n1819848974","n1819848953","n1819849019","n1819849049","n1819848979","n1819849140","n1819849193","n1819849147","n1819849151","n1819849163","n1819849023","n1819848878","n1819849004","n1819848857","n1819848879","n1819849041","n1819849165","n1819849107","n1819849156","n1819848934","n1819848914","n1819848955","n1819848931","n1819848927","n1819849084","n1819849169","n1819849045","n1819848945","n1819849095","n1819848924","n1819849171","n1819849141","n1819849046","n1819849197","n1819849011","n1819849108","n1819849158","n1819849160","n1819848870","n1819849006","n1819849157","n1819848993","n1819848970","n1819849202","n1819848903","n1819848975","n1819848849","n1819849025","n1819849105","n1819849033","n1819849176","n1819849099","n1819849086","n1819848960","n1819848961","n1819849001","n1819848980","n1819849038","n1819848854","n1819849127","n1819849170","n1819849139","n1819848873","n1819848929","n1819849201","n1819849121","n1819849031","n1819849131","n1819848875","n1819849080","n1819849066","n1819849081","n1819849096","n1819849172","n1819849114","n1819849182","n1819848905","n1819849054","n1819848920","n1819848851","n1819848968","n1819848917","n1819849111","n1819849119","n1819849074","n1819848893","n1819849129","n1819848850","n1819848956","n1819849154","n1819848877","n1819848986","n1819849191","n1819848952","n1819848954","n1819848942","n1819849028","n1819849195","n1819848938","n1819848962","n1819849070","n1819849034","n1819849052","n1819849059","n1819848916","n1819849162","n1819849167","n1819849093","n1819849030","n1819849002","n1819849161","n1819848886","n1819848958","n1819849064","n1819849112","n1819849148","n1819848856","n1819848976","n1819848977","n1819849144","n1819848918","n1819849200","n1819848919","n1819849042","n1819849166","n1819849186","n1819849152","n1819849058","n1819849185","n1819849199","n1819849053","n1819849194","n1819849068","n1819849146","n1819849174","n1819848967","n1819848932","n1819849155","n1819849198","n1819848964","n1819848894","n1819848969","n1819849184","n1819849055","n1819849179","n1819848865","n1819848860","n1819849082","n1819848966","n1819849040","n1819849069","n1819849078","n1819849077","n1819848904","n1819848959","n1819849133","n1819849089","n1819849000","n1819849124","n1819849032","n1819849097","n1819848939","n1819849072","n1819848915","n1819849196","n1819848946","n1819849047","n1819849029","n1819849164","n1819848994","n1819849022","n1819858513","n1819849126","n1819849063","n1819848941","n1819849085","n1819848871","n1819848943","n1819849192","n1819858501","n1819849159","n1819858523","n1819848901","n1819849189","n1819858503","n1819849065","n2139877106","n1819848909","n1819848930","n1819848888"]},"w17967397":{"id":"w17967397","tags":{"highway":"residential","name":"North Andrews Street"},"nodes":["n185964963","n185985217"]},"w17964497":{"id":"w17964497","tags":{"highway":"tertiary","name":"Constantine St"},"nodes":["n185958643","n185958645","n2139795852","n185958647","n185958649","n185958651","n185958653","n185958656","n185958658","n185958660","n185958662","n185958664","n185958666","n185958668","n185958670","n185948710","n185958672"]},"w203974068":{"id":"w203974068","tags":{"highway":"footway"},"nodes":["n2139870422","n2139870423","n2139870424","n2139870425","n2139870426","n2139870427"]},"w203974063":{"id":"w203974063","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139870398","n2139870399","n2139870400","n2139870401","n2139870398"]},"w203986459":{"id":"w203986459","tags":{"amenity":"shelter","area":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139989364","n2139989366","n2139989368","n2139989370","n2139989364"]},"w203988286":{"id":"w203988286","tags":{"area":"yes","leisure":"park","name":"Memory Isle Park"},"nodes":["n2140006331","n2140006334","n2140006336","n2140006338","n2140006340","n2140006342","n2140006344","n2140006346","n2140006348","n2140006351","n2140006353","n2140006355","n2140006357","n2140006359","n2140006361","n2140006363","n2140006364","n2140006365","n2140006395","n2140006366","n2140006401","n2140006397","n2140006399","n2140006331"]},"w203974073":{"id":"w203974073","tags":{"highway":"footway"},"nodes":["n2139870453","n2139870454","n2139870455"]},"w203974064":{"id":"w203974064","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139870402","n2139870403","n2139870404","n2139870405","n2139870402"]},"n185966959":{"id":"n185966959","loc":[-85.642185,41.946411]},"n1475283980":{"id":"n1475283980","loc":[-85.6398249,41.9451425]},"n1475284013":{"id":"n1475284013","loc":[-85.6396448,41.9451666]},"n1475284042":{"id":"n1475284042","loc":[-85.6386382,41.9454789]},"n185975925":{"id":"n185975925","loc":[-85.6393332,41.9452388]},"n185975919":{"id":"n185975919","loc":[-85.6391279,41.9453044]},"n185975917":{"id":"n185975917","loc":[-85.6389034,41.9453872]},"n2140006369":{"id":"n2140006369","loc":[-85.6386163,41.9451631]},"n2140006370":{"id":"n2140006370","loc":[-85.6385144,41.9449357]},"n2140006417":{"id":"n2140006417","loc":[-85.6385785,41.9450299]},"n2140006419":{"id":"n2140006419","loc":[-85.6385781,41.9452152]},"n2189123361":{"id":"n2189123361","loc":[-85.6404948,41.947015]},"n2189123363":{"id":"n2189123363","loc":[-85.6395765,41.946495]},"n2189123365":{"id":"n2189123365","loc":[-85.6389347,41.9460875]},"n185966962":{"id":"n185966962","loc":[-85.644417,41.946364]},"n185975911":{"id":"n185975911","loc":[-85.637532,41.9458276]},"n185975913":{"id":"n185975913","loc":[-85.6376323,41.9457936]},"n185975915":{"id":"n185975915","loc":[-85.6383596,41.9455425]},"n185975932":{"id":"n185975932","loc":[-85.644403,41.945088]},"n185975934":{"id":"n185975934","loc":[-85.645486,41.945084]},"n185979974":{"id":"n185979974","loc":[-85.644381,41.943831]},"n2139795809":{"id":"n2139795809","loc":[-85.6464756,41.9450813]},"n2139795810":{"id":"n2139795810","loc":[-85.6466646,41.945174]},"n2139858952":{"id":"n2139858952","loc":[-85.6383567,41.9454039]},"n2139858953":{"id":"n2139858953","loc":[-85.6380506,41.9455301]},"n2139858954":{"id":"n2139858954","loc":[-85.6377321,41.9455546]},"n2139858955":{"id":"n2139858955","loc":[-85.6376571,41.9455245]},"n2139858956":{"id":"n2139858956","loc":[-85.6375859,41.9454544]},"n2139858957":{"id":"n2139858957","loc":[-85.6376686,41.9453185]},"n2139858958":{"id":"n2139858958","loc":[-85.6378936,41.9451712]},"n2139858959":{"id":"n2139858959","loc":[-85.6379225,41.9450825]},"n2139858960":{"id":"n2139858960","loc":[-85.6379302,41.9447564]},"n2139858961":{"id":"n2139858961","loc":[-85.6379763,41.9446963]},"n2139858962":{"id":"n2139858962","loc":[-85.6380436,41.9446706]},"n2139858963":{"id":"n2139858963","loc":[-85.6381286,41.9445969]},"n2139858965":{"id":"n2139858965","loc":[-85.6382523,41.9444134]},"n2140006367":{"id":"n2140006367","loc":[-85.6380923,41.9454418]},"n2140006368":{"id":"n2140006368","loc":[-85.6384089,41.9453146]},"n2140006372":{"id":"n2140006372","loc":[-85.6383252,41.9447706]},"n2140006374":{"id":"n2140006374","loc":[-85.6381033,41.9447436]},"n2140006376":{"id":"n2140006376","loc":[-85.6379759,41.9447815]},"n2140006378":{"id":"n2140006378","loc":[-85.6379832,41.9448654]},"n2140006380":{"id":"n2140006380","loc":[-85.6380632,41.9450738]},"n2140006382":{"id":"n2140006382","loc":[-85.6380414,41.9452064]},"n2140006389":{"id":"n2140006389","loc":[-85.6379068,41.9453092]},"n2140006391":{"id":"n2140006391","loc":[-85.637925,41.9453904]},"n2140006393":{"id":"n2140006393","loc":[-85.6379977,41.94545]},"n2189123275":{"id":"n2189123275","loc":[-85.6371346,41.9462544]},"n2189123278":{"id":"n2189123278","loc":[-85.6368371,41.9466153]},"n2189123280":{"id":"n2189123280","loc":[-85.6379537,41.9489088]},"n2189123282":{"id":"n2189123282","loc":[-85.6383816,41.9497858]},"n2189123285":{"id":"n2189123285","loc":[-85.6393673,41.9512417]},"n2189123287":{"id":"n2189123287","loc":[-85.640554,41.9517766]},"n2189123289":{"id":"n2189123289","loc":[-85.6411,41.9522344]},"n2189123291":{"id":"n2189123291","loc":[-85.6417418,41.9526574]},"n2189123293":{"id":"n2189123293","loc":[-85.642321,41.9529407]},"n2189123295":{"id":"n2189123295","loc":[-85.6427697,41.9532278]},"n2189123297":{"id":"n2189123297","loc":[-85.6433332,41.9538254]},"n2189123300":{"id":"n2189123300","loc":[-85.6435785,41.9543648]},"n2189123301":{"id":"n2189123301","loc":[-85.6444394,41.9541048]},"n2189123303":{"id":"n2189123303","loc":[-85.6450603,41.954]},"n2189123312":{"id":"n2189123312","loc":[-85.6454829,41.9539108]},"n2189123314":{"id":"n2189123314","loc":[-85.6460464,41.9538526]},"n2189123315":{"id":"n2189123315","loc":[-85.6463178,41.9537167]},"n2189123316":{"id":"n2189123316","loc":[-85.646276,41.9534141]},"n2189123317":{"id":"n2189123317","loc":[-85.6459995,41.9531541]},"n2189123318":{"id":"n2189123318","loc":[-85.645222,41.9531929]},"n2189123319":{"id":"n2189123319","loc":[-85.6447316,41.9531813]},"n2189123320":{"id":"n2189123320","loc":[-85.6440637,41.9532977]},"n2189123321":{"id":"n2189123321","loc":[-85.6438185,41.9531774]},"n2189123322":{"id":"n2189123322","loc":[-85.6440011,41.9528398]},"n2189123323":{"id":"n2189123323","loc":[-85.6442672,41.9525914]},"n2189123324":{"id":"n2189123324","loc":[-85.6442881,41.9523276]},"n2189123326":{"id":"n2189123326","loc":[-85.644262,41.952153]},"n2189123328":{"id":"n2189123328","loc":[-85.6441681,41.9520404]},"n2189123330":{"id":"n2189123330","loc":[-85.6442098,41.9517494]},"n2189123333":{"id":"n2189123333","loc":[-85.6438498,41.9515864]},"n2189123336":{"id":"n2189123336","loc":[-85.6435889,41.9513225]},"n2189123339":{"id":"n2189123339","loc":[-85.6425349,41.9510315]},"n2189123342":{"id":"n2189123342","loc":[-85.6422688,41.9508802]},"n2189123345":{"id":"n2189123345","loc":[-85.6418775,41.9508142]},"n2189123348":{"id":"n2189123348","loc":[-85.6415488,41.9508064]},"n2189123351":{"id":"n2189123351","loc":[-85.6411027,41.9505488]},"n2189123353":{"id":"n2189123353","loc":[-85.6410374,41.9498208]},"n2189123355":{"id":"n2189123355","loc":[-85.6410061,41.9494327]},"n2189123357":{"id":"n2189123357","loc":[-85.6411522,41.9482569]},"n2189123359":{"id":"n2189123359","loc":[-85.6410548,41.9473036]},"n2189123368":{"id":"n2189123368","loc":[-85.6380216,41.9458974]},"n2189123370":{"id":"n2189123370","loc":[-85.6386721,41.9507782]},"w17968193":{"id":"w17968193","tags":{"highway":"residential","name":"French St"},"nodes":["n185970906","n185982877","n185967774","n185985823","n185979974"]},"w203972939":{"id":"w203972939","tags":{"highway":"path"},"nodes":["n2139858965","n2139858966"]},"w203988289":{"id":"w203988289","tags":{"area":"yes","natural":"water"},"nodes":["n2140006367","n2140006368","n2140006419","n2140006369","n2140006417","n2140006370","n2140006372","n2140006374","n2140006376","n2140006378","n2140006380","n2140006382","n2140006389","n2140006391","n2140006393","n2140006367"]},"w208640157":{"id":"w208640157","tags":{"area":"yes","natural":"wetland"},"nodes":["n1819849029","n2189123275","n2189123278","n2189123280","n2189123282","n2189123370","n2189123285","n2189123287","n2189123289","n2189123291","n2189123293","n2189123295","n2189123297","n2189123300","n2189123301","n2189123303","n2189123312","n2189123314","n2189123315","n2189123316","n2189123317","n2189123318","n2189123319","n2189123320","n2189123321","n2189123322","n2189123323","n2189123324","n2189123326","n2189123328","n2189123330","n2189123333","n2189123336","n2189123339","n2189123342","n2189123345","n2189123348","n2189123351","n2189123353","n2189123355","n2189123357","n2189123359","n2189123361","n2189123363","n2189123365","n2189123368","n1819849029"]},"w17966281":{"id":"w17966281","tags":{"highway":"residential","name":"Pealer St"},"nodes":["n185975911","n185975913","n185975915","n1475284042","n185975917","n185975919","n185975925","n185970909","n1475284013","n1475283980","n185975928","n185967775","n185975930","n185975932","n185975934","n2139795809","n2139795810"]},"w17965353":{"id":"w17965353","tags":{"highway":"residential","name":"Yauney St"},"nodes":["n185966958","n185966959","n185966960","n185966962"]},"w203972938":{"id":"w203972938","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139858964","n2139858965","n2139858963","n2139858962","n2139858961","n2139858960","n2139858959","n2139858958","n2139858957","n2139858956","n2139858955","n2139858954","n2139858953","n2139858952","n2139858951"]},"n354002665":{"id":"n354002665","loc":[-85.6366599,41.9444923],"tags":{"name":"Memory Isle","place":"island"}},"n354031301":{"id":"n354031301","loc":[-85.635,41.9463889],"tags":{"amenity":"post_office","name":"Three Rivers Post Office"}},"n185963454":{"id":"n185963454","loc":[-85.633686,41.946072]},"n185963455":{"id":"n185963455","loc":[-85.633815,41.946131]},"n185963456":{"id":"n185963456","loc":[-85.633951,41.946174]},"n185978375":{"id":"n185978375","loc":[-85.634385,41.94559]},"n185978377":{"id":"n185978377","loc":[-85.634544,41.945725]},"n185978379":{"id":"n185978379","loc":[-85.634573,41.945764]},"n185978381":{"id":"n185978381","loc":[-85.634616,41.945849]},"n185978383":{"id":"n185978383","loc":[-85.634629,41.945893]},"n185984011":{"id":"n185984011","loc":[-85.636058,41.946201]},"n185984013":{"id":"n185984013","loc":[-85.636112,41.946366]},"n185984015":{"id":"n185984015","loc":[-85.636143,41.946551]},"n185988237":{"id":"n185988237","loc":[-85.6354162,41.946044]},"n185988969":{"id":"n185988969","loc":[-85.635374,41.945325]},"n185988971":{"id":"n185988971","loc":[-85.635643,41.945585]},"n185988972":{"id":"n185988972","loc":[-85.635853,41.94586]},"n1475283992":{"id":"n1475283992","loc":[-85.6372968,41.9459007]},"n1475284011":{"id":"n1475284011","loc":[-85.6359415,41.9459797]},"n1475284019":{"id":"n1475284019","loc":[-85.6364433,41.9460423]},"n185984009":{"id":"n185984009","loc":[-85.6360524,41.9460485]},"n185988239":{"id":"n185988239","loc":[-85.6358187,41.9460423]},"n185988243":{"id":"n185988243","loc":[-85.6366156,41.9460282]},"n185988244":{"id":"n185988244","loc":[-85.6368316,41.9460046]},"n185988245":{"id":"n185988245","loc":[-85.6370133,41.9459704]},"n185988241":{"id":"n185988241","loc":[-85.636291,41.9460461]},"n185964976":{"id":"n185964976","loc":[-85.633923,41.9434157]},"n185964980":{"id":"n185964980","loc":[-85.6333656,41.9437293]},"n185978388":{"id":"n185978388","loc":[-85.6346449,41.9460571]},"n1819858504":{"id":"n1819858504","loc":[-85.6365343,41.9447926]},"n1819858506":{"id":"n1819858506","loc":[-85.6370546,41.9451882]},"n1819858516":{"id":"n1819858516","loc":[-85.6358369,41.9444654]},"n1819858519":{"id":"n1819858519","loc":[-85.6361534,41.9446176]},"n1819858525":{"id":"n1819858525","loc":[-85.6368025,41.9449442]},"n1819858527":{"id":"n1819858527","loc":[-85.6334199,41.9457495]},"n185963452":{"id":"n185963452","loc":[-85.633564,41.9458519]},"n185963453":{"id":"n185963453","loc":[-85.6336152,41.9459804]},"n185963451":{"id":"n185963451","loc":[-85.6332888,41.9456871]},"n2130304152":{"id":"n2130304152","loc":[-85.6359466,41.9454599]},"n2130304153":{"id":"n2130304153","loc":[-85.6362773,41.9452683]},"n2130304154":{"id":"n2130304154","loc":[-85.6352028,41.9442868]},"n2130304155":{"id":"n2130304155","loc":[-85.6348756,41.9444769]},"n2130304156":{"id":"n2130304156","loc":[-85.6349723,41.9444207]},"n2130304157":{"id":"n2130304157","loc":[-85.6338698,41.9434443]},"n2130304158":{"id":"n2130304158","loc":[-85.635094,41.9451026]},"n2130304160":{"id":"n2130304160","loc":[-85.6353716,41.9449322]},"n2130304162":{"id":"n2130304162","loc":[-85.6365942,41.9459352]},"n2130304163":{"id":"n2130304163","loc":[-85.6369006,41.9457469]},"n2130304164":{"id":"n2130304164","loc":[-85.6363292,41.9452278]},"n2130304165":{"id":"n2130304165","loc":[-85.6360248,41.9454175]},"n2139824683":{"id":"n2139824683","loc":[-85.6339825,41.9446441]},"n2139824689":{"id":"n2139824689","loc":[-85.6340437,41.9446925]},"n2139824702":{"id":"n2139824702","loc":[-85.6340961,41.9447551]},"n2139824705":{"id":"n2139824705","loc":[-85.6337467,41.944809]},"n2139824707":{"id":"n2139824707","loc":[-85.6341598,41.9448129]},"n2139824710":{"id":"n2139824710","loc":[-85.6342771,41.9448223]},"n2139824712":{"id":"n2139824712","loc":[-85.6346058,41.944841]},"n2139824713":{"id":"n2139824713","loc":[-85.633808,41.9448574]},"n2139824714":{"id":"n2139824714","loc":[-85.6340889,41.9448589]},"n2139824716":{"id":"n2139824716","loc":[-85.6343335,41.944871]},"n2139824717":{"id":"n2139824717","loc":[-85.6343341,41.9448717]},"n2139824720":{"id":"n2139824720","loc":[-85.6338757,41.9449069]},"n2139824721":{"id":"n2139824721","loc":[-85.6341445,41.9449071]},"n2139824724":{"id":"n2139824724","loc":[-85.6334787,41.9449262]},"n2139824726":{"id":"n2139824726","loc":[-85.6347119,41.9449332]},"n2139824727":{"id":"n2139824727","loc":[-85.6347175,41.9449418]},"n2139824728":{"id":"n2139824728","loc":[-85.6344284,41.9449538]},"n2139824729":{"id":"n2139824729","loc":[-85.6339339,41.9449573]},"n2139824730":{"id":"n2139824730","loc":[-85.6339179,41.9449682]},"n2139824732":{"id":"n2139824732","loc":[-85.6335472,41.9449895]},"n2139824733":{"id":"n2139824733","loc":[-85.6339736,41.9450164]},"n2139824735":{"id":"n2139824735","loc":[-85.6336034,41.9450415]},"n2139824736":{"id":"n2139824736","loc":[-85.6348317,41.945043]},"n2139824737":{"id":"n2139824737","loc":[-85.63403,41.9450651]},"n2139824738":{"id":"n2139824738","loc":[-85.6336611,41.9450949]},"n2139824740":{"id":"n2139824740","loc":[-85.6336582,41.9450966]},"n2139824744":{"id":"n2139824744","loc":[-85.6331702,41.9451107]},"n2139824745":{"id":"n2139824745","loc":[-85.6333388,41.9451142]},"n2139824746":{"id":"n2139824746","loc":[-85.6337131,41.9451341]},"n2139824747":{"id":"n2139824747","loc":[-85.6337021,41.9451372]},"n2139824748":{"id":"n2139824748","loc":[-85.6341244,41.9451472]},"n2139824749":{"id":"n2139824749","loc":[-85.6333952,41.945166]},"n2139824750":{"id":"n2139824750","loc":[-85.633395,41.9451661]},"n2139824751":{"id":"n2139824751","loc":[-85.6346258,41.9451725]},"n2139824752":{"id":"n2139824752","loc":[-85.6332387,41.9451741]},"n2139824753":{"id":"n2139824753","loc":[-85.6346901,41.9451853]},"n2139824754":{"id":"n2139824754","loc":[-85.6346611,41.9452035]},"n2139824755":{"id":"n2139824755","loc":[-85.6346574,41.9452059]},"n2139824756":{"id":"n2139824756","loc":[-85.6345611,41.9452133]},"n2139824757":{"id":"n2139824757","loc":[-85.633453,41.9452194]},"n2139824758":{"id":"n2139824758","loc":[-85.6335508,41.9452283]},"n2139824759":{"id":"n2139824759","loc":[-85.6347424,41.9452312]},"n2139824760":{"id":"n2139824760","loc":[-85.6342305,41.9452395]},"n2139824761":{"id":"n2139824761","loc":[-85.6342319,41.9452449]},"n2139824762":{"id":"n2139824762","loc":[-85.6334969,41.94526]},"n2139824763":{"id":"n2139824763","loc":[-85.63468,41.9452706]},"n2139824764":{"id":"n2139824764","loc":[-85.6346772,41.9452724]},"n2139824765":{"id":"n2139824765","loc":[-85.6338611,41.9452763]},"n2139824766":{"id":"n2139824766","loc":[-85.6347811,41.9452939]},"n2139824767":{"id":"n2139824767","loc":[-85.6347375,41.9453211]},"n2139824768":{"id":"n2139824768","loc":[-85.6339171,41.9453301]},"n2139824769":{"id":"n2139824769","loc":[-85.6348307,41.9453377]},"n2139824770":{"id":"n2139824770","loc":[-85.6347067,41.9453405]},"n2139824771":{"id":"n2139824771","loc":[-85.6343461,41.9453461]},"n2139824772":{"id":"n2139824772","loc":[-85.6343481,41.9453475]},"n2139824773":{"id":"n2139824773","loc":[-85.634805,41.9453538]},"n2139824774":{"id":"n2139824774","loc":[-85.6336997,41.9453692]},"n2139824775":{"id":"n2139824775","loc":[-85.6339709,41.9453818]},"n2139824776":{"id":"n2139824776","loc":[-85.6336229,41.9454134]},"n2139824777":{"id":"n2139824777","loc":[-85.6349022,41.9454141]},"n2139824778":{"id":"n2139824778","loc":[-85.6348854,41.9454246]},"n2139824779":{"id":"n2139824779","loc":[-85.6340286,41.9454373]},"n2139824780":{"id":"n2139824780","loc":[-85.6336963,41.9454572]},"n2139824781":{"id":"n2139824781","loc":[-85.6336789,41.9454672]},"n2139824782":{"id":"n2139824782","loc":[-85.6344933,41.945475]},"n2139824783":{"id":"n2139824783","loc":[-85.6340854,41.9454918]},"n2139824784":{"id":"n2139824784","loc":[-85.6350036,41.9455034]},"n2139824785":{"id":"n2139824785","loc":[-85.6337501,41.9455089]},"n2139824786":{"id":"n2139824786","loc":[-85.6337497,41.9455091]},"n2139824787":{"id":"n2139824787","loc":[-85.6345425,41.9455186]},"n2139824788":{"id":"n2139824788","loc":[-85.6341459,41.9455372]},"n2139824789":{"id":"n2139824789","loc":[-85.6341376,41.945542]},"n2139824790":{"id":"n2139824790","loc":[-85.6338394,41.9455462]},"n2139824791":{"id":"n2139824791","loc":[-85.6349171,41.9455588]},"n2139824792":{"id":"n2139824792","loc":[-85.6338074,41.9455646]},"n2139824793":{"id":"n2139824793","loc":[-85.6346229,41.9455894]},"n2139824794":{"id":"n2139824794","loc":[-85.6338983,41.9455995]},"n2139824795":{"id":"n2139824795","loc":[-85.6338962,41.9456007]},"n2139824796":{"id":"n2139824796","loc":[-85.6342475,41.9456348]},"n2139824797":{"id":"n2139824797","loc":[-85.6339505,41.9456497]},"n2139824798":{"id":"n2139824798","loc":[-85.6347243,41.9456788]},"n2139824799":{"id":"n2139824799","loc":[-85.635057,41.9456831]},"n2139824800":{"id":"n2139824800","loc":[-85.635287,41.9457056]},"n2139824801":{"id":"n2139824801","loc":[-85.6350753,41.9457068]},"n2139824802":{"id":"n2139824802","loc":[-85.6347753,41.9457252]},"n2139824803":{"id":"n2139824803","loc":[-85.6340521,41.9457473]},"n2139824804":{"id":"n2139824804","loc":[-85.6352875,41.9457611]},"n2139824805":{"id":"n2139824805","loc":[-85.6352941,41.9457611]},"n2139824806":{"id":"n2139824806","loc":[-85.6350758,41.9457623]},"n2139824807":{"id":"n2139824807","loc":[-85.6348194,41.9457638]},"n2139824808":{"id":"n2139824808","loc":[-85.635296,41.9459428]},"n2139824809":{"id":"n2139824809","loc":[-85.6348212,41.9459455]},"n2139832635":{"id":"n2139832635","loc":[-85.6354612,41.9448791]},"n2139832636":{"id":"n2139832636","loc":[-85.6360241,41.9453844]},"n2139832637":{"id":"n2139832637","loc":[-85.6361452,41.9453121]},"n2139832639":{"id":"n2139832639","loc":[-85.6355997,41.944797]},"n2139832641":{"id":"n2139832641","loc":[-85.6351346,41.9443541]},"n2139832647":{"id":"n2139832647","loc":[-85.6329883,41.9453692]},"n2139832653":{"id":"n2139832653","loc":[-85.6333643,41.9456293]},"n2139832663":{"id":"n2139832663","loc":[-85.6335394,41.9455339]},"n2139832665":{"id":"n2139832665","loc":[-85.6332375,41.9452476]},"n2139832667":{"id":"n2139832667","loc":[-85.6331664,41.9452161]},"n2139832669":{"id":"n2139832669","loc":[-85.6331144,41.9451875]},"n2139832671":{"id":"n2139832671","loc":[-85.6330779,41.9451274]},"n2139832673":{"id":"n2139832673","loc":[-85.6330664,41.9450802]},"n2139832678":{"id":"n2139832678","loc":[-85.6332218,41.9453585]},"n2139832686":{"id":"n2139832686","loc":[-85.6334246,41.945541]},"n2139832691":{"id":"n2139832691","loc":[-85.6329898,41.9454997]},"n2139832693":{"id":"n2139832693","loc":[-85.6343554,41.9443274]},"n2139832694":{"id":"n2139832694","loc":[-85.6336339,41.9437089]},"n2139832696":{"id":"n2139832696","loc":[-85.633532,41.9437708]},"n2139832697":{"id":"n2139832697","loc":[-85.6338316,41.9440868]},"n2139832698":{"id":"n2139832698","loc":[-85.6342258,41.9444141]},"n2139832699":{"id":"n2139832699","loc":[-85.6339164,41.9442166]},"n2139832700":{"id":"n2139832700","loc":[-85.6341389,41.944384]},"n2139832701":{"id":"n2139832701","loc":[-85.634235,41.9443259]},"n2139832702":{"id":"n2139832702","loc":[-85.633613,41.9437875]},"n2139832703":{"id":"n2139832703","loc":[-85.633915,41.9436132]},"n2139832704":{"id":"n2139832704","loc":[-85.6340019,41.9435613]},"n2139832706":{"id":"n2139832706","loc":[-85.6343197,41.9438427]},"n2139832708":{"id":"n2139832708","loc":[-85.6342361,41.9438936]},"n2139832709":{"id":"n2139832709","loc":[-85.6353839,41.9460401]},"n2139832710":{"id":"n2139832710","loc":[-85.6354032,41.9456763]},"n2139832711":{"id":"n2139832711","loc":[-85.6356839,41.9459252]},"n2139832712":{"id":"n2139832712","loc":[-85.6356109,41.945735]},"n2139832713":{"id":"n2139832713","loc":[-85.6353997,41.9457421]},"n2139832714":{"id":"n2139832714","loc":[-85.6353895,41.9459347]},"n2139832715":{"id":"n2139832715","loc":[-85.6334777,41.9436628]},"n2139832716":{"id":"n2139832716","loc":[-85.6333137,41.9435382]},"n2139832717":{"id":"n2139832717","loc":[-85.6330938,41.9435406]},"n2139832721":{"id":"n2139832721","loc":[-85.6333023,41.9434922]},"n2139832722":{"id":"n2139832722","loc":[-85.6330466,41.943623]},"n2139832723":{"id":"n2139832723","loc":[-85.6332746,41.9435624]},"n2139832724":{"id":"n2139832724","loc":[-85.6333511,41.9435176]},"n2139832725":{"id":"n2139832725","loc":[-85.6332241,41.9434001]},"n2139832726":{"id":"n2139832726","loc":[-85.6332355,41.9433686]},"n2139870373":{"id":"n2139870373","loc":[-85.6351783,41.9439117]},"n2139870374":{"id":"n2139870374","loc":[-85.6351431,41.9439217]},"n2139870375":{"id":"n2139870375","loc":[-85.6348853,41.9439117]},"n2139870376":{"id":"n2139870376","loc":[-85.6348317,41.9439105]},"n2139870377":{"id":"n2139870377","loc":[-85.6346384,41.944007]},"n2139870378":{"id":"n2139870378","loc":[-85.6345563,41.9440523]},"n2140006403":{"id":"n2140006403","loc":[-85.6359942,41.9450097]},"n2140006405":{"id":"n2140006405","loc":[-85.6363884,41.9446079]},"n2140006407":{"id":"n2140006407","loc":[-85.6362148,41.9447874]},"n2140006409":{"id":"n2140006409","loc":[-85.6379476,41.9445869]},"n2140006411":{"id":"n2140006411","loc":[-85.6378485,41.9445674]},"n2140006413":{"id":"n2140006413","loc":[-85.6378952,41.9444547]},"n2140006415":{"id":"n2140006415","loc":[-85.6379962,41.944477]},"n2140006421":{"id":"n2140006421","loc":[-85.6355248,41.9433702]},"n2140006423":{"id":"n2140006423","loc":[-85.6378471,41.9439233]},"n2140006425":{"id":"n2140006425","loc":[-85.6378913,41.9441238]},"n2140006426":{"id":"n2140006426","loc":[-85.6381674,41.9442289]},"n2140006427":{"id":"n2140006427","loc":[-85.6382359,41.9440975]},"n2140006428":{"id":"n2140006428","loc":[-85.6382071,41.9440252]},"n2140006429":{"id":"n2140006429","loc":[-85.6381409,41.9439973]},"n2140006430":{"id":"n2140006430","loc":[-85.6380569,41.9440153]},"n2140006433":{"id":"n2140006433","loc":[-85.6379071,41.9442467]},"n2140006435":{"id":"n2140006435","loc":[-85.6381634,41.9443125]},"n2140006436":{"id":"n2140006436","loc":[-85.6382407,41.944301]},"n2140006438":{"id":"n2140006438","loc":[-85.6382761,41.9442188]},"n2140006439":{"id":"n2140006439","loc":[-85.6382429,41.9441761]},"n2140006440":{"id":"n2140006440","loc":[-85.6382016,41.9441632]},"n2140006441":{"id":"n2140006441","loc":[-85.6378185,41.9439835]},"n2166205688":{"id":"n2166205688","loc":[-85.6349963,41.9444392]},"n2168544780":{"id":"n2168544780","loc":[-85.633944,41.945807]},"n2168544781":{"id":"n2168544781","loc":[-85.6340783,41.9458621]},"n2168544782":{"id":"n2168544782","loc":[-85.6338184,41.9457548]},"n2168544783":{"id":"n2168544783","loc":[-85.6339925,41.9459777]},"n2168544784":{"id":"n2168544784","loc":[-85.6337317,41.9458698]},"n2168544785":{"id":"n2168544785","loc":[-85.6337297,41.9460042]},"n2168544786":{"id":"n2168544786","loc":[-85.633919,41.9460797]},"n2168544787":{"id":"n2168544787","loc":[-85.6338672,41.9459263]},"n2168544788":{"id":"n2168544788","loc":[-85.6338246,41.9459853]},"n2168544789":{"id":"n2168544789","loc":[-85.6337615,41.9459601]},"n2168544790":{"id":"n2168544790","loc":[-85.6342079,41.9460399]},"n2168544791":{"id":"n2168544791","loc":[-85.6343346,41.9458503]},"n2168544792":{"id":"n2168544792","loc":[-85.6343759,41.9458116]},"n2168544793":{"id":"n2168544793","loc":[-85.6344394,41.9458109]},"n2168544795":{"id":"n2168544795","loc":[-85.6344827,41.945851]},"n2168544797":{"id":"n2168544797","loc":[-85.6344807,41.945969]},"n2168544798":{"id":"n2168544798","loc":[-85.6344404,41.9459697]},"n2168544799":{"id":"n2168544799","loc":[-85.6344413,41.9460333]},"n2168544800":{"id":"n2168544800","loc":[-85.6342173,41.9460705]},"n2168544801":{"id":"n2168544801","loc":[-85.6342162,41.9460392]},"n2168544802":{"id":"n2168544802","loc":[-85.6344251,41.9460351]},"n2168544805":{"id":"n2168544805","loc":[-85.6344257,41.9460507]},"n2168544807":{"id":"n2168544807","loc":[-85.6344721,41.9460498]},"n2168544809":{"id":"n2168544809","loc":[-85.6344754,41.9461427]},"n2168544811":{"id":"n2168544811","loc":[-85.6344311,41.9461435]},"n2168544813":{"id":"n2168544813","loc":[-85.6344317,41.9461592]},"n2168544815":{"id":"n2168544815","loc":[-85.6343708,41.9461604]},"n2168544817":{"id":"n2168544817","loc":[-85.6343715,41.9461786]},"n2168544819":{"id":"n2168544819","loc":[-85.6343229,41.9461795]},"n2168544821":{"id":"n2168544821","loc":[-85.6343222,41.9461606]},"n2168544823":{"id":"n2168544823","loc":[-85.6342476,41.9461621]},"n2168544825":{"id":"n2168544825","loc":[-85.6342444,41.94607]},"n2168544827":{"id":"n2168544827","loc":[-85.634138,41.9461632]},"n2168544829":{"id":"n2168544829","loc":[-85.6342016,41.9460703]},"n2168544830":{"id":"n2168544830","loc":[-85.6332929,41.9463092]},"n2168544831":{"id":"n2168544831","loc":[-85.633122,41.946239]},"n2168544832":{"id":"n2168544832","loc":[-85.6332954,41.9460055]},"n2168544833":{"id":"n2168544833","loc":[-85.6333954,41.9460466]},"n2168544834":{"id":"n2168544834","loc":[-85.6334044,41.9460345]},"n2168544835":{"id":"n2168544835","loc":[-85.6334594,41.9460571]},"n2168544836":{"id":"n2168544836","loc":[-85.6333871,41.9461544]},"n2168544837":{"id":"n2168544837","loc":[-85.633403,41.9461609]},"n2168544838":{"id":"n2168544838","loc":[-85.6341683,41.9464167]},"n2168544839":{"id":"n2168544839","loc":[-85.6341711,41.9463411]},"n2168544840":{"id":"n2168544840","loc":[-85.6344471,41.9463469]},"n2168544841":{"id":"n2168544841","loc":[-85.6344441,41.9464243]},"n2168544842":{"id":"n2168544842","loc":[-85.6343622,41.9464226]},"n2168544843":{"id":"n2168544843","loc":[-85.6343593,41.9464989]},"n2168544844":{"id":"n2168544844","loc":[-85.6342812,41.9464973]},"n2168544845":{"id":"n2168544845","loc":[-85.634283,41.9464504]},"n2168544846":{"id":"n2168544846","loc":[-85.6342609,41.9464499]},"n2168544847":{"id":"n2168544847","loc":[-85.6342621,41.9464187]},"n2168544848":{"id":"n2168544848","loc":[-85.6348414,41.9463396]},"n2168544849":{"id":"n2168544849","loc":[-85.6348387,41.9461872]},"n2168544850":{"id":"n2168544850","loc":[-85.6351186,41.9461844]},"n2168544851":{"id":"n2168544851","loc":[-85.635119,41.9462112]},"n2168544852":{"id":"n2168544852","loc":[-85.6351918,41.9462104]},"n2168544853":{"id":"n2168544853","loc":[-85.6351944,41.9463515]},"n2168544854":{"id":"n2168544854","loc":[-85.6351049,41.9463524]},"n2168544855":{"id":"n2168544855","loc":[-85.6351046,41.946337]},"n2189153180":{"id":"n2189153180","loc":[-85.6340369,41.9469572]},"n2189153181":{"id":"n2189153181","loc":[-85.6342531,41.946953]},"n2189153183":{"id":"n2189153183","loc":[-85.6348115,41.9465468]},"n2189153184":{"id":"n2189153184","loc":[-85.6348105,41.9464569]},"n2189153185":{"id":"n2189153185","loc":[-85.6351431,41.9464549]},"n2189153186":{"id":"n2189153186","loc":[-85.6351441,41.9465448]},"n2189153187":{"id":"n2189153187","loc":[-85.6350077,41.9465456]},"n2189153188":{"id":"n2189153188","loc":[-85.635008,41.9465721]},"n2189153189":{"id":"n2189153189","loc":[-85.6348965,41.9465727]},"n2189153190":{"id":"n2189153190","loc":[-85.6348962,41.9465463]},"n2189153191":{"id":"n2189153191","loc":[-85.6348963,41.9471586]},"n2189153192":{"id":"n2189153192","loc":[-85.6348944,41.947032]},"n2189153193":{"id":"n2189153193","loc":[-85.6350241,41.947031]},"n2189153194":{"id":"n2189153194","loc":[-85.635026,41.9471575]},"n2189153195":{"id":"n2189153195","loc":[-85.6352328,41.9471053]},"n2189153196":{"id":"n2189153196","loc":[-85.6352359,41.9469906]},"n2189153197":{"id":"n2189153197","loc":[-85.6353694,41.9469925]},"n2189153198":{"id":"n2189153198","loc":[-85.6353664,41.9471072]},"n2189153199":{"id":"n2189153199","loc":[-85.6348241,41.9469287]},"n2189153200":{"id":"n2189153200","loc":[-85.6348248,41.9468185]},"n2189153201":{"id":"n2189153201","loc":[-85.6351199,41.9468195]},"n2189153202":{"id":"n2189153202","loc":[-85.6351192,41.9469298]},"n2189153203":{"id":"n2189153203","loc":[-85.6347965,41.9468057]},"n2189153204":{"id":"n2189153204","loc":[-85.634792,41.9466044]},"n2189153205":{"id":"n2189153205","loc":[-85.6349483,41.9466025]},"n2189153206":{"id":"n2189153206","loc":[-85.6349493,41.9466448]},"n2189153207":{"id":"n2189153207","loc":[-85.6349753,41.9466445]},"n2189153208":{"id":"n2189153208","loc":[-85.6349743,41.9465995]},"n2189153209":{"id":"n2189153209","loc":[-85.6351173,41.9465977]},"n2189153210":{"id":"n2189153210","loc":[-85.6351219,41.9468015]},"n2189153211":{"id":"n2189153211","loc":[-85.6349806,41.9468032]},"n2189153212":{"id":"n2189153212","loc":[-85.6349794,41.9467519]},"n2189153213":{"id":"n2189153213","loc":[-85.6349521,41.9467523]},"n2189153214":{"id":"n2189153214","loc":[-85.6349532,41.9468037]},"n2189153215":{"id":"n2189153215","loc":[-85.6346302,41.9468381]},"n2189153216":{"id":"n2189153216","loc":[-85.6343028,41.9468449]},"n2189153217":{"id":"n2189153217","loc":[-85.6342006,41.9468297]},"n2189153218":{"id":"n2189153218","loc":[-85.6336698,41.9465918]},"n2189153219":{"id":"n2189153219","loc":[-85.6344663,41.9466639]},"n2189153220":{"id":"n2189153220","loc":[-85.6344639,41.9466015]},"n2189153221":{"id":"n2189153221","loc":[-85.6342283,41.9466065]},"n2189153222":{"id":"n2189153222","loc":[-85.6342303,41.9466587]},"n2189153223":{"id":"n2189153223","loc":[-85.6342843,41.9466575]},"n2189153224":{"id":"n2189153224","loc":[-85.6342851,41.9466794]},"n2189153225":{"id":"n2189153225","loc":[-85.6343475,41.9466781]},"n2189153226":{"id":"n2189153226","loc":[-85.634347,41.9466664]},"n2189153227":{"id":"n2189153227","loc":[-85.6354428,41.9470148]},"n2189153228":{"id":"n2189153228","loc":[-85.6354432,41.9468005]},"n2189153229":{"id":"n2189153229","loc":[-85.6360277,41.9468011]},"n2189153230":{"id":"n2189153230","loc":[-85.6360273,41.9470154]},"n2189153231":{"id":"n2189153231","loc":[-85.6354565,41.9465823]},"n2189153232":{"id":"n2189153232","loc":[-85.6354496,41.946218]},"n2189153233":{"id":"n2189153233","loc":[-85.6356355,41.9465788]},"n2189153234":{"id":"n2189153234","loc":[-85.6357155,41.9468008]},"n2189153235":{"id":"n2189153235","loc":[-85.6359539,41.9467969]},"n2189153236":{"id":"n2189153236","loc":[-85.6359561,41.9463036]},"n2189153237":{"id":"n2189153237","loc":[-85.6360129,41.9464793]},"n2189153238":{"id":"n2189153238","loc":[-85.6360152,41.9463898]},"n2189153239":{"id":"n2189153239","loc":[-85.6359607,41.9464928]},"n2189153240":{"id":"n2189153240","loc":[-85.6356903,41.9462227]},"n2189153242":{"id":"n2189153242","loc":[-85.6354163,41.946142]},"n2189153243":{"id":"n2189153243","loc":[-85.6357546,41.9462214]},"n2189153244":{"id":"n2189153244","loc":[-85.6357937,41.9462542]},"n2189153245":{"id":"n2189153245","loc":[-85.6358723,41.9467048]},"n2189153246":{"id":"n2189153246","loc":[-85.6361494,41.946757]},"n2189153247":{"id":"n2189153247","loc":[-85.6354173,41.9469082]},"n2189153248":{"id":"n2189153248","loc":[-85.635443,41.9469079]},"n2189153249":{"id":"n2189153249","loc":[-85.6360275,41.9469093]},"n2189153250":{"id":"n2189153250","loc":[-85.6361542,41.946915]},"n2189153251":{"id":"n2189153251","loc":[-85.6358654,41.9464843]},"n2189153252":{"id":"n2189153252","loc":[-85.6359549,41.9467499]},"n2189153253":{"id":"n2189153253","loc":[-85.6357172,41.9466335]},"n2189153254":{"id":"n2189153254","loc":[-85.6355644,41.9461768]},"n2189153255":{"id":"n2189153255","loc":[-85.6355655,41.946528]},"n2189153256":{"id":"n2189153256","loc":[-85.6357055,41.9465971]},"n2189153257":{"id":"n2189153257","loc":[-85.635869,41.9465971]},"n2189153259":{"id":"n2189153259","loc":[-85.6354561,41.9470278]},"n2189153260":{"id":"n2189153260","loc":[-85.6357961,41.9470233]},"n2189153261":{"id":"n2189153261","loc":[-85.6357977,41.9470907]},"n2189153262":{"id":"n2189153262","loc":[-85.6357297,41.9470916]},"n2189153263":{"id":"n2189153263","loc":[-85.635733,41.947233]},"n2189153264":{"id":"n2189153264","loc":[-85.6362674,41.9468637]},"n2189153265":{"id":"n2189153265","loc":[-85.6362646,41.9467047]},"n2189153266":{"id":"n2189153266","loc":[-85.6363267,41.9467047]},"n2189153267":{"id":"n2189153267","loc":[-85.6362633,41.9465848]},"n2189153268":{"id":"n2189153268","loc":[-85.6363805,41.9465468]},"n2189153269":{"id":"n2189153269","loc":[-85.6364604,41.9466842]},"n2189153270":{"id":"n2189153270","loc":[-85.6364604,41.9468647]},"n2199109756":{"id":"n2199109756","loc":[-85.6337134,41.9471841]},"n2199109757":{"id":"n2199109757","loc":[-85.6336514,41.94716]},"n2199109758":{"id":"n2199109758","loc":[-85.6337043,41.9470847]},"n2199109759":{"id":"n2199109759","loc":[-85.6335997,41.9470441]},"n2199109760":{"id":"n2199109760","loc":[-85.6335064,41.9471771]},"n185960195":{"id":"n185960195","loc":[-85.6295992,41.9524346]},"n185960796":{"id":"n185960796","loc":[-85.634723,41.953681]},"n185961396":{"id":"n185961396","loc":[-85.634767,41.959009]},"n185962625":{"id":"n185962625","loc":[-85.635175,41.97201]},"n185964982":{"id":"n185964982","loc":[-85.632799,41.9440543]},"n185965289":{"id":"n185965289","loc":[-85.634621,41.947323]},"n185965291":{"id":"n185965291","loc":[-85.636166,41.947296]},"n185965399":{"id":"n185965399","loc":[-85.634776,41.959834]},"n185966937":{"id":"n185966937","loc":[-85.633183,41.947315]},"n185966948":{"id":"n185966948","loc":[-85.626406,41.957188]},"n185967422":{"id":"n185967422","loc":[-85.6320229,41.9490123]},"n185967917":{"id":"n185967917","loc":[-85.634763,41.958292]},"n185967918":{"id":"n185967918","loc":[-85.636271,41.958311]},"n185968100":{"id":"n185968100","loc":[-85.630835,41.950656]},"n185970515":{"id":"n185970515","loc":[-85.634832,41.963866]},"n185971578":{"id":"n185971578","loc":[-85.634641,41.948627]},"n185971580":{"id":"n185971580","loc":[-85.6361818,41.9486135]},"n185971631":{"id":"n185971631","loc":[-85.634729,41.954667]},"n185971632":{"id":"n185971632","loc":[-85.636236,41.954656]},"n185972155":{"id":"n185972155","loc":[-85.623333,41.961987]},"n185974583":{"id":"n185974583","loc":[-85.634686,41.951158]},"n185974585":{"id":"n185974585","loc":[-85.6362059,41.9511457]},"n185975064":{"id":"n185975064","loc":[-85.636218,41.953667]},"n185975735":{"id":"n185975735","loc":[-85.634923,41.969269]},"n185978390":{"id":"n185978390","loc":[-85.634668,41.949875]},"n185978392":{"id":"n185978392","loc":[-85.634686,41.952415]},"n185978394":{"id":"n185978394","loc":[-85.634726,41.955921]},"n185978399":{"id":"n185978399","loc":[-85.6347861,41.9606613]},"n185978402":{"id":"n185978402","loc":[-85.634806,41.961485]},"n185978406":{"id":"n185978406","loc":[-85.6348298,41.964783]},"n185978410":{"id":"n185978410","loc":[-85.6348766,41.9677088]},"n185978414":{"id":"n185978414","loc":[-85.634938,41.971566]},"n185978415":{"id":"n185978415","loc":[-85.634942,41.971611]},"n185978417":{"id":"n185978417","loc":[-85.634952,41.971655]},"n185978419":{"id":"n185978419","loc":[-85.634989,41.971741]},"n185978420":{"id":"n185978420","loc":[-85.635063,41.971864]},"n185978787":{"id":"n185978787","loc":[-85.627936,41.954693]},"n185978790":{"id":"n185978790","loc":[-85.626832,41.954677]},"n185978967":{"id":"n185978967","loc":[-85.632278,41.948613]},"n185980735":{"id":"n185980735","loc":[-85.628639,41.953725]},"n185982163":{"id":"n185982163","loc":[-85.636233,41.952398]},"n185982193":{"id":"n185982193","loc":[-85.6313855,41.9499125]},"n185982195":{"id":"n185982195","loc":[-85.6304857,41.9511945]},"n185982196":{"id":"n185982196","loc":[-85.626336,41.957291]},"n185982197":{"id":"n185982197","loc":[-85.625578,41.958664]},"n185982198":{"id":"n185982198","loc":[-85.624619,41.960145]},"n185982200":{"id":"n185982200","loc":[-85.624494,41.960338]},"n185984017":{"id":"n185984017","loc":[-85.636163,41.947382]},"n185984020":{"id":"n185984020","loc":[-85.636188,41.9498803]},"n185984022":{"id":"n185984022","loc":[-85.636276,41.955919]},"n185984024":{"id":"n185984024","loc":[-85.636279,41.956901]},"n185988036":{"id":"n185988036","loc":[-85.631422,41.948294]},"n185988867":{"id":"n185988867","loc":[-85.63102,41.948805]},"n185988869":{"id":"n185988869","loc":[-85.630773,41.949209]},"n185988871":{"id":"n185988871","loc":[-85.63005,41.95016]},"n185988872":{"id":"n185988872","loc":[-85.629423,41.951016]},"n185988873":{"id":"n185988873","loc":[-85.629252,41.951256]},"n185988875":{"id":"n185988875","loc":[-85.629126,41.951489]},"n185988877":{"id":"n185988877","loc":[-85.628991,41.951704]},"n185988878":{"id":"n185988878","loc":[-85.628689,41.952112]},"n185988879":{"id":"n185988879","loc":[-85.628313,41.952666]},"n185988880":{"id":"n185988880","loc":[-85.627687,41.953529]},"n185988882":{"id":"n185988882","loc":[-85.627394,41.953947]},"n185988884":{"id":"n185988884","loc":[-85.627287,41.954128]},"n1819858502":{"id":"n1819858502","loc":[-85.6328435,41.9455473]},"n1819858510":{"id":"n1819858510","loc":[-85.6324841,41.9453438]},"n1819858515":{"id":"n1819858515","loc":[-85.6318511,41.9446409]},"n1819858520":{"id":"n1819858520","loc":[-85.6326558,41.9454708]},"n1819858522":{"id":"n1819858522","loc":[-85.6319048,41.9447407]},"n1819858524":{"id":"n1819858524","loc":[-85.6317718,41.9443666]},"n1819858530":{"id":"n1819858530","loc":[-85.632055,41.9449128]},"n2139795768":{"id":"n2139795768","loc":[-85.6243023,41.9606102]},"n2139832645":{"id":"n2139832645","loc":[-85.6324455,41.9448607]},"n2139832649":{"id":"n2139832649","loc":[-85.6328043,41.9454773]},"n2139832651":{"id":"n2139832651","loc":[-85.6322547,41.9449621]},"n2139832675":{"id":"n2139832675","loc":[-85.6327356,41.944757]},"n2139832677":{"id":"n2139832677","loc":[-85.6325433,41.9448599]},"n2139832680":{"id":"n2139832680","loc":[-85.6328885,41.9455614]},"n2139832682":{"id":"n2139832682","loc":[-85.6320913,41.9449492]},"n2139832684":{"id":"n2139832684","loc":[-85.6325366,41.9447133]},"n2139832688":{"id":"n2139832688","loc":[-85.6322786,41.94485]},"n2139832718":{"id":"n2139832718","loc":[-85.6327486,41.9432475]},"n2139832719":{"id":"n2139832719","loc":[-85.6327926,41.9431773]},"n2139832720":{"id":"n2139832720","loc":[-85.6329033,41.943153]},"n2139832727":{"id":"n2139832727","loc":[-85.6328975,41.9430783]},"n2139844839":{"id":"n2139844839","loc":[-85.6326261,41.9432308]},"n2189015992":{"id":"n2189015992","loc":[-85.6347706,41.9593383]},"n2189153179":{"id":"n2189153179","loc":[-85.6340476,41.9472565]},"n2189153182":{"id":"n2189153182","loc":[-85.6342638,41.9472522]},"n2189153241":{"id":"n2189153241","loc":[-85.6354184,41.9473091]},"n2189153258":{"id":"n2189153258","loc":[-85.6354611,41.9472366]},"n2189153277":{"id":"n2189153277","loc":[-85.6328948,41.9462374]},"n2199109755":{"id":"n2199109755","loc":[-85.6336729,41.9472417]},"w203970139":{"id":"w203970139","tags":{"building":"yes"},"nodes":["n2139824793","n2139824787","n2139824773","n2139824778","n2139824793"]},"w203970098":{"id":"w203970098","tags":{"building":"yes"},"nodes":["n2139824748","n2139824712","n2139824726","n2139824760","n2139824748"]},"w208643132":{"id":"w208643132","tags":{"area":"yes","building":"yes"},"nodes":["n2189153195","n2189153196","n2189153197","n2189153198","n2189153195"]},"w203970094":{"id":"w203970094","tags":{"building":"yes"},"nodes":["n2139824755","n2139824753","n2139824759","n2139824764","n2139824763","n2139824767","n2139824770","n2139824782","n2139824772","n2139824756","n2139824751","n2139824754","n2139824755"]},"w208643138":{"id":"w208643138","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153231","n2189153232","n2189153240","n2189153244","n2189153236","n2189153238","n2189153237","n2189153239","n2189153252","n2189153235","n2189153234","n2189153253","n2189153233","n2189153231"]},"w203970125":{"id":"w203970125","tags":{"building":"yes"},"nodes":["n2139824735","n2139824738","n2139824757","n2139824749","n2139824735"]},"w170848823":{"id":"w170848823","tags":{"name":"Rocky River","waterway":"river"},"nodes":["n1819849189","n1819858516","n1819858519","n1819858504","n1819858525","n1819858506","n1819858513"]},"w203970898":{"id":"w203970898","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832645","n2139832647","n2139832649","n2139832651","n2139832645"]},"w203970134":{"id":"w203970134","tags":{"building":"yes"},"nodes":["n2139824796","n2139824803","n2139824797","n2139824788","n2139824796"]},"w203970104":{"id":"w203970104","tags":{"building":"yes"},"nodes":["n2139824733","n2139824730","n2139824714","n2139824721","n2139824733"]},"w206805245":{"id":"w206805245","tags":{"area":"yes","building":"yes"},"nodes":["n2168544780","n2168544781","n2139824796","n2139824803","n2168544780"]},"w206805252":{"id":"w206805252","tags":{"area":"yes","building":"yes"},"nodes":["n2168544838","n2168544839","n2168544840","n2168544841","n2168544842","n2168544843","n2168544844","n2168544845","n2168544846","n2168544847","n2168544838"]},"w203970099":{"id":"w203970099","tags":{"building":"yes"},"nodes":["n2139824783","n2139824795","n2139824790","n2139824779","n2139824783"]},"w17967730":{"id":"w17967730","tags":{"highway":"residential","name":"Water St"},"nodes":["n185963451","n2189153277","n185988036","n185988867","n185988869","n185988871","n185988872","n185988873","n185988875","n185988877","n185988878","n185988879","n185988880","n185988882","n185988884","n185978790"]},"w208643133":{"id":"w208643133","tags":{"area":"yes","building":"yes"},"nodes":["n2189153199","n2189153200","n2189153201","n2189153202","n2189153199"]},"w203970127":{"id":"w203970127","tags":{"building":"yes"},"nodes":["n2139824794","n2139824783","n2139824789","n2139824797","n2139824794"]},"w208643139":{"id":"w208643139","tags":{"highway":"service"},"nodes":["n185988237","n2189153242","n2189153247","n2189153241"]},"w203988297":{"id":"w203988297","tags":{"amenity":"parking","area":"yes"},"nodes":["n2140006423","n2140006441","n2140006425","n2140006426","n2140006440","n2140006427","n2140006428","n2140006429","n2140006430","n2140006423"]},"w206805250":{"id":"w206805250","tags":{"area":"yes","building":"yes"},"nodes":["n2168544827","n2168544823","n2168544825","n2168544800","n2168544829","n2168544827"]},"w208643140":{"id":"w208643140","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153242","n2189153254","n2189153243","n2189153244","n2189153251","n2189153257","n2189153245","n2189153252","n2189153246"]},"w203974055":{"id":"w203974055","tags":{"bridge":"yes","highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870376","n2139870377"]},"w206805247":{"id":"w206805247","tags":{"area":"yes","building":"yes"},"nodes":["n2168544785","n2168544786","n2168544783","n2168544787","n2168544788","n2168544789","n2168544785"]},"w17964996":{"id":"w17964996","tags":{"highway":"residential","name":"Foster St"},"nodes":["n1819858524","n1819858515","n1819858522","n1819858530","n2139832682","n1819858510","n1819858520","n1819858502","n2139832680","n185963451","n1819858527","n185963452","n185963453","n185963454","n185963455","n185963456"]},"w208643144":{"id":"w208643144","tags":{"area":"yes","building":"yes"},"nodes":["n2189153264","n2189153265","n2189153266","n2189153267","n2189153268","n2189153269","n2189153270","n2189153264"]},"w203970914":{"id":"w203970914","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832722","n2139832723","n2139832724","n2139832725","n2139832726","n2139832727","n2139844839","n2139832722"]},"w208643143":{"id":"w208643143","tags":{"area":"yes","building":"yes"},"nodes":["n2189153258","n2189153259","n2189153260","n2189153261","n2189153262","n2189153263","n2189153258"]},"w203049590":{"id":"w203049590","tags":{"amenity":"parking","area":"yes"},"nodes":["n2130304152","n2130304153","n2140006403","n2130304154","n2130304156","n2130304155","n2130304160","n2130304152"]},"w203974054":{"id":"w203974054","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139858971","n2139870373","n2139870374"]},"w203049595":{"id":"w203049595","tags":{"highway":"service"},"nodes":["n2130304158","n2130304159","n2130304160","n2139832635","n2139832639"]},"w203970913":{"id":"w203970913","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832715","n2139832716","n2139832717","n2139832718","n2139832719","n2139832720","n2139832721","n2139832716"]},"w208643134":{"id":"w208643134","tags":{"area":"yes","building":"yes"},"nodes":["n2189153203","n2189153204","n2189153205","n2189153206","n2189153207","n2189153208","n2189153209","n2189153210","n2189153211","n2189153212","n2189153213","n2189153214","n2189153203"]},"w134150808":{"id":"w134150808","tags":{"bridge":"yes","highway":"residential","name":"Moore St"},"nodes":["n185988239","n185984009","n185988241","n1475284019"]},"w203970115":{"id":"w203970115","tags":{"building":"yes"},"nodes":["n2139824761","n2139824727","n2139824736","n2139824771","n2139824761"]},"w208643130":{"id":"w208643130","tags":{"area":"yes","building":"yes"},"nodes":["n2189153183","n2189153184","n2189153185","n2189153186","n2189153187","n2189153188","n2189153189","n2189153190","n2189153183"]},"w206805246":{"id":"w206805246","tags":{"area":"yes","building":"yes"},"nodes":["n2168544782","n2168544780","n2168544781","n2168544783","n2168544787","n2168544784","n2168544782"]},"w203970138":{"id":"w203970138","tags":{"building":"yes"},"nodes":["n2139824729","n2139824720","n2139824702","n2139824707","n2139824729"]},"w203970133":{"id":"w203970133","tags":{"building":"yes"},"nodes":["n2139824748","n2139824737","n2139824717","n2139824728","n2139824748"]},"w203970907":{"id":"w203970907","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832700","n2139832701","n2139832702"]},"w203974056":{"id":"w203974056","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870377","n2139870378"]},"w203970897":{"id":"w203970897","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2130304156","n2166205688","n2139832635","n2139832636","n2139832637","n2139832639","n2139832641","n2166205688"]},"w203974057":{"id":"w203974057","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870375","n2139870376"]},"w203049594":{"id":"w203049594","tags":{"highway":"service"},"nodes":["n2130304156","n2139870378","n2139832706","n2139832704","n2130304157"]},"w203970122":{"id":"w203970122","tags":{"building":"yes"},"nodes":["n2139824757","n2139824740","n2139824747","n2139824762","n2139824757"]},"w208643136":{"id":"w208643136","tags":{"area":"yes","building":"yes"},"nodes":["n2189153219","n2189153220","n2189153221","n2189153222","n2189153223","n2189153224","n2189153225","n2189153226","n2189153219"]},"w203970128":{"id":"w203970128","tags":{"building":"yes"},"nodes":["n2139824732","n2139824752","n2139824744","n2139824724","n2139824732"]},"w203970097":{"id":"w203970097","tags":{"building":"yes"},"nodes":["n2139824737","n2139824733","n2139824710","n2139824716","n2139824737"]},"w203970137":{"id":"w203970137","tags":{"building":"yes"},"nodes":["n2139824765","n2139824774","n2139824758","n2139824746","n2139824765"]},"w134150840":{"id":"w134150840","tags":{"highway":"residential","name":"Moore St"},"nodes":["n1475284019","n185988243","n185988244","n185988245"]},"w17967628":{"id":"w17967628","tags":{"highway":"residential","name":"Moore St"},"nodes":["n185978388","n2139832709","n185988237","n185988239"]},"w203988292":{"id":"w203988292","tags":{"bridge":"yes","highway":"footway"},"nodes":["n2140006407","n2140006405"]},"w203970118":{"id":"w203970118","tags":{"building":"yes"},"nodes":["n2139824775","n2139824785","n2139824780","n2139824768","n2139824775"]},"w203970121":{"id":"w203970121","tags":{"building":"yes"},"nodes":["n2139824768","n2139824781","n2139824776","n2139824765","n2139824768"]},"w17967752":{"id":"w17967752","tags":{"highway":"residential","name":"Railroad Drive"},"nodes":["n185964980","n2139832699","n2139832700","n2130304158","n185988969","n185988971","n185988972","n1475284011"]},"w203970136":{"id":"w203970136","tags":{"building":"yes"},"nodes":["n2139824798","n2139824793","n2139824777","n2139824784","n2139824798"]},"w203970142":{"id":"w203970142","tags":{"building":"yes"},"nodes":["n2139824808","n2139824809","n2139824807","n2139824806","n2139824801","n2139824800","n2139824804","n2139824805","n2139824808"]},"w208643137":{"id":"w208643137","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153227","n2189153248","n2189153228","n2189153234","n2189153235","n2189153229","n2189153249","n2189153230","n2189153227"]},"w208643129":{"id":"w208643129","tags":{"area":"yes","building":"yes"},"nodes":["n2189153179","n2189153180","n2189153181","n2189153182","n2189153179"]},"w203970909":{"id":"w203970909","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832703","n2139832704","n2139832706","n2139832708","n2139832703"]},"w203970905":{"id":"w203970905","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832688","n2139832691"]},"w203988298":{"id":"w203988298","tags":{"highway":"service"},"nodes":["n2140006431","n2140006433","n2140006435","n2140006436","n2140006437","n2140006438","n2140006439","n2140006440"]},"w203970106":{"id":"w203970106","tags":{"building":"yes"},"nodes":["n2139824798","n2139824791","n2139824799","n2139824802","n2139824798"]},"w203970129":{"id":"w203970129","tags":{"building":"yes"},"nodes":["n2139824787","n2139824782","n2139824766","n2139824769","n2139824787"]},"w208643131":{"id":"w208643131","tags":{"area":"yes","building":"yes"},"nodes":["n2189153191","n2189153192","n2189153193","n2189153194","n2189153191"]},"w206805249":{"id":"w206805249","tags":{"area":"yes","building":"yes"},"nodes":["n2168544800","n2168544801","n2168544802","n2168544805","n2168544807","n2168544809","n2168544811","n2168544813","n2168544815","n2168544817","n2168544819","n2168544821","n2168544823","n2168544825","n2168544800"]},"w134150800":{"id":"w134150800","tags":{"bridge":"yes","highway":"primary","name":"W Michigan Ave","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964972","n185964976"]},"w17966984":{"id":"w17966984","tags":{"highway":"residential","name":"Portage Avenue"},"nodes":["n185978375","n185963456","n2189153218","n185966937","n185978967","n185967422","n185982193","n185968100","n185982195","n185960195","n185980735","n185978787","n185966948","n185982196","n185982197","n185982198","n185982200","n2139795768","n185972155"]},"w203988294":{"id":"w203988294","tags":{"amenity":"shelter","area":"yes","building":"yes","shelter_type":"picnic_shelter"},"nodes":["n2140006409","n2140006411","n2140006413","n2140006415","n2140006409"]},"w203970912":{"id":"w203970912","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832711","n2139832712","n2139832713","n2139832714","n2139832711"]},"w203970119":{"id":"w203970119","tags":{"building":"yes"},"nodes":["n2139824713","n2139824705","n2139824683","n2139824689","n2139824713"]},"w203970114":{"id":"w203970114","tags":{"building":"yes"},"nodes":["n2139824735","n2139824750","n2139824745","n2139824732","n2139824735"]},"w208643142":{"id":"w208643142","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153254","n2189153255","n2189153256","n2189153257"]},"w206805253":{"id":"w206805253","tags":{"area":"yes","building":"yes"},"nodes":["n2168544848","n2168544849","n2168544850","n2168544851","n2168544852","n2168544853","n2168544854","n2168544855","n2168544848"]},"w143497377":{"id":"w143497377","tags":{"highway":"primary","name":"North Main Street","old_ref":"US 131","ref":"US 131 Business"},"nodes":["n185962625","n185978420","n185978419","n185978417","n185978415","n185978414","n185975735","n1475293254","n185978410","n185978406","n185970515","n185978402","n185978399","n185965399","n2189015992","n185961396","n185967917","n185978394","n185971631","n185960796","n185978392","n185974583","n185978390","n185971578","n185965289","n2189153215","n185978388","n185978383","n185978381","n185978379","n185978377","n185978375","n185964982"]},"w134150811":{"id":"w134150811","tags":{"highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964976","n2130304157","n1475284023","n2139832715","n185964980","n185964982"]},"w208643135":{"id":"w208643135","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153215","n2189153216","n2189153217","n2189153218"]},"w17967183":{"id":"w17967183","tags":{"highway":"residential","name":"West Street"},"nodes":["n1475284011","n185984011","n185984013","n185984015","n2189153246","n2189153250","n185965291","n185984017","n185971580","n185984020","n185974585","n185982163","n185975064","n185971632","n185984022","n185984024","n185967918"]},"w134150778":{"id":"w134150778","tags":{"bridge":"yes","highway":"residential","name":"Moore St"},"nodes":["n185988245","n1475283992","n185975911"]},"w206805248":{"id":"w206805248","tags":{"area":"yes","building":"yes"},"nodes":["n2168544790","n2168544791","n2168544792","n2168544793","n2168544795","n2168544797","n2168544798","n2168544799","n2168544802","n2168544801","n2168544790"]},"w203974058":{"id":"w203974058","tags":{"bridge":"yes","highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870374","n2139870375"]},"w203970902":{"id":"w203970902","tags":{"highway":"service"},"nodes":["n2139832678","n2139832691","n2139832680"]},"w203988296":{"id":"w203988296","tags":{"highway":"path"},"nodes":["n2139858967","n2140006421","n2139858935"]},"w206805251":{"id":"w206805251","tags":{"area":"yes","building":"yes"},"nodes":["n2168544830","n2168544831","n2168544832","n2168544833","n2168544834","n2168544835","n2168544836","n2168544837","n2168544830"]},"w203970906":{"id":"w203970906","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832693","n2139832694","n2139832696","n2139832697","n2139832698","n2139832693"]},"w203049598":{"id":"w203049598","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2130304162","n2130304163","n2130304164","n2130304165","n2130304162"]},"w203970911":{"id":"w203970911","tags":{"highway":"service"},"nodes":["n2139832709","n2139832714","n2139832713","n2139832710","n185988971"]},"w203970105":{"id":"w203970105","tags":{"building":"yes"},"nodes":["n2139824779","n2139824792","n2139824786","n2139824775","n2139824779"]},"w203988290":{"id":"w203988290","tags":{"highway":"footway"},"nodes":["n2140006403","n2140006407"]},"w203970900":{"id":"w203970900","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832653","n2139832663","n2139832665","n2139832667","n2139832669","n2139832671","n2139832673","n2139832675","n2139832677","n2139832653"]},"w209717048":{"id":"w209717048","tags":{"area":"yes","building":"yes"},"nodes":["n2199109755","n2199109756","n2199109757","n2199109758","n2199109759","n2199109760","n2199109755"]},"w208643141":{"id":"w208643141","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153247","n2189153248","n2189153249","n2189153250"]},"w203970903":{"id":"w203970903","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832682","n2139832688","n2139832684","n2139832678","n2139832686"]},"n354002527":{"id":"n354002527","loc":[-85.6236039,41.9458813],"tags":{"amenity":"school","name":"Barrows School"}},"n185963396":{"id":"n185963396","loc":[-85.627401,41.943496]},"n185963397":{"id":"n185963397","loc":[-85.627403,41.943625]},"n185965101":{"id":"n185965101","loc":[-85.626409,41.943215]},"n185971474":{"id":"n185971474","loc":[-85.624884,41.943508]},"n185971475":{"id":"n185971475","loc":[-85.625191,41.943509]},"n185971482":{"id":"n185971482","loc":[-85.624882,41.94382]},"n185983135":{"id":"n185983135","loc":[-85.624893,41.945616]},"n185983137":{"id":"n185983137","loc":[-85.624912,41.946524]},"n185988027":{"id":"n185988027","loc":[-85.622721,41.946535]},"n185963398":{"id":"n185963398","loc":[-85.6273993,41.9446899]},"n185983238":{"id":"n185983238","loc":[-85.6227157,41.9456321]},"n185980374":{"id":"n185980374","loc":[-85.6248856,41.9447242]},"n185980373":{"id":"n185980373","loc":[-85.6226744,41.9447371]},"n2196831342":{"id":"n2196831342","loc":[-85.6250924,41.945063]},"n2196831343":{"id":"n2196831343","loc":[-85.6252335,41.9450636]},"n2196831344":{"id":"n2196831344","loc":[-85.6252286,41.9448707]},"n2196831345":{"id":"n2196831345","loc":[-85.6250661,41.9448707]},"n2196831346":{"id":"n2196831346","loc":[-85.6250243,41.9449012]},"n2196831347":{"id":"n2196831347","loc":[-85.6250251,41.9449244]},"n2196831348":{"id":"n2196831348","loc":[-85.6250867,41.9449257]},"n2196831349":{"id":"n2196831349","loc":[-85.625349,41.9445058]},"n2196831350":{"id":"n2196831350","loc":[-85.6253471,41.9443882]},"n2196831351":{"id":"n2196831351","loc":[-85.6251516,41.94439]},"n2196831352":{"id":"n2196831352","loc":[-85.6251522,41.9444308]},"n2196831353":{"id":"n2196831353","loc":[-85.6251344,41.9444309]},"n2196831354":{"id":"n2196831354","loc":[-85.6251356,41.9445077]},"n2196831355":{"id":"n2196831355","loc":[-85.6232357,41.9463406]},"n2196831356":{"id":"n2196831356","loc":[-85.6232409,41.9460668]},"n2196831357":{"id":"n2196831357","loc":[-85.6232072,41.9460665]},"n2196831358":{"id":"n2196831358","loc":[-85.6232117,41.9458272]},"n2196831359":{"id":"n2196831359","loc":[-85.6229808,41.9458248]},"n2196831360":{"id":"n2196831360","loc":[-85.6229763,41.9460627]},"n2196831361":{"id":"n2196831361","loc":[-85.623006,41.946063]},"n2196831362":{"id":"n2196831362","loc":[-85.6230023,41.9462557]},"n2196831363":{"id":"n2196831363","loc":[-85.6230755,41.9462565]},"n2196831364":{"id":"n2196831364","loc":[-85.6230739,41.9463389]},"n185947349":{"id":"n185947349","loc":[-85.618327,41.945607]},"n185947359":{"id":"n185947359","loc":[-85.615453,41.945597]},"n185947378":{"id":"n185947378","loc":[-85.617231,41.945603]},"n185947474":{"id":"n185947474","loc":[-85.616136,41.945602]},"n185948972":{"id":"n185948972","loc":[-85.615273,41.945637]},"n185955019":{"id":"n185955019","loc":[-85.620172,41.945627]},"n185960682":{"id":"n185960682","loc":[-85.622759,41.951845]},"n185961369":{"id":"n185961369","loc":[-85.622758,41.947444]},"n185961371":{"id":"n185961371","loc":[-85.624908,41.947416]},"n185963392":{"id":"n185963392","loc":[-85.6270462,41.9409953]},"n185963393":{"id":"n185963393","loc":[-85.627295,41.941304]},"n185963394":{"id":"n185963394","loc":[-85.627352,41.94148]},"n185963395":{"id":"n185963395","loc":[-85.62737,41.942261]},"n185965099":{"id":"n185965099","loc":[-85.6264,41.942263]},"n185965108":{"id":"n185965108","loc":[-85.622769,41.949224]},"n185965110":{"id":"n185965110","loc":[-85.624937,41.949237]},"n185966295":{"id":"n185966295","loc":[-85.6299942,41.9446689]},"n185966342":{"id":"n185966342","loc":[-85.624873,41.942022]},"n185970222":{"id":"n185970222","loc":[-85.622761,41.948357]},"n185970224":{"id":"n185970224","loc":[-85.624924,41.9483338]},"n185971477":{"id":"n185971477","loc":[-85.620051,41.94383]},"n185971478":{"id":"n185971478","loc":[-85.621219,41.943801]},"n185971481":{"id":"n185971481","loc":[-85.621812,41.943807]},"n185973866":{"id":"n185973866","loc":[-85.627629,41.946498]},"n185974699":{"id":"n185974699","loc":[-85.6227688,41.950119]},"n185978800":{"id":"n185978800","loc":[-85.623953,41.954684]},"n185980372":{"id":"n185980372","loc":[-85.621459,41.944756]},"n185980378":{"id":"n185980378","loc":[-85.6286375,41.9446764]},"n185980380":{"id":"n185980380","loc":[-85.630139,41.944661]},"n185980382":{"id":"n185980382","loc":[-85.630298,41.944635]},"n185980384":{"id":"n185980384","loc":[-85.630759,41.94454]},"n185980386":{"id":"n185980386","loc":[-85.6312369,41.9444548]},"n185983133":{"id":"n185983133","loc":[-85.6248672,41.9415903]},"n185983139":{"id":"n185983139","loc":[-85.624951,41.950239]},"n185983140":{"id":"n185983140","loc":[-85.624934,41.950681]},"n185983141":{"id":"n185983141","loc":[-85.624813,41.950983]},"n185983143":{"id":"n185983143","loc":[-85.6246225,41.951591]},"n185983144":{"id":"n185983144","loc":[-85.623908,41.9539165]},"n185983145":{"id":"n185983145","loc":[-85.6238903,41.9540956]},"n185983146":{"id":"n185983146","loc":[-85.623898,41.95431]},"n185983236":{"id":"n185983236","loc":[-85.628481,41.945611]},"n185985914":{"id":"n185985914","loc":[-85.620072,41.946538]},"n185986812":{"id":"n185986812","loc":[-85.6227785,41.9510005]},"n185988028":{"id":"n185988028","loc":[-85.6281401,41.9469632]},"n185988030":{"id":"n185988030","loc":[-85.6282451,41.9470314]},"n185988032":{"id":"n185988032","loc":[-85.6283312,41.9470656]},"w17964989":{"id":"w17964989","tags":{"highway":"residential","name":"Middle St"},"nodes":["n185963392","n185963393","n185963394","n185963395","n185963396","n185963397","n185963398"]},"w17965158":{"id":"w17965158","tags":{"access":"private","highway":"service","name":"Battle St"},"nodes":["n185965099","n185965101"]},"w41074896":{"id":"w41074896","tags":{"highway":"secondary","name":"East Michigan Avenue","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185980372","n185980373","n185980374","n185963398","n185980378","n185966295","n185980380","n185980382","n185980384","n185980386"]},"w17965846":{"id":"w17965846","tags":{"highway":"residential","name":"2nd Ave"},"nodes":["n185971477","n185971478","n185971481","n185971482"]},"w209470306":{"id":"w209470306","tags":{"area":"yes","building":"yes"},"nodes":["n2196831349","n2196831350","n2196831351","n2196831352","n2196831353","n2196831354","n2196831349"]},"w17965845":{"id":"w17965845","tags":{"highway":"residential","name":"2nd Ave"},"nodes":["n185971474","n185971475","n185963396"]},"w209470307":{"id":"w209470307","tags":{"area":"yes","building":"yes"},"nodes":["n2196831355","n2196831356","n2196831357","n2196831358","n2196831359","n2196831360","n2196831361","n2196831362","n2196831363","n2196831364","n2196831355"]},"w17968192":{"id":"w17968192","tags":{"highway":"residential","name":"Washington St"},"nodes":["n185980373","n185983238","n185988027","n185961369","n185970222","n185965108","n185974699","n185986812","n185960682"]},"w17967603":{"id":"w17967603","tags":{"highway":"residential","name":"5th Ave"},"nodes":["n185985914","n185988027","n185983137","n185973866","n185988028","n185988030","n185988032"]},"w209470305":{"id":"w209470305","tags":{"area":"yes","building":"yes"},"nodes":["n2196831342","n2196831343","n2196831344","n2196831345","n2196831346","n2196831347","n2196831348","n2196831342"]},"w17967092":{"id":"w17967092","tags":{"highway":"residential","name":"Wood St"},"nodes":["n185983133","n185966342","n185971474","n185971482","n185980374","n185983135","n185983137","n185961371","n185970224","n185965110","n185983139","n185983140","n185983141","n185983143","n185983144","n185983145","n185983146","n185978800"]},"w17967107":{"id":"w17967107","tags":{"highway":"residential","name":"4th Ave"},"nodes":["n185983236","n185983135","n185983238","n185955019","n185947349","n185947378","n185947474","n185947359","n185948972"]},"n354030330":{"id":"n354030330","loc":[-85.6297222,41.9444444],"tags":{"leisure":"park","name":"Scouter Park"}},"n185966296":{"id":"n185966296","loc":[-85.629998,41.944078]},"n185966298":{"id":"n185966298","loc":[-85.629972,41.943927]},"n185966300":{"id":"n185966300","loc":[-85.629948,41.943783]},"n185980391":{"id":"n185980391","loc":[-85.6322992,41.9442766]},"n185980393":{"id":"n185980393","loc":[-85.6324925,41.9442136]},"n185980389":{"id":"n185980389","loc":[-85.6320272,41.9443281]},"n185980388":{"id":"n185980388","loc":[-85.6315778,41.9443959]},"n354031320":{"id":"n354031320","loc":[-85.6280556,41.9447222],"tags":{"amenity":"place_of_worship","name":"Riverside Church","religion":"christian"}},"n185987309":{"id":"n185987309","loc":[-85.6286497,41.9453531]},"n185987311":{"id":"n185987311","loc":[-85.6285942,41.9454805]},"n185988034":{"id":"n185988034","loc":[-85.6285815,41.9471692]},"n185988896":{"id":"n185988896","loc":[-85.6318433,41.9437929]},"n185977764":{"id":"n185977764","loc":[-85.6322988,41.943472]},"n1819848852":{"id":"n1819848852","loc":[-85.6315188,41.9448808]},"n1819848912":{"id":"n1819848912","loc":[-85.6284289,41.9472189]},"n1819848925":{"id":"n1819848925","loc":[-85.6314501,41.9451617]},"n1819848949":{"id":"n1819848949","loc":[-85.6309394,41.9455192]},"n1819848951":{"id":"n1819848951","loc":[-85.6290297,41.9457187]},"n1819848963":{"id":"n1819848963","loc":[-85.630521,41.9455591]},"n1819848981":{"id":"n1819848981","loc":[-85.6292936,41.9455846]},"n1819848989":{"id":"n1819848989","loc":[-85.6298451,41.9455431]},"n1819848998":{"id":"n1819848998","loc":[-85.6314973,41.9446254]},"n1819849018":{"id":"n1819849018","loc":[-85.6302807,41.9455527]},"n1819849043":{"id":"n1819849043","loc":[-85.6285533,41.9469731]},"n1819849087":{"id":"n1819849087","loc":[-85.6314501,41.9453532]},"n1819849090":{"id":"n1819849090","loc":[-85.628843,41.9461033]},"n1819849109":{"id":"n1819849109","loc":[-85.6311926,41.9454729]},"n1819849116":{"id":"n1819849116","loc":[-85.6288967,41.9459437]},"n1819849177":{"id":"n1819849177","loc":[-85.6287894,41.9464544]},"n1819858529":{"id":"n1819858529","loc":[-85.6325485,41.9445625]},"n2189112797":{"id":"n2189112797","loc":[-85.6275271,41.944555]},"n2189112798":{"id":"n2189112798","loc":[-85.6275196,41.9437258]},"n2189112799":{"id":"n2189112799","loc":[-85.6278937,41.943723]},"n2189112800":{"id":"n2189112800","loc":[-85.6278969,41.9439191]},"n2189112801":{"id":"n2189112801","loc":[-85.6279907,41.9439345]},"n2189112802":{"id":"n2189112802","loc":[-85.6280817,41.9439663]},"n2189112803":{"id":"n2189112803","loc":[-85.6281768,41.9440145]},"n2189112804":{"id":"n2189112804","loc":[-85.6281933,41.9440483]},"n2189112805":{"id":"n2189112805","loc":[-85.6281671,41.9440535]},"n2189112806":{"id":"n2189112806","loc":[-85.6281933,41.9440935]},"n2189112807":{"id":"n2189112807","loc":[-85.6282126,41.9441437]},"n2189112808":{"id":"n2189112808","loc":[-85.628214,41.9441991]},"n2189112809":{"id":"n2189112809","loc":[-85.6283298,41.944196]},"n2189112810":{"id":"n2189112810","loc":[-85.6283285,41.9442616]},"n2189112811":{"id":"n2189112811","loc":[-85.6281727,41.9442616]},"n2189112812":{"id":"n2189112812","loc":[-85.6281713,41.9442934]},"n2189112813":{"id":"n2189112813","loc":[-85.6280386,41.9442963]},"n2189112814":{"id":"n2189112814","loc":[-85.6280405,41.9443292]},"n2189112815":{"id":"n2189112815","loc":[-85.627829,41.9443349]},"n2189112816":{"id":"n2189112816","loc":[-85.6278347,41.9445495]},"n2189153271":{"id":"n2189153271","loc":[-85.6321053,41.9460342]},"n2189153272":{"id":"n2189153272","loc":[-85.632278,41.9457841]},"n2189153273":{"id":"n2189153273","loc":[-85.632823,41.9459936]},"n2189153274":{"id":"n2189153274","loc":[-85.6326845,41.9461963]},"n2189153275":{"id":"n2189153275","loc":[-85.6325664,41.9461507]},"n2189153276":{"id":"n2189153276","loc":[-85.6325323,41.946198]},"n2189153278":{"id":"n2189153278","loc":[-85.6321916,41.9459733]},"n2189153279":{"id":"n2189153279","loc":[-85.6322598,41.9458703]},"n2189153280":{"id":"n2189153280","loc":[-85.6327208,41.9460358]},"n2189153281":{"id":"n2189153281","loc":[-85.6326413,41.9461422]},"n185959079":{"id":"n185959079","loc":[-85.6293702,41.9474668]},"n185966301":{"id":"n185966301","loc":[-85.629692,41.943136]},"n185966304":{"id":"n185966304","loc":[-85.629565,41.942916]},"n185966308":{"id":"n185966308","loc":[-85.629501,41.942751]},"n185966315":{"id":"n185966315","loc":[-85.629472,41.942578]},"n185966319":{"id":"n185966319","loc":[-85.629444,41.942414]},"n185966321":{"id":"n185966321","loc":[-85.629391,41.94205]},"n185966323":{"id":"n185966323","loc":[-85.629369,41.941858]},"n185966327":{"id":"n185966327","loc":[-85.629297,41.941604]},"n185966331":{"id":"n185966331","loc":[-85.629233,41.941549]},"n185966336":{"id":"n185966336","loc":[-85.628504,41.941364]},"n185966338":{"id":"n185966338","loc":[-85.628275,41.941303]},"n185966340":{"id":"n185966340","loc":[-85.6269038,41.9410983]},"n185973867":{"id":"n185973867","loc":[-85.626843,41.947333]},"n185977762":{"id":"n185977762","loc":[-85.6318441,41.9429453]},"n1819848853":{"id":"n1819848853","loc":[-85.625854,41.9492218]},"n1819848861":{"id":"n1819848861","loc":[-85.6251459,41.9552376]},"n1819848874":{"id":"n1819848874","loc":[-85.6267445,41.9482961]},"n1819848882":{"id":"n1819848882","loc":[-85.6257209,41.9552396]},"n1819848883":{"id":"n1819848883","loc":[-85.624706,41.9523173]},"n1819848907":{"id":"n1819848907","loc":[-85.62609,41.9561471]},"n1819848908":{"id":"n1819848908","loc":[-85.6244013,41.9549284]},"n1819848911":{"id":"n1819848911","loc":[-85.6265578,41.9553672]},"n1819848923":{"id":"n1819848923","loc":[-85.6246802,41.9550959]},"n1819848936":{"id":"n1819848936","loc":[-85.6241588,41.9539291]},"n1819848940":{"id":"n1819848940","loc":[-85.62506,41.9511129]},"n1819848944":{"id":"n1819848944","loc":[-85.624942,41.9515912]},"n1819848950":{"id":"n1819848950","loc":[-85.6273989,41.9475461]},"n1819848957":{"id":"n1819848957","loc":[-85.627695,41.947404]},"n1819849009":{"id":"n1819849009","loc":[-85.6259248,41.94896]},"n1819849037":{"id":"n1819849037","loc":[-85.6257252,41.9502112]},"n1819849061":{"id":"n1819849061","loc":[-85.6270084,41.9479626]},"n1819849073":{"id":"n1819849073","loc":[-85.6243734,41.9534583]},"n1819849091":{"id":"n1819849091","loc":[-85.6241373,41.9543918]},"n1819849130":{"id":"n1819849130","loc":[-85.6282572,41.9473067]},"n1819849143":{"id":"n1819849143","loc":[-85.625281,41.9506596]},"n1819849153":{"id":"n1819849153","loc":[-85.6258647,41.9498043]},"n1819849168":{"id":"n1819849168","loc":[-85.6265084,41.9559317]},"n1819849173":{"id":"n1819849173","loc":[-85.6263325,41.9552156]},"n1819849175":{"id":"n1819849175","loc":[-85.6266372,41.9556764]},"n1819849178":{"id":"n1819849178","loc":[-85.6242232,41.9545993]},"n1819849181":{"id":"n1819849181","loc":[-85.6262187,41.9486712]},"n1819849188":{"id":"n1819849188","loc":[-85.6245558,41.9530434]},"n1819849190":{"id":"n1819849190","loc":[-85.6255982,41.9563017]},"n2168544738":{"id":"n2168544738","loc":[-85.6245707,41.9529711]},"w208643145":{"id":"w208643145","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153271","n2189153272","n2189153273","n2189153274","n2189153275","n2189153276","n2189153271"]},"w17967561":{"id":"w17967561","tags":{"highway":"residential","name":"Garden St"},"nodes":["n185980378","n185987309","n185987311","n185983236","n185973866"]},"w134150802":{"id":"w134150802","tags":{"bridge":"yes","highway":"secondary","name":"East Michigan Avenue","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185980386","n185980388"]},"w208639462":{"id":"w208639462","tags":{"area":"yes","building":"yes"},"nodes":["n2189112797","n2189112798","n2189112799","n2189112800","n2189112801","n2189112802","n2189112803","n2189112804","n2189112805","n2189112806","n2189112807","n2189112808","n2189112809","n2189112810","n2189112811","n2189112812","n2189112813","n2189112814","n2189112815","n2189112816","n2189112797"]},"w134150830":{"id":"w134150830","tags":{"bridge":"yes","highway":"secondary","name":"South Main Street","old_ref":"US 131","ref":"M 86"},"nodes":["n185977762","n185977764"]},"w134150801":{"id":"w134150801","tags":{"highway":"secondary","name":"South Main Street","old_ref":"US 131","ref":"M 86"},"nodes":["n185977764","n185964982"]},"w208643146":{"id":"w208643146","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153277","n2189153281","n2189153278","n2189153279","n2189153280","n2189153281"]},"w17966061":{"id":"w17966061","tags":{"highway":"residential","name":"John Glenn Ct"},"nodes":["n185973866","n185973867"]},"w134150772":{"id":"w134150772","tags":{"highway":"residential","name":"5th Ave"},"nodes":["n185988034","n185959079","n185988036","n185978967"]},"w134150836":{"id":"w134150836","tags":{"highway":"secondary","name":"East Michigan Avenue","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185980388","n1819858524","n185980389","n185980391","n185980393","n185964982"]},"w17967734":{"id":"w17967734","tags":{"highway":"residential","name":"Water Street"},"nodes":["n185988896","n185980391","n1819858529"]},"w17965305":{"id":"w17965305","tags":{"highway":"residential","name":"River Dr"},"nodes":["n185966295","n185966296","n185966298","n185966300","n185966301","n185966304","n185966308","n185966315","n185966319","n185966321","n185966323","n185966327","n185966331","n185966336","n185966338","n185963392","n185966340","n185966342"]},"w134150826":{"id":"w134150826","tags":{"bridge":"yes","highway":"residential","name":"5th Ave"},"nodes":["n185988032","n185988034"]},"w170848330":{"id":"w170848330","tags":{"name":"Portage River","waterway":"river"},"nodes":["n1819849190","n1819848907","n1819849168","n1819849175","n1819848911","n1819849173","n1819848882","n1819848861","n1819848923","n1819848908","n1819849178","n1819849091","n1819848936","n1819849073","n1819849188","n2168544738","n1819848883","n1819848944","n1819848940","n1819849143","n1819849037","n1819849153","n1819848853","n1819849009","n1819849181","n1819848874","n1819849061","n1819848950","n1819848957","n1819849130","n1819848912","n1819849043","n1819849177","n1819849090","n1819849116","n1819848951","n1819848981","n1819848989","n1819849018","n1819848963","n1819848949","n1819849109","n1819849087","n1819848925","n1819848852","n1819848998","n1819849057"]},"r270264":{"id":"r270264","tags":{"network":"US:MI","ref":"86","route":"road","state_id":"MI","type":"route","url":"http://en.wikipedia.org/wiki/M-86_%28Michigan_highway%29"},"members":[{"id":"w17737723","type":"way","role":""},{"id":"w17735949","type":"way","role":""},{"id":"w17740404","type":"way","role":""},{"id":"w17966273","type":"way","role":""},{"id":"w17964745","type":"way","role":""},{"id":"w151538068","type":"way","role":""},{"id":"w151538067","type":"way","role":""},{"id":"w17964960","type":"way","role":""},{"id":"w17966099","type":"way","role":""},{"id":"w17968009","type":"way","role":""},{"id":"w41259499","type":"way","role":""},{"id":"w151540401","type":"way","role":""},{"id":"w151540418","type":"way","role":""},{"id":"w17967997","type":"way","role":""},{"id":"w17966029","type":"way","role":""},{"id":"w17964801","type":"way","role":""},{"id":"w41259496","type":"way","role":""},{"id":"w151540399","type":"way","role":""},{"id":"w17968004","type":"way","role":""},{"id":"w17966462","type":"way","role":""},{"id":"w134150830","type":"way","role":""},{"id":"w134150801","type":"way","role":""},{"id":"w17732295","type":"way","role":""}]},"n185980093":{"id":"n185980093","loc":[-85.6271414,41.9407274]},"n185964330":{"id":"n185964330","loc":[-85.6235688,41.9399111]},"n185964328":{"id":"n185964328","loc":[-85.6235609,41.9391301]},"n185958034":{"id":"n185958034","loc":[-85.627102,41.939125]},"n185964331":{"id":"n185964331","loc":[-85.623571,41.940124]},"n185964329":{"id":"n185964329","loc":[-85.623562,41.9392411]},"n185972756":{"id":"n185972756","loc":[-85.623802,41.939102]},"n185972757":{"id":"n185972757","loc":[-85.623584,41.93913]},"n185975325":{"id":"n185975325","loc":[-85.624835,41.939318]},"n185975326":{"id":"n185975326","loc":[-85.624811,41.939435]},"n185975327":{"id":"n185975327","loc":[-85.624635,41.939703]},"n185975328":{"id":"n185975328","loc":[-85.624366,41.940055]},"n185975330":{"id":"n185975330","loc":[-85.624287,41.940113]},"n185975332":{"id":"n185975332","loc":[-85.624215,41.940134]},"n185980088":{"id":"n185980088","loc":[-85.627127,41.940086]},"n185988943":{"id":"n185988943","loc":[-85.622643,41.940128]},"n185988961":{"id":"n185988961","loc":[-85.627263,41.940082]},"n185990192":{"id":"n185990192","loc":[-85.622933,41.939224]},"n185990194":{"id":"n185990194","loc":[-85.621976,41.939203]},"n185991378":{"id":"n185991378","loc":[-85.622643,41.940635]},"n1475283999":{"id":"n1475283999","loc":[-85.6271165,41.9408429]},"n185980090":{"id":"n185980090","loc":[-85.6271315,41.9402001]},"n185958036":{"id":"n185958036","loc":[-85.6248366,41.9391615]},"n1819800188":{"id":"n1819800188","loc":[-85.6246947,41.9401644]},"n1819800199":{"id":"n1819800199","loc":[-85.6233686,41.9430896]},"n1819800204":{"id":"n1819800204","loc":[-85.6223236,41.9408587]},"n1819800213":{"id":"n1819800213","loc":[-85.6247526,41.9414138]},"n1819800216":{"id":"n1819800216","loc":[-85.6230961,41.9407151]},"n1819800218":{"id":"n1819800218","loc":[-85.621991,41.9429336]},"n1819800221":{"id":"n1819800221","loc":[-85.6246088,41.9424708]},"n1819800227":{"id":"n1819800227","loc":[-85.6241368,41.9403081]},"n1819800230":{"id":"n1819800230","loc":[-85.6226776,41.9431012]},"n1819800231":{"id":"n1819800231","loc":[-85.6243728,41.9401644]},"n1819800232":{"id":"n1819800232","loc":[-85.6249629,41.9408907]},"n1819800248":{"id":"n1819800248","loc":[-85.6238685,41.9405555]},"n1819800266":{"id":"n1819800266","loc":[-85.6246882,41.9418367]},"n1819800271":{"id":"n1819800271","loc":[-85.62492,41.9413695]},"n1819800294":{"id":"n1819800294","loc":[-85.6243556,41.9427465]},"n1819800304":{"id":"n1819800304","loc":[-85.6251453,41.94117]},"n1819800325":{"id":"n1819800325","loc":[-85.6248234,41.9405714]},"n1819800362":{"id":"n1819800362","loc":[-85.6239544,41.9429416]},"n1819800368":{"id":"n1819800368","loc":[-85.6243406,41.9402283]},"n1819800375":{"id":"n1819800375","loc":[-85.6226562,41.940755]},"n1819800377":{"id":"n1819800377","loc":[-85.6232033,41.9406512]},"n185945133":{"id":"n185945133","loc":[-85.623501,41.933232]},"n185945135":{"id":"n185945135","loc":[-85.624776,41.933205]},"n185945395":{"id":"n185945395","loc":[-85.624741,41.93019]},"n185952239":{"id":"n185952239","loc":[-85.615166,41.9382]},"n185954490":{"id":"n185954490","loc":[-85.624721,41.929278]},"n185957831":{"id":"n185957831","loc":[-85.625041,41.938662]},"n185958030":{"id":"n185958030","loc":[-85.629033,41.93913]},"n185958032":{"id":"n185958032","loc":[-85.628429,41.939143]},"n185958498":{"id":"n185958498","loc":[-85.621605,41.940143]},"n185961186":{"id":"n185961186","loc":[-85.624792,41.935214]},"n185963099":{"id":"n185963099","loc":[-85.6204461,41.9401485]},"n185963698":{"id":"n185963698","loc":[-85.6297342,41.9400783]},"n185964320":{"id":"n185964320","loc":[-85.623511,41.934216]},"n185964322":{"id":"n185964322","loc":[-85.6235312,41.9362084]},"n185964324":{"id":"n185964324","loc":[-85.6235488,41.9371726]},"n185964326":{"id":"n185964326","loc":[-85.6235512,41.9381718]},"n185967077":{"id":"n185967077","loc":[-85.617359,41.940161]},"n185967634":{"id":"n185967634","loc":[-85.6248039,41.9362012]},"n185970833":{"id":"n185970833","loc":[-85.6248019,41.9381684]},"n185972752":{"id":"n185972752","loc":[-85.624582,41.938848]},"n185972754":{"id":"n185972754","loc":[-85.6242,41.939008]},"n185973251":{"id":"n185973251","loc":[-85.602727,41.936012]},"n185974509":{"id":"n185974509","loc":[-85.62478,41.93217]},"n185975315":{"id":"n185975315","loc":[-85.624703,41.925597]},"n185975316":{"id":"n185975316","loc":[-85.624716,41.927359]},"n185975317":{"id":"n185975317","loc":[-85.62475,41.93119]},"n185975318":{"id":"n185975318","loc":[-85.624782,41.934218]},"n185975320":{"id":"n185975320","loc":[-85.6247949,41.9371708]},"n185977754":{"id":"n185977754","loc":[-85.6276,41.937412]},"n185980075":{"id":"n185980075","loc":[-85.627451,41.937549]},"n185980077":{"id":"n185980077","loc":[-85.627375,41.937618]},"n185980078":{"id":"n185980078","loc":[-85.627278,41.937728]},"n185980079":{"id":"n185980079","loc":[-85.627199,41.937842]},"n185980081":{"id":"n185980081","loc":[-85.627141,41.937981]},"n185980083":{"id":"n185980083","loc":[-85.627109,41.938153]},"n185980085":{"id":"n185980085","loc":[-85.627101,41.938699]},"n185981173":{"id":"n185981173","loc":[-85.61433,41.940167]},"n185987021":{"id":"n185987021","loc":[-85.628311,41.942261]},"n185988963":{"id":"n185988963","loc":[-85.628439,41.940086]},"n185990195":{"id":"n185990195","loc":[-85.621225,41.939143]},"n185990196":{"id":"n185990196","loc":[-85.620576,41.939033]},"n185990198":{"id":"n185990198","loc":[-85.619081,41.938804]},"n185990200":{"id":"n185990200","loc":[-85.617593,41.938552]},"n185990202":{"id":"n185990202","loc":[-85.617372,41.938535]},"n185990204":{"id":"n185990204","loc":[-85.616087,41.93832]},"n185990206":{"id":"n185990206","loc":[-85.615754,41.938289]},"n185990209":{"id":"n185990209","loc":[-85.615438,41.938251]},"n185990211":{"id":"n185990211","loc":[-85.613469,41.937867]},"n185990212":{"id":"n185990212","loc":[-85.610172,41.937298]},"n185990213":{"id":"n185990213","loc":[-85.605537,41.936497]},"n185990214":{"id":"n185990214","loc":[-85.604014,41.936234]},"n1819800180":{"id":"n1819800180","loc":[-85.588775,41.9455032]},"n1819800181":{"id":"n1819800181","loc":[-85.6074212,41.9408827]},"n1819800182":{"id":"n1819800182","loc":[-85.6131397,41.9427022]},"n1819800183":{"id":"n1819800183","loc":[-85.6171523,41.9416807]},"n1819800184":{"id":"n1819800184","loc":[-85.602465,41.9397415]},"n1819800185":{"id":"n1819800185","loc":[-85.6109296,41.9410583]},"n1819800186":{"id":"n1819800186","loc":[-85.6165729,41.9418004]},"n1819800189":{"id":"n1819800189","loc":[-85.5866293,41.9458224]},"n1819800191":{"id":"n1819800191","loc":[-85.5853311,41.9466603]},"n1819800201":{"id":"n1819800201","loc":[-85.6101142,41.9433406]},"n1819800202":{"id":"n1819800202","loc":[-85.600963,41.9428618]},"n1819800206":{"id":"n1819800206","loc":[-85.6154357,41.9427501]},"n1819800207":{"id":"n1819800207","loc":[-85.6040309,41.9414094]},"n1819800209":{"id":"n1819800209","loc":[-85.6113694,41.943189]},"n1819800211":{"id":"n1819800211","loc":[-85.618032,41.9416408]},"n1819800214":{"id":"n1819800214","loc":[-85.5959419,41.9402602]},"n1819800219":{"id":"n1819800219","loc":[-85.5972117,41.9420043]},"n1819800223":{"id":"n1819800223","loc":[-85.6117171,41.9430019]},"n1819800224":{"id":"n1819800224","loc":[-85.5977873,41.9395579]},"n1819800226":{"id":"n1819800226","loc":[-85.5917362,41.9432209]},"n1819800228":{"id":"n1819800228","loc":[-85.6055759,41.9419122]},"n1819800229":{"id":"n1819800229","loc":[-85.6203395,41.9425595]},"n1819800233":{"id":"n1819800233","loc":[-85.6107579,41.9433007]},"n1819800234":{"id":"n1819800234","loc":[-85.6039773,41.9412498]},"n1819800235":{"id":"n1819800235","loc":[-85.6000977,41.9412861]},"n1819800236":{"id":"n1819800236","loc":[-85.6026689,41.9407231]},"n1819800237":{"id":"n1819800237","loc":[-85.615161,41.9428662]},"n1819800238":{"id":"n1819800238","loc":[-85.5878953,41.9454314]},"n1819800239":{"id":"n1819800239","loc":[-85.6035267,41.941569]},"n1819800240":{"id":"n1819800240","loc":[-85.5929738,41.9450208]},"n1819800241":{"id":"n1819800241","loc":[-85.6186329,41.9416488]},"n1819800242":{"id":"n1819800242","loc":[-85.5881136,41.9483963]},"n1819800243":{"id":"n1819800243","loc":[-85.5909208,41.9466922]},"n1819800244":{"id":"n1819800244","loc":[-85.5997721,41.9394941]},"n1819800245":{"id":"n1819800245","loc":[-85.6202064,41.9425712]},"n1819800246":{"id":"n1819800246","loc":[-85.591071,41.9448808]},"n1819800247":{"id":"n1819800247","loc":[-85.5866078,41.9490622]},"n1819800250":{"id":"n1819800250","loc":[-85.602383,41.9420841]},"n1819800251":{"id":"n1819800251","loc":[-85.5957418,41.9426906]},"n1819800255":{"id":"n1819800255","loc":[-85.6157039,41.9416727]},"n1819800256":{"id":"n1819800256","loc":[-85.6080328,41.9410982]},"n1819800258":{"id":"n1819800258","loc":[-85.6192551,41.9414892]},"n1819800260":{"id":"n1819800260","loc":[-85.6104253,41.94117]},"n1819800261":{"id":"n1819800261","loc":[-85.6204503,41.9425709]},"n1819800263":{"id":"n1819800263","loc":[-85.5872194,41.9455431]},"n1819800264":{"id":"n1819800264","loc":[-85.616176,41.9418244]},"n1819800268":{"id":"n1819800268","loc":[-85.6120883,41.9426703]},"n1819800269":{"id":"n1819800269","loc":[-85.5894547,41.9474946]},"n1819800272":{"id":"n1819800272","loc":[-85.6209181,41.9425027]},"n1819800274":{"id":"n1819800274","loc":[-85.6122814,41.9412817]},"n1819800276":{"id":"n1819800276","loc":[-85.5895153,41.9452798]},"n1819800277":{"id":"n1819800277","loc":[-85.5884317,41.9455272]},"n1819800279":{"id":"n1819800279","loc":[-85.5884103,41.9480966]},"n1819800287":{"id":"n1819800287","loc":[-85.5904917,41.9453915]},"n1819800288":{"id":"n1819800288","loc":[-85.6212292,41.9412977]},"n1819800289":{"id":"n1819800289","loc":[-85.5954377,41.9406832]},"n1819800290":{"id":"n1819800290","loc":[-85.593721,41.9420957]},"n1819800291":{"id":"n1819800291","loc":[-85.6162832,41.9427102]},"n1819800292":{"id":"n1819800292","loc":[-85.605018,41.9401804]},"n1819800293":{"id":"n1819800293","loc":[-85.6086443,41.941146]},"n1819800296":{"id":"n1819800296","loc":[-85.6204675,41.9413775]},"n1819800297":{"id":"n1819800297","loc":[-85.612496,41.9424947]},"n1819800299":{"id":"n1819800299","loc":[-85.6065629,41.9423431]},"n1819800301":{"id":"n1819800301","loc":[-85.6036125,41.9398452]},"n1819800303":{"id":"n1819800303","loc":[-85.6114767,41.94117]},"n1819800306":{"id":"n1819800306","loc":[-85.592616,41.9428139]},"n1819800308":{"id":"n1819800308","loc":[-85.6023041,41.9419521]},"n1819800310":{"id":"n1819800310","loc":[-85.6218944,41.9411061]},"n1819800311":{"id":"n1819800311","loc":[-85.6097816,41.941162]},"n1819800312":{"id":"n1819800312","loc":[-85.5922549,41.9457869]},"n1819800313":{"id":"n1819800313","loc":[-85.5986027,41.9417206]},"n1819800314":{"id":"n1819800314","loc":[-85.5918687,41.946138]},"n1819800315":{"id":"n1819800315","loc":[-85.5872875,41.948883]},"n1819800316":{"id":"n1819800316","loc":[-85.594272,41.9436642]},"n1819800317":{"id":"n1819800317","loc":[-85.6176351,41.941577]},"n1819800318":{"id":"n1819800318","loc":[-85.6137834,41.9430853]},"n1819800319":{"id":"n1819800319","loc":[-85.6195383,41.942622],"tags":{"leisure":"slipway"}},"n1819800320":{"id":"n1819800320","loc":[-85.5971006,41.9398053]},"n1819800321":{"id":"n1819800321","loc":[-85.601714,41.9406752]},"n1819800322":{"id":"n1819800322","loc":[-85.5908028,41.9453117]},"n1819800323":{"id":"n1819800323","loc":[-85.6062732,41.9404597]},"n1819800324":{"id":"n1819800324","loc":[-85.62124,41.9425905]},"n1819800327":{"id":"n1819800327","loc":[-85.6008664,41.942766]},"n1819800328":{"id":"n1819800328","loc":[-85.6179355,41.9428538]},"n1819800330":{"id":"n1819800330","loc":[-85.6045566,41.9415131]},"n1819800331":{"id":"n1819800331","loc":[-85.5944935,41.9414653]},"n1819800333":{"id":"n1819800333","loc":[-85.6088911,41.943181]},"n1819800334":{"id":"n1819800334","loc":[-85.5946367,41.943369]},"n1819800336":{"id":"n1819800336","loc":[-85.6150494,41.9429656]},"n1819800343":{"id":"n1819800343","loc":[-85.6096099,41.9433326]},"n1819800345":{"id":"n1819800345","loc":[-85.5915216,41.9435401]},"n1819800347":{"id":"n1819800347","loc":[-85.607786,41.9428698]},"n1819800349":{"id":"n1819800349","loc":[-85.6187616,41.9426623]},"n1819800350":{"id":"n1819800350","loc":[-85.6012527,41.9426064]},"n1819800352":{"id":"n1819800352","loc":[-85.6214867,41.9428379]},"n1819800354":{"id":"n1819800354","loc":[-85.61338,41.94293]},"n1819800355":{"id":"n1819800355","loc":[-85.5923156,41.9428139]},"n1819800357":{"id":"n1819800357","loc":[-85.5901591,41.9453197]},"n1819800359":{"id":"n1819800359","loc":[-85.6033979,41.9408827]},"n1819800360":{"id":"n1819800360","loc":[-85.6186543,41.9414653]},"n1819800363":{"id":"n1819800363","loc":[-85.6128607,41.9425665]},"n1819800365":{"id":"n1819800365","loc":[-85.614234,41.9412977]},"n1819800367":{"id":"n1819800367","loc":[-85.6089662,41.9410902]},"n1819800369":{"id":"n1819800369","loc":[-85.6197379,41.9413695]},"n1819800370":{"id":"n1819800370","loc":[-85.6037348,41.941733]},"n1819800371":{"id":"n1819800371","loc":[-85.5993467,41.9415654]},"n1819800372":{"id":"n1819800372","loc":[-85.598077,41.94196]},"n1819800373":{"id":"n1819800373","loc":[-85.5984203,41.9394781]},"n1819800374":{"id":"n1819800374","loc":[-85.6013315,41.9427066]},"n1819800376":{"id":"n1819800376","loc":[-85.5934673,41.944167]},"n1819800378":{"id":"n1819800378","loc":[-85.6011062,41.9407753]},"n1819800379":{"id":"n1819800379","loc":[-85.6150602,41.9415131]},"n1819800380":{"id":"n1819800380","loc":[-85.6132148,41.9412338]},"n1819800381":{"id":"n1819800381","loc":[-85.5889038,41.9453835]},"n2139966621":{"id":"n2139966621","loc":[-85.6198719,41.9426184]},"n2139966622":{"id":"n2139966622","loc":[-85.6197551,41.9426123]},"n2139966623":{"id":"n2139966623","loc":[-85.6196467,41.9426279]},"n2139966624":{"id":"n2139966624","loc":[-85.6191519,41.9426221]},"n2139966625":{"id":"n2139966625","loc":[-85.6194153,41.9426256]},"n2139966626":{"id":"n2139966626","loc":[-85.6200497,41.9425812]},"n2139966629":{"id":"n2139966629","loc":[-85.6192123,41.9426229]},"n2203933101":{"id":"n2203933101","loc":[-85.6030009,41.9360592]},"w17967539":{"id":"w17967539","tags":{"highway":"residential","name":"1st Ave"},"nodes":["n185965099","n185963395","n185987021"]},"w17967751":{"id":"w17967751","tags":{"highway":"residential","name":"River St"},"nodes":["n185980088","n185988961","n185988963","n185963698"]},"w17965088":{"id":"w17965088","tags":{"highway":"residential","name":"9th St"},"nodes":["n185945133","n185964320","n185964322","n185964324","n185964326","n185964328","n185964329","n185964330","n185964331"]},"w17964467":{"id":"w17964467","tags":{"highway":"residential","name":"Mechanic St"},"nodes":["n185958030","n185958032","n185958034","n185958036"]},"w134150842":{"id":"w134150842","tags":{"bridge":"yes","highway":"residential","name":"6th St"},"nodes":["n185980090","n185980093"]},"w17966740":{"id":"w17966740","tags":{"highway":"residential","name":"6th St"},"nodes":["n185977754","n185980075","n185980077","n185980078","n185980079","n185980081","n185980083","n185980085","n185958034","n185980088","n185980090"]},"w170844765":{"id":"w170844765","tags":{"waterway":"dam"},"nodes":["n1819800304","n1819800232","n1819800325","n1819800188"]},"w17967745":{"id":"w17967745","tags":{"highway":"residential","name":"River St"},"nodes":["n185981173","n185967077","n185963099","n185958498","n185988943","n185964331","n185975332"]},"w17968113":{"id":"w17968113","tags":{"highway":"residential","name":"Green St"},"nodes":["n185988943","n185991378"]},"w134150833":{"id":"w134150833","tags":{"highway":"residential","name":"6th St"},"nodes":["n185980093","n1475283999","n185963392"]},"w17967935":{"id":"w17967935","tags":{"name":"Michigan Central Railroad","railway":"abandoned"},"nodes":["n185972757","n185990192","n185990194","n185990195","n185990196","n185990198","n185990200","n185990202","n185990204","n185990206","n185990209","n185952239","n185990211","n185990212","n185990213","n185990214","n2203933101","n185973251"]},"w17965993":{"id":"w17965993","tags":{"name":"Conrail Railroad","railway":"abandoned"},"nodes":["n185957831","n185972752","n185972754","n185972756","n185972757"]},"w17966211":{"id":"w17966211","tags":{"highway":"residential","name":"8th St"},"nodes":["n185975315","n185975316","n185954490","n185945395","n185975317","n185974509","n185945135","n185975318","n185961186","n185967634","n185975320","n185970833","n185958036","n185975325","n185975326","n185975327","n185975328","n185975330","n185975332"]},"w170844766":{"id":"w170844766","tags":{"waterway":"riverbank"},"nodes":["n1819800229","n1819800245","n2139966626","n2139966621","n2139966622","n2139966623","n1819800319","n2139966625","n2139966629","n2139966624","n1819800349","n1819800328","n1819800291","n1819800206","n1819800237","n1819800336","n1819800318","n1819800354","n1819800182","n1819800363","n1819800297","n1819800268","n1819800223","n1819800209","n1819800233","n1819800201","n1819800343","n1819800333","n1819800347","n1819800299","n1819800228","n1819800330","n1819800370","n1819800250","n1819800374","n1819800202","n1819800327","n1819800350","n1819800308","n1819800239","n1819800207","n1819800234","n1819800359","n1819800236","n1819800321","n1819800378","n1819800235","n1819800371","n1819800313","n1819800372","n1819800219","n1819800251","n1819800334","n1819800316","n1819800376","n1819800240","n1819800312","n1819800314","n1819800243","n1819800269","n1819800279","n1819800242","n1819800315","n1819800247","n1819800191","n1819800189","n1819800263","n1819800238","n1819800277","n1819800180","n1819800381","n1819800276","n1819800357","n1819800287","n1819800322","n1819800246","n1819800345","n1819800226","n1819800355","n1819800306","n1819800290","n1819800331","n1819800289","n1819800214","n1819800320","n1819800224","n1819800373","n1819800244","n1819800184","n1819800301","n1819800292","n1819800323","n1819800181","n1819800256","n1819800293","n1819800367","n1819800311","n1819800260","n1819800185","n1819800303","n1819800274","n1819800380","n1819800365","n1819800379","n1819800255","n1819800264","n1819800186","n1819800183","n1819800317","n1819800211","n1819800241","n1819800360","n1819800258","n1819800369","n1819800296","n1819800288","n1819800310","n1819800204","n1819800375","n1819800216","n1819800377","n1819800248","n1819800227","n1819800368","n1819800231","n1819800188","n1819800325","n1819800232","n1819800304","n1819800271","n1819800213","n1819800266","n1819800221","n1819800294","n1819800362","n1819800199","n1819800230","n1819800218","n1819800352","n1819800324","n1819800272","n1819800261","n1819800229"]},"n1875654132":{"id":"n1875654132","loc":[-85.6297439,41.939808]},"n1475293263":{"id":"n1475293263","loc":[-85.6296235,41.939922]},"n185947850":{"id":"n185947850","loc":[-85.631594,41.942613]},"n185952745":{"id":"n185952745","loc":[-85.630986,41.941786]},"n185972907":{"id":"n185972907","loc":[-85.631797,41.9420055]},"n185972911":{"id":"n185972911","loc":[-85.6309723,41.9411623]},"n185972915":{"id":"n185972915","loc":[-85.6295971,41.939267]},"n1475293223":{"id":"n1475293223","loc":[-85.6313962,41.9416114],"tags":{"railway":"level_crossing"}},"n1475293231":{"id":"n1475293231","loc":[-85.6318779,41.9415447]},"n1475293241":{"id":"n1475293241","loc":[-85.6304613,41.9405499]},"n1475293246":{"id":"n1475293246","loc":[-85.6297512,41.9395393],"tags":{"railway":"level_crossing"}},"n1475293251":{"id":"n1475293251","loc":[-85.6316633,41.9415128]},"n2139982404":{"id":"n2139982404","loc":[-85.6313283,41.9413748]},"n2139982407":{"id":"n2139982407","loc":[-85.6325545,41.9417787]},"n2139982408":{"id":"n2139982408","loc":[-85.6324499,41.9417693]},"n2139982409":{"id":"n2139982409","loc":[-85.6324753,41.9416444]},"n2139982410":{"id":"n2139982410","loc":[-85.6325814,41.9416538]},"n2139982411":{"id":"n2139982411","loc":[-85.6319572,41.9413515]},"n2139982412":{"id":"n2139982412","loc":[-85.6322925,41.941139]},"n2139982413":{"id":"n2139982413","loc":[-85.6323153,41.941153]},"n2139982414":{"id":"n2139982414","loc":[-85.6323019,41.9412617]},"n2139982415":{"id":"n2139982415","loc":[-85.6323703,41.9412667]},"n2139982416":{"id":"n2139982416","loc":[-85.6323555,41.941538]},"n2139982417":{"id":"n2139982417","loc":[-85.6321343,41.9416777]},"n2139982418":{"id":"n2139982418","loc":[-85.6319425,41.9416866]},"n2139982419":{"id":"n2139982419","loc":[-85.6320303,41.9416941]},"n2139982420":{"id":"n2139982420","loc":[-85.6321665,41.9415554]},"n2139982421":{"id":"n2139982421","loc":[-85.632412,41.9414164]},"n2139982422":{"id":"n2139982422","loc":[-85.6324801,41.9413421]},"n2139982423":{"id":"n2139982423","loc":[-85.6325023,41.9412585]},"n2139982424":{"id":"n2139982424","loc":[-85.6324532,41.9411607]},"n2139982425":{"id":"n2139982425","loc":[-85.6323502,41.941103]},"n2139982426":{"id":"n2139982426","loc":[-85.6322362,41.9411183]},"n2139982427":{"id":"n2139982427","loc":[-85.6318941,41.9413551]},"n2139982428":{"id":"n2139982428","loc":[-85.6318592,41.9414105]},"n2139982429":{"id":"n2139982429","loc":[-85.6320111,41.9415866]},"n2139982430":{"id":"n2139982430","loc":[-85.632446,41.9413792]},"n2139982431":{"id":"n2139982431","loc":[-85.6325112,41.941416]},"n2139982432":{"id":"n2139982432","loc":[-85.6325449,41.9416345]},"n2139982433":{"id":"n2139982433","loc":[-85.6326122,41.94164]},"n2139982434":{"id":"n2139982434","loc":[-85.6325954,41.9421966]},"n2139982435":{"id":"n2139982435","loc":[-85.6325655,41.9422411]},"n2139982436":{"id":"n2139982436","loc":[-85.632515,41.9422564]},"n2139982437":{"id":"n2139982437","loc":[-85.6324495,41.94223]},"n2139982438":{"id":"n2139982438","loc":[-85.6324009,41.9421743]},"n2139982439":{"id":"n2139982439","loc":[-85.6323915,41.9421145]},"n2139982440":{"id":"n2139982440","loc":[-85.6320287,41.9418585]},"n2139982441":{"id":"n2139982441","loc":[-85.6318285,41.9416387]},"n1475293258":{"id":"n1475293258","loc":[-85.6318289,41.9415077]},"n2168544754":{"id":"n2168544754","loc":[-85.6312814,41.9431198]},"n2168544755":{"id":"n2168544755","loc":[-85.6314212,41.9430646]},"n2168544756":{"id":"n2168544756","loc":[-85.6313387,41.942949]},"n2168544757":{"id":"n2168544757","loc":[-85.6311989,41.9430041]},"n2168544758":{"id":"n2168544758","loc":[-85.6311024,41.9429313]},"n2168544759":{"id":"n2168544759","loc":[-85.6310087,41.9428087]},"n2168544760":{"id":"n2168544760","loc":[-85.6313831,41.9426504]},"n2168544761":{"id":"n2168544761","loc":[-85.6314768,41.9427729]},"n2168544762":{"id":"n2168544762","loc":[-85.6306376,41.942809]},"n2168544763":{"id":"n2168544763","loc":[-85.6307378,41.9429427]},"n2168544764":{"id":"n2168544764","loc":[-85.630841,41.9428998]},"n2168544765":{"id":"n2168544765","loc":[-85.6307408,41.9427662]},"n2168544766":{"id":"n2168544766","loc":[-85.6305404,41.9426029]},"n2168544767":{"id":"n2168544767","loc":[-85.6304976,41.9426194]},"n2168544768":{"id":"n2168544768","loc":[-85.6305673,41.9427184]},"n2168544769":{"id":"n2168544769","loc":[-85.6306164,41.9426984]},"n2168544770":{"id":"n2168544770","loc":[-85.6306418,41.9427302]},"n2168544771":{"id":"n2168544771","loc":[-85.6306861,41.9427137]},"n2168544772":{"id":"n2168544772","loc":[-85.6307146,41.9427537]},"n2168544773":{"id":"n2168544773","loc":[-85.6308999,41.9426807]},"n2168544774":{"id":"n2168544774","loc":[-85.6308429,41.9426053]},"n2168544775":{"id":"n2168544775","loc":[-85.6308999,41.9425806]},"n2168544776":{"id":"n2168544776","loc":[-85.6308318,41.9424875]},"n2168544777":{"id":"n2168544777","loc":[-85.6307732,41.9425087]},"n2168544778":{"id":"n2168544778","loc":[-85.6307178,41.9424357]},"n2168544779":{"id":"n2168544779","loc":[-85.630485,41.942524]},"n2189099387":{"id":"n2189099387","loc":[-85.631203,41.9393371]},"n2189099404":{"id":"n2189099404","loc":[-85.6301963,41.9391363]},"n2189099405":{"id":"n2189099405","loc":[-85.6304447,41.9391352]},"n2189099406":{"id":"n2189099406","loc":[-85.6304463,41.9393391]},"n2189099407":{"id":"n2189099407","loc":[-85.6308435,41.9393373]},"n2189099408":{"id":"n2189099408","loc":[-85.6308418,41.9391251]},"n2189099409":{"id":"n2189099409","loc":[-85.6310929,41.939124]},"n2189099410":{"id":"n2189099410","loc":[-85.6310946,41.9393376]},"n2189112720":{"id":"n2189112720","loc":[-85.6314677,41.9412327]},"n2189112721":{"id":"n2189112721","loc":[-85.6313337,41.9411397]},"n2189112722":{"id":"n2189112722","loc":[-85.6320521,41.9405678]},"n2189112723":{"id":"n2189112723","loc":[-85.6321899,41.9406633]},"n2189112724":{"id":"n2189112724","loc":[-85.6313229,41.9408344]},"n2189112725":{"id":"n2189112725","loc":[-85.6311223,41.9410018]},"n2189112726":{"id":"n2189112726","loc":[-85.6313205,41.9411333]},"n2189112727":{"id":"n2189112727","loc":[-85.6315211,41.9409659]},"n2189112728":{"id":"n2189112728","loc":[-85.6311035,41.9402529]},"n2189112729":{"id":"n2189112729","loc":[-85.631226,41.9402107]},"n2189112730":{"id":"n2189112730","loc":[-85.6315966,41.9408051]},"n2189112731":{"id":"n2189112731","loc":[-85.6314741,41.9408473]},"n2189112732":{"id":"n2189112732","loc":[-85.6318114,41.940534]},"n2189112733":{"id":"n2189112733","loc":[-85.631588,41.94061]},"n2189112734":{"id":"n2189112734","loc":[-85.6314379,41.940366]},"n2189112735":{"id":"n2189112735","loc":[-85.6316613,41.94029]},"n2189112736":{"id":"n2189112736","loc":[-85.6306214,41.9400415]},"n2189112737":{"id":"n2189112737","loc":[-85.6304362,41.9397728]},"n2189112738":{"id":"n2189112738","loc":[-85.6305899,41.9397142]},"n2189112739":{"id":"n2189112739","loc":[-85.6307751,41.9399828]},"n2189112740":{"id":"n2189112740","loc":[-85.6304695,41.9401673]},"n2189112741":{"id":"n2189112741","loc":[-85.6301298,41.9396855]},"n2189112742":{"id":"n2189112742","loc":[-85.6303016,41.9396184]},"n2189112743":{"id":"n2189112743","loc":[-85.6306413,41.9401003]},"n2189112744":{"id":"n2189112744","loc":[-85.6309656,41.9406189]},"n2189112745":{"id":"n2189112745","loc":[-85.6308738,41.940493]},"n2189112746":{"id":"n2189112746","loc":[-85.6309333,41.940469]},"n2189112747":{"id":"n2189112747","loc":[-85.6307634,41.9402358]},"n2189112748":{"id":"n2189112748","loc":[-85.6308798,41.9401889]},"n2189112749":{"id":"n2189112749","loc":[-85.6311416,41.940548]},"n2189112750":{"id":"n2189112750","loc":[-85.6309577,41.9408708]},"n2189112751":{"id":"n2189112751","loc":[-85.630874,41.9407777]},"n2189112752":{"id":"n2189112752","loc":[-85.6310622,41.9406841]},"n2189112753":{"id":"n2189112753","loc":[-85.6311459,41.9407772]},"n2189112754":{"id":"n2189112754","loc":[-85.6320308,41.9405747]},"n2189112755":{"id":"n2189112755","loc":[-85.6317769,41.9401857]},"n2189112756":{"id":"n2189112756","loc":[-85.6313462,41.9401785]},"n2189112757":{"id":"n2189112757","loc":[-85.6313423,41.9401199]},"n2189112758":{"id":"n2189112758","loc":[-85.6318308,41.9401184]},"n2189112759":{"id":"n2189112759","loc":[-85.6321154,41.9405433]},"n2189112760":{"id":"n2189112760","loc":[-85.6310307,41.941683]},"n2189112761":{"id":"n2189112761","loc":[-85.6309808,41.9416078]},"n2189112762":{"id":"n2189112762","loc":[-85.6312094,41.9415156]},"n2189112763":{"id":"n2189112763","loc":[-85.6312636,41.9415865]},"n2189112764":{"id":"n2189112764","loc":[-85.6309384,41.94155]},"n2189112765":{"id":"n2189112765","loc":[-85.631156,41.9414619]},"n2189112766":{"id":"n2189112766","loc":[-85.6311968,41.94152]},"n2189112767":{"id":"n2189112767","loc":[-85.6308946,41.9414851]},"n2189112768":{"id":"n2189112768","loc":[-85.6308237,41.9413888]},"n2189112769":{"id":"n2189112769","loc":[-85.6309858,41.9413228]},"n2189112770":{"id":"n2189112770","loc":[-85.6310567,41.9414192]},"n2189112771":{"id":"n2189112771","loc":[-85.6307774,41.9413276]},"n2189112772":{"id":"n2189112772","loc":[-85.6309068,41.9412735]},"n2189112773":{"id":"n2189112773","loc":[-85.6309531,41.9413347]},"n2189112774":{"id":"n2189112774","loc":[-85.6307975,41.9412466]},"n2189112775":{"id":"n2189112775","loc":[-85.6307006,41.9411699]},"n2189112776":{"id":"n2189112776","loc":[-85.6308289,41.941113]},"n2189112777":{"id":"n2189112777","loc":[-85.6308997,41.9412012]},"n2189112778":{"id":"n2189112778","loc":[-85.630765,41.9412062]},"n2189112779":{"id":"n2189112779","loc":[-85.630739,41.9412177]},"n2189112780":{"id":"n2189112780","loc":[-85.6305822,41.9410391]},"n2189112781":{"id":"n2189112781","loc":[-85.6304117,41.9408177]},"n2189112782":{"id":"n2189112782","loc":[-85.6305086,41.9407769]},"n2189112783":{"id":"n2189112783","loc":[-85.6306779,41.9410044]},"n2189112784":{"id":"n2189112784","loc":[-85.6307734,41.9421663]},"n2189112785":{"id":"n2189112785","loc":[-85.630708,41.9420741]},"n2189112786":{"id":"n2189112786","loc":[-85.630863,41.9420133]},"n2189112787":{"id":"n2189112787","loc":[-85.6309285,41.9421055]},"n2189112788":{"id":"n2189112788","loc":[-85.6307014,41.9420263]},"n2189112789":{"id":"n2189112789","loc":[-85.6306648,41.941971]},"n2189112790":{"id":"n2189112790","loc":[-85.6307927,41.9419178]},"n2189112791":{"id":"n2189112791","loc":[-85.6308366,41.9419696]},"n2189112792":{"id":"n2189112792","loc":[-85.6307574,41.9418708]},"n2189112793":{"id":"n2189112793","loc":[-85.6306288,41.9419231]},"n2189112794":{"id":"n2189112794","loc":[-85.6306943,41.9417835]},"n2189112795":{"id":"n2189112795","loc":[-85.6305344,41.9418474]},"n2189112796":{"id":"n2189112796","loc":[-85.6305981,41.9419355]},"n2189123410":{"id":"n2189123410","loc":[-85.6315476,41.9393801]},"n2189123412":{"id":"n2189123412","loc":[-85.6315247,41.9399188]},"n2189123415":{"id":"n2189123415","loc":[-85.6316484,41.9400433]},"n185945138":{"id":"n185945138","loc":[-85.627073,41.93319]},"n185945142":{"id":"n185945142","loc":[-85.6296891,41.9331674]},"n185945401":{"id":"n185945401","loc":[-85.6269,41.930199]},"n185945405":{"id":"n185945405","loc":[-85.6296598,41.9301676]},"n185956891":{"id":"n185956891","loc":[-85.6251617,41.9255049]},"n185959979":{"id":"n185959979","loc":[-85.626333,41.928347]},"n185959983":{"id":"n185959983","loc":[-85.6296419,41.9283288]},"n185961192":{"id":"n185961192","loc":[-85.627053,41.9352031]},"n185961200":{"id":"n185961200","loc":[-85.6297088,41.9351902]},"n185963655":{"id":"n185963655","loc":[-85.6296112,41.9273948]},"n185963665":{"id":"n185963665","loc":[-85.626047,41.92737]},"n185963688":{"id":"n185963688","loc":[-85.6296503,41.9292199]},"n185963689":{"id":"n185963689","loc":[-85.6296694,41.931157]},"n185963690":{"id":"n185963690","loc":[-85.6296791,41.9321485]},"n185963691":{"id":"n185963691","loc":[-85.6296991,41.9341973]},"n185967638":{"id":"n185967638","loc":[-85.627089,41.9361884]},"n185972917":{"id":"n185972917","loc":[-85.6293759,41.9388605]},"n185972919":{"id":"n185972919","loc":[-85.6290337,41.9380234]},"n185972921":{"id":"n185972921","loc":[-85.628424,41.936212]},"n185972923":{"id":"n185972923","loc":[-85.628367,41.936029]},"n185974511":{"id":"n185974511","loc":[-85.627064,41.932169]},"n185977728":{"id":"n185977728","loc":[-85.625605,41.925842]},"n185977729":{"id":"n185977729","loc":[-85.625685,41.926163]},"n185977731":{"id":"n185977731","loc":[-85.6257845,41.9264872]},"n185977733":{"id":"n185977733","loc":[-85.62663,41.929251]},"n185977734":{"id":"n185977734","loc":[-85.627008,41.930642]},"n185977736":{"id":"n185977736","loc":[-85.627029,41.930775]},"n185977738":{"id":"n185977738","loc":[-85.627041,41.930946]},"n185977739":{"id":"n185977739","loc":[-85.6270379,41.9311746]},"n185977742":{"id":"n185977742","loc":[-85.627055,41.934206]},"n185977744":{"id":"n185977744","loc":[-85.627084,41.936804]},"n185977746":{"id":"n185977746","loc":[-85.627104,41.936914]},"n185977748":{"id":"n185977748","loc":[-85.627156,41.937026]},"n185977750":{"id":"n185977750","loc":[-85.6272406,41.9371672]},"n185977752":{"id":"n185977752","loc":[-85.627317,41.93723]},"n185977753":{"id":"n185977753","loc":[-85.627422,41.937312]},"n185977755":{"id":"n185977755","loc":[-85.627754,41.937504]},"n185977757":{"id":"n185977757","loc":[-85.627883,41.937623]},"n185977761":{"id":"n185977761","loc":[-85.627984,41.93773]},"n1475283996":{"id":"n1475283996","loc":[-85.6270514,41.9317122],"tags":{"railway":"level_crossing"}},"n1475284004":{"id":"n1475284004","loc":[-85.6278177,41.9342117],"tags":{"railway":"level_crossing"}},"n1475284014":{"id":"n1475284014","loc":[-85.6251877,41.9255913],"tags":{"railway":"level_crossing"}},"n1475284017":{"id":"n1475284017","loc":[-85.6274992,41.9331816],"tags":{"railway":"level_crossing"}},"n1475284021":{"id":"n1475284021","loc":[-85.6297108,41.9353939],"tags":{"railway":"level_crossing"}},"n1475284027":{"id":"n1475284027","loc":[-85.62811,41.935198],"tags":{"railway":"level_crossing"}},"n1475284035":{"id":"n1475284035","loc":[-85.626888,41.9311757],"tags":{"railway":"level_crossing"}},"n1475293245":{"id":"n1475293245","loc":[-85.6286047,41.9367881]},"n1875654302":{"id":"n1875654302","loc":[-85.6296367,41.927491]},"n2189099388":{"id":"n2189099388","loc":[-85.6312007,41.9389988]},"n2189099389":{"id":"n2189099389","loc":[-85.6311003,41.9389992]},"n2189099390":{"id":"n2189099390","loc":[-85.6310988,41.9387847]},"n2189099391":{"id":"n2189099391","loc":[-85.6312165,41.9387843]},"n2189099392":{"id":"n2189099392","loc":[-85.6312152,41.9385857]},"n2189099393":{"id":"n2189099393","loc":[-85.6310877,41.9385862]},"n2189099394":{"id":"n2189099394","loc":[-85.6310858,41.9383161]},"n2189099395":{"id":"n2189099395","loc":[-85.6302002,41.9383196]},"n2189099396":{"id":"n2189099396","loc":[-85.6302011,41.9384472]},"n2189099397":{"id":"n2189099397","loc":[-85.6301018,41.9384476]},"n2189099398":{"id":"n2189099398","loc":[-85.6301025,41.9385419]},"n2189099399":{"id":"n2189099399","loc":[-85.6299275,41.9385427]},"n2189099400":{"id":"n2189099400","loc":[-85.62993,41.9388653]},"n2189099401":{"id":"n2189099401","loc":[-85.630107,41.9388645]},"n2189099402":{"id":"n2189099402","loc":[-85.6301079,41.9389908]},"n2189099403":{"id":"n2189099403","loc":[-85.6301951,41.9389904]},"n2189123382":{"id":"n2189123382","loc":[-85.6336279,41.9354365]},"n2189123384":{"id":"n2189123384","loc":[-85.6328492,41.9355177]},"n2189123387":{"id":"n2189123387","loc":[-85.6323762,41.9357396]},"n2189123388":{"id":"n2189123388","loc":[-85.6315174,41.9358966]},"n2189123389":{"id":"n2189123389","loc":[-85.6304331,41.936124]},"n2189123390":{"id":"n2189123390","loc":[-85.6302075,41.9364271]},"n2189123391":{"id":"n2189123391","loc":[-85.6303458,41.9367953]},"n2189123392":{"id":"n2189123392","loc":[-85.6299601,41.9369739]},"n2189123393":{"id":"n2189123393","loc":[-85.6299164,41.9374882]},"n2189123394":{"id":"n2189123394","loc":[-85.6299455,41.9378022]},"n2189123395":{"id":"n2189123395","loc":[-85.6299771,41.9379053]},"n2189123396":{"id":"n2189123396","loc":[-85.6301597,41.9379091]},"n2189123397":{"id":"n2189123397","loc":[-85.6308042,41.9377913]},"n2189123398":{"id":"n2189123398","loc":[-85.6316885,41.9378082]},"n2189123399":{"id":"n2189123399","loc":[-85.6316848,41.9380079]},"n2189123400":{"id":"n2189123400","loc":[-85.6318449,41.9381161]},"n2189123401":{"id":"n2189123401","loc":[-85.6320705,41.9381811]},"n2189123402":{"id":"n2189123402","loc":[-85.6321433,41.9383706]},"n2189123404":{"id":"n2189123404","loc":[-85.632056,41.9384355]},"n2189123406":{"id":"n2189123406","loc":[-85.6317867,41.9384572]},"n2189123409":{"id":"n2189123409","loc":[-85.6316572,41.9387281]},"n2189123417":{"id":"n2189123417","loc":[-85.6315946,41.93775]},"n2189123419":{"id":"n2189123419","loc":[-85.6302641,41.9378393]},"w208640158":{"id":"w208640158","tags":{"area":"yes","natural":"wetland"},"nodes":["n2189123379","n2189123382","n2189123384","n2189123387","n2189123388","n2189123389","n2189123390","n2189123391","n2189123392","n2189123393","n2189123394","n2189123395","n2189123396","n2189123419","n2189123397","n2189123417","n2189123398","n2189123399","n2189123400","n2189123401","n2189123402","n2189123404","n2189123406","n2189123409","n2189123410","n2189123412","n2189123415","n1819805722","n1819805861","n1819805887","n1819805760","n1819805641","n1819805632","n2189123379"]},"w134150787":{"id":"w134150787","tags":{"name":"Conrail Railroad","railway":"rail"},"nodes":["n185972905","n185972907","n1475293223","n185972911","n1475293241","n1475293246","n185972915","n185972917","n185972919","n1475293245","n185972921","n185972923","n1475284027","n1475284004","n1475284017","n1475283996","n1475284035","n1475284014","n185956891"]},"w208639443":{"id":"w208639443","tags":{"area":"yes","building":"yes"},"nodes":["n2189112720","n2189112721","n2189112722","n2189112723","n2189112720"]},"w17966462":{"id":"w17966462","tags":{"highway":"secondary","name":"South Main Street","old_ref":"US 131","ref":"M 86"},"nodes":["n185977728","n185977729","n185977731","n185963665","n185959979","n185977733","n185945401","n185977734","n185977736","n185977738","n185977739","n1475283996","n185974511","n185945138","n185977742","n185961192","n185967638","n185977744","n185977746","n185977748","n185977750","n185977752","n185977753","n185977754","n185977755","n185977757","n185977761","n185958030","n1475293263","n185963698","n185952745","n185947850","n185977762"]},"w203985741":{"id":"w203985741","tags":{"area":"yes","leisure":"park","name":"Conservation Park"},"nodes":["n2139982404","n2139982405","n2139982399","n2139982400","n1819805770","n2139982402","n2139982403","n2139982401","n1819805780","n1819805834","n2139982406","n2139982404"]},"w17963676":{"id":"w17963676","tags":{"highway":"service"},"nodes":["n1475293258","n2139982428","n2139982427","n2139982426","n2139982425","n2139982424","n2139982423","n2139982422","n2139982430","n2139982421","n2139982420","n2139982429","n1475293231","n1475293258","n1475293251","n1475293223","n185952745"]},"w203985745":{"id":"w203985745","tags":{"highway":"footway"},"nodes":["n2139982430","n2139982431","n2139982432","n2139982433","n2139982434","n2139982435","n2139982436","n2139982437","n2139982438","n2139982439","n2139982440","n2139982441","n1475293231"]},"w208639451":{"id":"w208639451","tags":{"area":"yes","building":"yes"},"nodes":["n2189112754","n2189112755","n2189112756","n2189112757","n2189112758","n2189112759","n2189112754"]},"w208639452":{"id":"w208639452","tags":{"area":"yes","building":"yes"},"nodes":["n2189112760","n2189112761","n2189112766","n2189112762","n2189112763","n2189112760"]},"w206805244":{"id":"w206805244","tags":{"area":"yes","building":"yes"},"nodes":["n2168544766","n2168544767","n2168544768","n2168544769","n2168544770","n2168544771","n2168544772","n2168544773","n2168544774","n2168544775","n2168544776","n2168544777","n2168544778","n2168544779","n2168544766"]},"w208639444":{"id":"w208639444","tags":{"area":"yes","building":"yes"},"nodes":["n2189112724","n2189112725","n2189112726","n2189112727","n2189112724"]},"w208639450":{"id":"w208639450","tags":{"area":"yes","building":"yes"},"nodes":["n2189112750","n2189112751","n2189112752","n2189112753","n2189112750"]},"w208639448":{"id":"w208639448","tags":{"area":"yes","building":"yes"},"nodes":["n2189112740","n2189112741","n2189112742","n2189112743","n2189112740"]},"w208637859":{"id":"w208637859","tags":{"area":"yes","building":"yes"},"nodes":["n2189099387","n2189099388","n2189099389","n2189099390","n2189099391","n2189099392","n2189099393","n2189099394","n2189099395","n2189099396","n2189099397","n2189099398","n2189099399","n2189099400","n2189099401","n2189099402","n2189099403","n2189099404","n2189099405","n2189099406","n2189099407","n2189099408","n2189099409","n2189099410","n2189099387"]},"w208639453":{"id":"w208639453","tags":{"area":"yes","building":"yes"},"nodes":["n2189112764","n2189112765","n2189112766","n2189112761","n2189112764"]},"w208639456":{"id":"w208639456","tags":{"area":"yes","building":"yes"},"nodes":["n2189112774","n2189112778","n2189112779","n2189112775","n2189112776","n2189112777","n2189112774"]},"w208639445":{"id":"w208639445","tags":{"area":"yes","building":"yes"},"nodes":["n2189112728","n2189112729","n2189112730","n2189112731","n2189112728"]},"w17967776":{"id":"w17967776","tags":{"highway":"residential","name":"5th St"},"nodes":["n185958032","n185988963"]},"w208639461":{"id":"w208639461","tags":{"area":"yes","building":"yes"},"nodes":["n2189112792","n2189112794","n2189112795","n2189112796","n2189112793","n2189112792"]},"w206805241":{"id":"w206805241","tags":{"area":"yes","building":"yes"},"nodes":["n2168544754","n2168544755","n2168544756","n2168544757","n2168544754"]},"w208639449":{"id":"w208639449","tags":{"area":"yes","building":"yes"},"nodes":["n2189112744","n2189112745","n2189112746","n2189112747","n2189112748","n2189112749","n2189112744"]},"w208639455":{"id":"w208639455","tags":{"area":"yes","building":"yes"},"nodes":["n2189112771","n2189112772","n2189112773","n2189112768","n2189112771"]},"w208639457":{"id":"w208639457","tags":{"area":"yes","building":"yes"},"nodes":["n2189112780","n2189112781","n2189112782","n2189112783","n2189112780"]},"w208639446":{"id":"w208639446","tags":{"area":"yes","building":"yes"},"nodes":["n2189112732","n2189112733","n2189112734","n2189112735","n2189112732"]},"w208639454":{"id":"w208639454","tags":{"area":"yes","building":"yes"},"nodes":["n2189112767","n2189112768","n2189112773","n2189112769","n2189112770","n2189112767"]},"w203985743":{"id":"w203985743","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139982411","n2139982412","n2139982413","n2139982414","n2139982415","n2139982416","n2139982417","n2139982419","n2139982418","n2139982411"]},"w17965023":{"id":"w17965023","tags":{"highway":"residential","name":"4th St"},"nodes":["n185963655","n1875654302","n185959983","n185963688","n185945405","n185963689","n185963690","n185945142","n185963691","n185961200","n1475284021","n1475293246","n1875654132","n1475293263"]},"w206805242":{"id":"w206805242","tags":{"area":"yes","building":"yes"},"nodes":["n2168544758","n2168544759","n2168544760","n2168544761","n2168544758"]},"w208639460":{"id":"w208639460","tags":{"area":"yes","building":"yes"},"nodes":["n2189112792","n2189112793","n2189112789","n2189112790","n2189112792"]},"w208639447":{"id":"w208639447","tags":{"area":"yes","building":"yes"},"nodes":["n2189112736","n2189112737","n2189112738","n2189112739","n2189112736"]},"w208639458":{"id":"w208639458","tags":{"area":"yes","building":"yes"},"nodes":["n2189112784","n2189112785","n2189112786","n2189112787","n2189112784"]},"w203985744":{"id":"w203985744","tags":{"highway":"service"},"nodes":["n2139982425","n2139982400"]},"w208639459":{"id":"w208639459","tags":{"area":"yes","building":"yes"},"nodes":["n2189112788","n2189112789","n2189112790","n2189112791","n2189112788"]},"w203985742":{"id":"w203985742","tags":{"amenity":"shelter","area":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139982407","n2139982408","n2139982409","n2139982410","n2139982407"]},"w206805243":{"id":"w206805243","tags":{"area":"yes","building":"yes"},"nodes":["n2168544762","n2168544763","n2168544764","n2168544765","n2168544762"]},"n185959081":{"id":"n185959081","loc":[-85.628469,41.948674]},"n185967427":{"id":"n185967427","loc":[-85.632054,41.951174]},"n185967424":{"id":"n185967424","loc":[-85.6320391,41.9499109]},"n185968101":{"id":"n185968101","loc":[-85.6308395,41.9511969]},"n185960792":{"id":"n185960792","loc":[-85.632074,41.953707]},"n185961389":{"id":"n185961389","loc":[-85.630935,41.959037]},"n185961391":{"id":"n185961391","loc":[-85.632169,41.959025]},"n185965395":{"id":"n185965395","loc":[-85.63216,41.959859]},"n185966953":{"id":"n185966953","loc":[-85.630894,41.957428]},"n185966955":{"id":"n185966955","loc":[-85.632122,41.957427]},"n185967430":{"id":"n185967430","loc":[-85.632077,41.952453]},"n185967432":{"id":"n185967432","loc":[-85.632095,41.954685]},"n185967434":{"id":"n185967434","loc":[-85.632121,41.955914]},"n185967436":{"id":"n185967436","loc":[-85.632128,41.9583]},"n185967438":{"id":"n185967438","loc":[-85.632187,41.960681]},"n185967440":{"id":"n185967440","loc":[-85.632182,41.961493]},"n185968102":{"id":"n185968102","loc":[-85.630855,41.952452]},"n185968104":{"id":"n185968104","loc":[-85.630887,41.953714]},"n185968106":{"id":"n185968106","loc":[-85.630883,41.954692]},"n185968108":{"id":"n185968108","loc":[-85.630904,41.955913]},"n185968110":{"id":"n185968110","loc":[-85.630904,41.958058]},"n185968112":{"id":"n185968112","loc":[-85.630952,41.960667]},"n185968114":{"id":"n185968114","loc":[-85.630972,41.961495]},"n185968116":{"id":"n185968116","loc":[-85.630962,41.961967]},"n185978969":{"id":"n185978969","loc":[-85.633214,41.948618]},"n185985812":{"id":"n185985812","loc":[-85.633274,41.951159]},"n185986155":{"id":"n185986155","loc":[-85.633258,41.949893]},"n2208608826":{"id":"n2208608826","loc":[-85.6339222,41.9486225]},"w17964531":{"id":"w17964531","tags":{"highway":"residential","name":"Willow Dr"},"nodes":["n185959079","n185959081"]},"w17967386":{"id":"w17967386","tags":{"highway":"residential","name":"East Armitage Street"},"nodes":["n185982195","n185968101","n185967427","n185985812","n185974583"]},"w17965502":{"id":"w17965502","tags":{"highway":"residential","name":"Elm Street"},"nodes":["n185968100","n185968101","n185968102","n185968104","n185968106","n185968108","n185966953","n185968110","n185961389","n185968112","n185968114","n185968116"]},"w17967844":{"id":"w17967844","tags":{"highway":"residential","name":"East Bennett Street"},"nodes":["n185982193","n185967424","n185986155","n185978390"]},"w17966581":{"id":"w17966581","tags":{"highway":"residential","name":"E Kelsey St"},"nodes":["n185978967","n185978969","n2208608826","n185971578"]},"w17965402":{"id":"w17965402","tags":{"highway":"residential","name":"Walnut Street"},"nodes":["n185967422","n185967424","n185967427","n185967430","n185960792","n185967432","n185967434","n185966955","n185967436","n185961391","n185965395","n185967438","n185967440"]},"n2199093506":{"id":"n2199093506","loc":[-85.6251879,41.9478322]},"n2199093505":{"id":"n2199093505","loc":[-85.6252076,41.9477749]},"n2199093504":{"id":"n2199093504","loc":[-85.6252289,41.9477602]},"n2199093503":{"id":"n2199093503","loc":[-85.625201,41.9477492]},"n2199093502":{"id":"n2199093502","loc":[-85.6251682,41.9477066]},"n2199093501":{"id":"n2199093501","loc":[-85.6251715,41.947609]},"n2199093500":{"id":"n2199093500","loc":[-85.6252125,41.9475639]},"n2199093499":{"id":"n2199093499","loc":[-85.6252896,41.9475602]},"n2199093498":{"id":"n2199093498","loc":[-85.6253027,41.9475334]},"n2199093497":{"id":"n2199093497","loc":[-85.6253437,41.9474822]},"n2199093496":{"id":"n2199093496","loc":[-85.6254421,41.9474675]},"n2199093495":{"id":"n2199093495","loc":[-85.6256503,41.9474944]},"n2199093494":{"id":"n2199093494","loc":[-85.6257257,41.9476127]},"n2199093493":{"id":"n2199093493","loc":[-85.6257028,41.9477285]},"n2199093492":{"id":"n2199093492","loc":[-85.6255339,41.9478102]},"n2199093491":{"id":"n2199093491","loc":[-85.6253912,41.9478224]},"n2199093490":{"id":"n2199093490","loc":[-85.6253043,41.947859]},"n2199093489":{"id":"n2199093489","loc":[-85.6252027,41.9478846]},"n2199093458":{"id":"n2199093458","loc":[-85.6246876,41.9486617]},"n2199093457":{"id":"n2199093457","loc":[-85.6243127,41.9486583]},"n2199093456":{"id":"n2199093456","loc":[-85.624306,41.9490569]},"n2199093455":{"id":"n2199093455","loc":[-85.624681,41.9490603]},"n2199093514":{"id":"n2199093514","loc":[-85.6236228,41.9496059]},"n2199093513":{"id":"n2199093513","loc":[-85.6236231,41.9496997]},"n2199093512":{"id":"n2199093512","loc":[-85.623357,41.9497002]},"n2199093511":{"id":"n2199093511","loc":[-85.6233567,41.9496136]},"n2199093508":{"id":"n2199093508","loc":[-85.6239735,41.9494287]},"n2199093507":{"id":"n2199093507","loc":[-85.6239741,41.9496052]},"n2199093488":{"id":"n2199093488","loc":[-85.624497,41.9512286]},"n2199093487":{"id":"n2199093487","loc":[-85.6244966,41.9511259]},"n2199093486":{"id":"n2199093486","loc":[-85.6243151,41.9511263]},"n2199093485":{"id":"n2199093485","loc":[-85.6243154,41.951229]},"n2199093484":{"id":"n2199093484","loc":[-85.6241205,41.9508665]},"n2199093483":{"id":"n2199093483","loc":[-85.624115,41.9505249]},"n2199093482":{"id":"n2199093482","loc":[-85.6243149,41.9505231]},"n2199093481":{"id":"n2199093481","loc":[-85.6243203,41.9508648]},"n2199093480":{"id":"n2199093480","loc":[-85.624393,41.9508668]},"n2199093479":{"id":"n2199093479","loc":[-85.6243904,41.9505956]},"n2199093478":{"id":"n2199093478","loc":[-85.6246727,41.950594]},"n2199093477":{"id":"n2199093477","loc":[-85.624675,41.9508203]},"n2199093476":{"id":"n2199093476","loc":[-85.6245097,41.9508212]},"n2199093475":{"id":"n2199093475","loc":[-85.6245101,41.9508662]},"n2199093474":{"id":"n2199093474","loc":[-85.6241008,41.9493459]},"n2199093473":{"id":"n2199093473","loc":[-85.6242442,41.9493459]},"n2199093472":{"id":"n2199093472","loc":[-85.6242442,41.9493681]},"n2199093471":{"id":"n2199093471","loc":[-85.6243397,41.9493681]},"n2199093470":{"id":"n2199093470","loc":[-85.6243417,41.9493511]},"n2199093469":{"id":"n2199093469","loc":[-85.6247251,41.9493485]},"n2199093468":{"id":"n2199093468","loc":[-85.6247548,41.9504949]},"n2199093467":{"id":"n2199093467","loc":[-85.6241214,41.9505017]},"n2199093466":{"id":"n2199093466","loc":[-85.6254398,41.950174]},"n2199093465":{"id":"n2199093465","loc":[-85.6254412,41.9499872]},"n2199093464":{"id":"n2199093464","loc":[-85.6255363,41.9499876]},"n2199093463":{"id":"n2199093463","loc":[-85.6255374,41.9498439]},"n2199093462":{"id":"n2199093462","loc":[-85.6255638,41.949844]},"n2199093461":{"id":"n2199093461","loc":[-85.6255652,41.9496672]},"n2199093460":{"id":"n2199093460","loc":[-85.6251823,41.9496656]},"n2199093459":{"id":"n2199093459","loc":[-85.6251785,41.9501729]},"n2199093510":{"id":"n2199093510","loc":[-85.6229922,41.9496143]},"n2199093509":{"id":"n2199093509","loc":[-85.6229915,41.9494306]},"n185948903":{"id":"n185948903","loc":[-85.616514,41.947449]},"n185955120":{"id":"n185955120","loc":[-85.620103,41.951]},"n185955143":{"id":"n185955143","loc":[-85.619784,41.94746]},"n185960124":{"id":"n185960124","loc":[-85.615238,41.947468]},"n185961362":{"id":"n185961362","loc":[-85.617437,41.947451]},"n185961364":{"id":"n185961364","loc":[-85.61861,41.947456]},"n185961367":{"id":"n185961367","loc":[-85.620088,41.947458]},"n185965105":{"id":"n185965105","loc":[-85.620087,41.94924]},"n185970220":{"id":"n185970220","loc":[-85.62156,41.948333]},"n185974697":{"id":"n185974697","loc":[-85.6201059,41.950132]},"n2138420778":{"id":"n2138420778","loc":[-85.616948,41.9474499]},"w17967535":{"id":"w17967535","tags":{"highway":"residential","name":"10th Ave"},"nodes":["n185955120","n185986812","n185983141"]},"w209716130":{"id":"w209716130","tags":{"area":"yes","building":"yes"},"nodes":["n2199093485","n2199093486","n2199093487","n2199093488","n2199093485"]},"w17964788":{"id":"w17964788","tags":{"highway":"residential","name":"6th Ave"},"nodes":["n185960124","n185948903","n2138420778","n185961362","n185961364","n185955143","n185961367","n185961369","n185961371"]},"w17965159":{"id":"w17965159","tags":{"highway":"residential","name":"8th Ave"},"nodes":["n185965105","n185965108","n185965110"]},"w209716125":{"id":"w209716125","tags":{"area":"yes","building":"yes"},"nodes":["n2199093459","n2199093460","n2199093461","n2199093462","n2199093463","n2199093464","n2199093465","n2199093466","n2199093459"]},"w17965699":{"id":"w17965699","tags":{"highway":"residential","name":"7th Ave"},"nodes":["n185970220","n185970222","n185970224"]},"w209716132":{"id":"w209716132","tags":{"area":"yes","building":"yes"},"nodes":["n2199093507","n2199093508","n2199093509","n2199093510","n2199093511","n2199093512","n2199093513","n2199093514","n2199093507"]},"w17966129":{"id":"w17966129","tags":{"highway":"residential","name":"9th Ave"},"nodes":["n185974697","n185974699"]},"w209716127":{"id":"w209716127","tags":{"area":"yes","building":"yes"},"nodes":["n2199093475","n2199093476","n2199093477","n2199093478","n2199093479","n2199093480","n2199093475"]},"w209716131":{"id":"w209716131","tags":{"area":"yes","natural":"water","water":"pond"},"nodes":["n2199093489","n2199093490","n2199093491","n2199093492","n2199093493","n2199093494","n2199093495","n2199093496","n2199093497","n2199093498","n2199093499","n2199093500","n2199093501","n2199093502","n2199093503","n2199093504","n2199093505","n2199093506","n2199093489"]},"w209716126":{"id":"w209716126","tags":{"area":"yes","building":"yes"},"nodes":["n2199093467","n2199093468","n2199093469","n2199093470","n2199093471","n2199093472","n2199093473","n2199093474","n2199093467"]},"w209716124":{"id":"w209716124","tags":{"area":"yes","building":"yes"},"nodes":["n2199093455","n2199093456","n2199093457","n2199093458","n2199093455"]},"w209716128":{"id":"w209716128","tags":{"area":"yes","building":"yes"},"nodes":["n2199093481","n2199093482","n2199093483","n2199093484","n2199093481"]},"n185949872":{"id":"n185949872","loc":[-85.643009,41.949264]},"n185949875":{"id":"n185949875","loc":[-85.642598,41.94929]},"n185949877":{"id":"n185949877","loc":[-85.642127,41.949382]},"n185949881":{"id":"n185949881","loc":[-85.64169,41.949936]},"n185988165":{"id":"n185988165","loc":[-85.642167,41.947657]},"n185988167":{"id":"n185988167","loc":[-85.642347,41.947662]},"n185988169":{"id":"n185988169","loc":[-85.642621,41.947659]},"n185965019":{"id":"n185965019","loc":[-85.6385084,41.951127]},"n1475293248":{"id":"n1475293248","loc":[-85.6386095,41.9512214]},"n185962639":{"id":"n185962639","loc":[-85.649669,41.949161]},"n185962810":{"id":"n185962810","loc":[-85.649907,41.949157]},"n185964355":{"id":"n185964355","loc":[-85.637412,41.9511359]},"n185965021":{"id":"n185965021","loc":[-85.638661,41.952386]},"n185965023":{"id":"n185965023","loc":[-85.638654,41.953665]},"n185965025":{"id":"n185965025","loc":[-85.638694,41.954649]},"n185965027":{"id":"n185965027","loc":[-85.638724,41.955913]},"n185971415":{"id":"n185971415","loc":[-85.644466,41.949246]},"n185971417":{"id":"n185971417","loc":[-85.647021,41.949193]},"n185971420":{"id":"n185971420","loc":[-85.648476,41.949169]},"n185979975":{"id":"n185979975","loc":[-85.644429,41.947633]},"n185988171":{"id":"n185988171","loc":[-85.645377,41.947622]},"w17963211":{"id":"w17963211","tags":{"highway":"residential"},"nodes":["n185949870","n185949872","n185949875","n185949877","n185949881"]},"w17965839":{"id":"w17965839","tags":{"highway":"residential","name":"Arnold St"},"nodes":["n185949870","n185971415","n185971417","n185971420","n185962639","n185962810"]},"w17967618":{"id":"w17967618","tags":{"highway":"residential","name":"Pierson St"},"nodes":["n185967777","n185988165","n185988167","n185988169","n185985824","n185979975","n185988171"]},"w17965149":{"id":"w17965149","tags":{"highway":"residential","name":"Oak St"},"nodes":["n185965019","n1475293248","n185965021","n185965023","n185965025","n185965027"]},"w17966118":{"id":"w17966118","tags":{"highway":"residential","name":"West Armitage Street"},"nodes":["n185974583","n185974585","n185964355","n185965019"]},"n2208608800":{"id":"n2208608800","loc":[-85.6354294,41.9486201]},"n2199109806":{"id":"n2199109806","loc":[-85.6350474,41.9477884]},"n2199109804":{"id":"n2199109804","loc":[-85.6350476,41.9477962]},"n2199109802":{"id":"n2199109802","loc":[-85.635002,41.9477969]},"n2199109799":{"id":"n2199109799","loc":[-85.6350018,41.9477883]},"n2199109797":{"id":"n2199109797","loc":[-85.6349141,41.9477897]},"n2199109795":{"id":"n2199109795","loc":[-85.6349131,41.9477535]},"n2199109793":{"id":"n2199109793","loc":[-85.6349395,41.9477531]},"n2199109791":{"id":"n2199109791","loc":[-85.6349382,41.9477077]},"n2199109789":{"id":"n2199109789","loc":[-85.6351236,41.9477049]},"n2199109787":{"id":"n2199109787","loc":[-85.6351259,41.9477872]},"n2199109785":{"id":"n2199109785","loc":[-85.634972,41.9475992]},"n2199109783":{"id":"n2199109783","loc":[-85.6349206,41.9475997]},"n2199109770":{"id":"n2199109770","loc":[-85.6348499,41.9475461]},"n2199109768":{"id":"n2199109768","loc":[-85.6348499,41.9475084]},"n2199109765":{"id":"n2199109765","loc":[-85.6349241,41.9474569]},"n2199109763":{"id":"n2199109763","loc":[-85.634967,41.9474564]},"n2199109762":{"id":"n2199109762","loc":[-85.6350405,41.9475121]},"n2199109761":{"id":"n2199109761","loc":[-85.6350405,41.9475419]},"n2199109753":{"id":"n2199109753","loc":[-85.6342443,41.9478391]},"n2199109751":{"id":"n2199109751","loc":[-85.6342427,41.9477927]},"n2199109745":{"id":"n2199109745","loc":[-85.6342439,41.9476859]},"n2199109743":{"id":"n2199109743","loc":[-85.6342429,41.9476575]},"n2199109741":{"id":"n2199109741","loc":[-85.6344615,41.9476533]},"n2199109739":{"id":"n2199109739","loc":[-85.6344678,41.9478348]},"n2199109737":{"id":"n2199109737","loc":[-85.634416,41.9480059]},"n2199109735":{"id":"n2199109735","loc":[-85.6344145,41.9478983]},"n2199109733":{"id":"n2199109733","loc":[-85.6342749,41.9478993]},"n2199109731":{"id":"n2199109731","loc":[-85.6342753,41.9479272]},"n2199109729":{"id":"n2199109729","loc":[-85.6342498,41.9479274]},"n2199109727":{"id":"n2199109727","loc":[-85.6342505,41.9479762]},"n2199109725":{"id":"n2199109725","loc":[-85.6342743,41.947976]},"n2199109723":{"id":"n2199109723","loc":[-85.6342747,41.948007]},"n2199109721":{"id":"n2199109721","loc":[-85.6343415,41.9476355]},"n2199109719":{"id":"n2199109719","loc":[-85.6343391,41.9474973]},"n2199109717":{"id":"n2199109717","loc":[-85.6343133,41.9474798]},"n2199109715":{"id":"n2199109715","loc":[-85.6342874,41.9474737]},"n2199109709":{"id":"n2199109709","loc":[-85.6349804,41.94815]},"n2199109707":{"id":"n2199109707","loc":[-85.6348915,41.9481505]},"n2199109705":{"id":"n2199109705","loc":[-85.6348917,41.9481692]},"n2199109702":{"id":"n2199109702","loc":[-85.6348522,41.9481694]},"n2199109700":{"id":"n2199109700","loc":[-85.6348532,41.9482679]},"n2199109698":{"id":"n2199109698","loc":[-85.6348315,41.948268]},"n2199109696":{"id":"n2199109696","loc":[-85.6348318,41.9482955]},"n2199109694":{"id":"n2199109694","loc":[-85.6349653,41.9482946]},"n2199109692":{"id":"n2199109692","loc":[-85.6349656,41.9483211]},"n2199109690":{"id":"n2199109690","loc":[-85.634999,41.9483209]},"n2199109688":{"id":"n2199109688","loc":[-85.6349987,41.9482947]},"n2199109686":{"id":"n2199109686","loc":[-85.6351753,41.9482935]},"n2199109684":{"id":"n2199109684","loc":[-85.6351749,41.9482617]},"n2199109682":{"id":"n2199109682","loc":[-85.6351588,41.9482618]},"n2199109680":{"id":"n2199109680","loc":[-85.6351575,41.9481518]},"n2199109678":{"id":"n2199109678","loc":[-85.6350671,41.9481524]},"n2199109676":{"id":"n2199109676","loc":[-85.6350649,41.9479659]},"n2199109674":{"id":"n2199109674","loc":[-85.6349785,41.9479665]},"n2199109671":{"id":"n2199109671","loc":[-85.6343069,41.9483263]},"n2199109669":{"id":"n2199109669","loc":[-85.6343052,41.9482981]},"n2199109658":{"id":"n2199109658","loc":[-85.6343314,41.9480549]},"n2199109656":{"id":"n2199109656","loc":[-85.6343305,41.9480461]},"n2199109654":{"id":"n2199109654","loc":[-85.634435,41.9480468]},"n2199109652":{"id":"n2199109652","loc":[-85.6344342,41.9483746]},"n2199109650":{"id":"n2199109650","loc":[-85.6344629,41.9483727]},"n2199109648":{"id":"n2199109648","loc":[-85.6344637,41.9484561]},"n2199109645":{"id":"n2199109645","loc":[-85.63443,41.9484567]},"n2199109642":{"id":"n2199109642","loc":[-85.6344317,41.948505]},"n185964352":{"id":"n185964352","loc":[-85.6373958,41.9489943]},"n185964351":{"id":"n185964351","loc":[-85.637113,41.9486]},"n2208608825":{"id":"n2208608825","loc":[-85.6354483,41.9494241]},"n2208608823":{"id":"n2208608823","loc":[-85.6360418,41.949416]},"n2208608821":{"id":"n2208608821","loc":[-85.6360458,41.9495802]},"n2208608811":{"id":"n2208608811","loc":[-85.6357458,41.9495843]},"n2208608808":{"id":"n2208608808","loc":[-85.6357508,41.9497835]},"n2208608806":{"id":"n2208608806","loc":[-85.6354573,41.9497875]},"n2208608795":{"id":"n2208608795","loc":[-85.6354595,41.9498778]},"n2199109638":{"id":"n2199109638","loc":[-85.6349605,41.949749]},"n2199109636":{"id":"n2199109636","loc":[-85.6349605,41.9497639]},"n2199109634":{"id":"n2199109634","loc":[-85.6349061,41.94971]},"n2199109632":{"id":"n2199109632","loc":[-85.6349048,41.9496569]},"n2199109630":{"id":"n2199109630","loc":[-85.6348835,41.9496571]},"n2199109628":{"id":"n2199109628","loc":[-85.6348829,41.9497103]},"n2199109626":{"id":"n2199109626","loc":[-85.635227,41.9497738]},"n2199109624":{"id":"n2199109624","loc":[-85.6352184,41.9497787]},"n2199109622":{"id":"n2199109622","loc":[-85.6351181,41.9497806]},"n2199109620":{"id":"n2199109620","loc":[-85.6351181,41.9497456]},"n2199109618":{"id":"n2199109618","loc":[-85.6348842,41.9497651]},"n2199109616":{"id":"n2199109616","loc":[-85.6348827,41.9496238]},"n2199109615":{"id":"n2199109615","loc":[-85.6351268,41.9496206]},"n2199109614":{"id":"n2199109614","loc":[-85.6351261,41.9495891]},"n2199109613":{"id":"n2199109613","loc":[-85.6351957,41.9495881]},"n2199109612":{"id":"n2199109612","loc":[-85.6351924,41.9494515]},"n2199109611":{"id":"n2199109611","loc":[-85.6353997,41.9494488]},"n2199109610":{"id":"n2199109610","loc":[-85.6354074,41.9497715]},"n2189015681":{"id":"n2189015681","loc":[-85.6344229,41.9509639]},"n2189015677":{"id":"n2189015677","loc":[-85.634424,41.9507396]},"n2138493843":{"id":"n2138493843","loc":[-85.6343935,41.9502836]},"n2138493840":{"id":"n2138493840","loc":[-85.634398,41.9506264]},"n354002838":{"id":"n354002838","loc":[-85.6345197,41.9510631]},"n2114807590":{"id":"n2114807590","loc":[-85.634511,41.9499767]},"n185964353":{"id":"n185964353","loc":[-85.6374092,41.9498755]},"n1819849180":{"id":"n1819849180","loc":[-85.6348236,41.94996]},"n1819849115":{"id":"n1819849115","loc":[-85.6354372,41.9499538]},"n1819848921":{"id":"n1819848921","loc":[-85.6348439,41.951064]},"n1819848885":{"id":"n1819848885","loc":[-85.6354575,41.9510578]},"n185984281":{"id":"n185984281","loc":[-85.638075,41.949872]},"n2208608827":{"id":"n2208608827","loc":[-85.6339169,41.9473191]},"n2199109749":{"id":"n2199109749","loc":[-85.6342082,41.9477934]},"n2199109747":{"id":"n2199109747","loc":[-85.6342045,41.9476867]},"n2199109713":{"id":"n2199109713","loc":[-85.6342404,41.9474746]},"n2199109711":{"id":"n2199109711","loc":[-85.6342404,41.9476355]},"n2199109673":{"id":"n2199109673","loc":[-85.6340886,41.9483282]},"n2199109667":{"id":"n2199109667","loc":[-85.6342403,41.9482988]},"n2199109665":{"id":"n2199109665","loc":[-85.6342386,41.9482116]},"n2199109662":{"id":"n2199109662","loc":[-85.6340861,41.9482135]},"n2199109660":{"id":"n2199109660","loc":[-85.6340802,41.9480562]},"n2199109640":{"id":"n2199109640","loc":[-85.6340928,41.9485063]},"n354031366":{"id":"n354031366","loc":[-85.6341667,41.9477778],"tags":{"amenity":"place_of_worship","name":"Faith Tabernacle Church","religion":"christian"}},"n2189015686":{"id":"n2189015686","loc":[-85.6337798,41.95099]},"n2189015684":{"id":"n2189015684","loc":[-85.6337794,41.9509674]},"n2189015673":{"id":"n2189015673","loc":[-85.6337501,41.9507457]},"n2189015669":{"id":"n2189015669","loc":[-85.6337501,41.9506974]},"n2189015665":{"id":"n2189015665","loc":[-85.6339034,41.9506959]},"n2189015662":{"id":"n2189015662","loc":[-85.6339015,41.950436]},"n2189015658":{"id":"n2189015658","loc":[-85.6334916,41.9504376]},"n2189015655":{"id":"n2189015655","loc":[-85.6334939,41.9507558]},"n2189015650":{"id":"n2189015650","loc":[-85.6334543,41.950756]},"n2189015649":{"id":"n2189015649","loc":[-85.633456,41.9509915]},"n2138493842":{"id":"n2138493842","loc":[-85.6339937,41.9502836]},"n2138493841":{"id":"n2138493841","loc":[-85.6339983,41.9506281]},"n2114807579":{"id":"n2114807579","loc":[-85.6333644,41.9510682]},"n2114807573":{"id":"n2114807573","loc":[-85.6333557,41.9499819]},"n354031330":{"id":"n354031330","loc":[-85.6341667,41.9497222],"tags":{"amenity":"place_of_worship","name":"Trinity Episcopal Church","religion":"christian"}},"n185960794":{"id":"n185960794","loc":[-85.633307,41.9537]},"n185964357":{"id":"n185964357","loc":[-85.637432,41.952399]},"n185964358":{"id":"n185964358","loc":[-85.637452,41.953665]},"n185964359":{"id":"n185964359","loc":[-85.63746,41.954658]},"n185964360":{"id":"n185964360","loc":[-85.637473,41.95592]},"n185964361":{"id":"n185964361","loc":[-85.637468,41.956906]},"n185964362":{"id":"n185964362","loc":[-85.637483,41.958313]},"n185966957":{"id":"n185966957","loc":[-85.633361,41.957422]},"n185975351":{"id":"n185975351","loc":[-85.63334,41.9559]},"n185978784":{"id":"n185978784","loc":[-85.633311,41.954679]},"n185986157":{"id":"n185986157","loc":[-85.633287,41.952426]},"n185986158":{"id":"n185986158","loc":[-85.6333607,41.9582301],"tags":{"highway":"turning_circle"}},"w17965182":{"id":"w17965182","tags":{"highway":"residential","name":"W Prutzman St"},"nodes":["n185965289","n2189153241","n185965291"]},"w208627205":{"id":"w208627205","tags":{"area":"yes","building":"yes"},"nodes":["n2189015649","n2189015650","n2189015655","n2189015658","n2189015662","n2189015665","n2189015669","n2189015673","n2189015677","n2189015681","n2189015684","n2189015686","n2189015649"]},"w209717042":{"id":"w209717042","tags":{"amenity":"place_of_worship","area":"yes","building":"yes","denomination":"presbyterian","name":"First Presbyterian Church","religion":"christian"},"nodes":["n2199109610","n2199109611","n2199109612","n2199109613","n2199109614","n2199109615","n2199109616","n2199109630","n2199109632","n2199109634","n2199109628","n2199109618","n2199109636","n2199109638","n2199109620","n2199109622","n2199109624","n2199109626","n2199109610"]},"w209717045":{"id":"w209717045","tags":{"area":"yes","building":"yes"},"nodes":["n2199109711","n2199109713","n2199109715","n2199109717","n2199109719","n2199109721","n2199109711"]},"w209717047":{"id":"w209717047","tags":{"area":"yes","building":"yes"},"nodes":["n2199109739","n2199109741","n2199109743","n2199109745","n2199109747","n2199109749","n2199109751","n2199109753","n2199109739"]},"w209717044":{"id":"w209717044","tags":{"area":"yes","building":"yes"},"nodes":["n2199109674","n2199109676","n2199109678","n2199109680","n2199109682","n2199109684","n2199109686","n2199109688","n2199109690","n2199109692","n2199109694","n2199109696","n2199109698","n2199109700","n2199109702","n2199109705","n2199109707","n2199109709","n2199109674"]},"w210822776":{"id":"w210822776","tags":{"highway":"service","service":"alley","surface":"unpaved"},"nodes":["n2208608795","n2208608806","n2208608825","n2208608800","n2189153241"]},"w210822778":{"id":"w210822778","tags":{"highway":"service","service":"alley"},"nodes":["n2208608826","n2208608827"]},"w209717050":{"id":"w209717050","tags":{"area":"yes","building":"yes"},"nodes":["n2199109787","n2199109789","n2199109791","n2199109793","n2199109795","n2199109797","n2199109799","n2199109802","n2199109804","n2199109806","n2199109787"]},"w17965097":{"id":"w17965097","tags":{"highway":"residential","name":"Maple Street"},"nodes":["n185964351","n185964352","n185964353","n185964355","n185964357","n185964358","n185964359","n185964360","n185964361","n185964362"]},"w17965856":{"id":"w17965856","tags":{"highway":"residential","name":"W Kelsey St"},"nodes":["n185971578","n2208608800","n185971580","n185964351"]},"w17967444":{"id":"w17967444","tags":{"highway":"residential","name":"East Street"},"nodes":["n185966937","n185978969","n185986155","n185985812","n185986157","n185960794","n185978784","n185975351","n185966957","n185986158"]},"w17967764":{"id":"w17967764","tags":{"highway":"residential","name":"Rock River Ave"},"nodes":["n185984017","n185964351"]},"w170848329":{"id":"w170848329","tags":{"leisure":"park","name":"LaFayette Park"},"nodes":["n1819849180","n1819849115","n1819848885","n1819848921","n1819849180"]},"w17967208":{"id":"w17967208","tags":{"highway":"residential","name":"West Bennett Street"},"nodes":["n185978390","n2208608795","n185984020","n185964353","n185984281"]},"w17965349":{"id":"w17965349","tags":{"highway":"residential","name":"E Prutzman St"},"nodes":["n185966937","n2208608827","n185965289"]},"w209717049":{"id":"w209717049","tags":{"area":"yes","building":"yes"},"nodes":["n2199109761","n2199109762","n2199109763","n2199109765","n2199109768","n2199109770","n2199109783","n2199109785","n2199109761"]},"w203841840":{"id":"w203841840","tags":{"area":"yes","leisure":"playground"},"nodes":["n2138493840","n2138493841","n2138493842","n2138493843","n2138493840"]},"w209717043":{"id":"w209717043","tags":{"amenity":"place_of_worship","area":"yes","building":"church","denomination":"methodist","name":"First United Methodist Church","religion":"christian"},"nodes":["n2199109640","n2199109642","n2199109645","n2199109648","n2199109650","n2199109652","n2199109654","n2199109656","n2199109658","n2199109660","n2199109662","n2199109665","n2199109667","n2199109669","n2199109671","n2199109673","n2199109640"]},"w201484341":{"id":"w201484341","tags":{"amenity":"school","name":"Hoppin School"},"nodes":["n354002838","n2114807579","n2114807573","n2114807590","n354002838"]},"w209717046":{"id":"w209717046","tags":{"area":"yes","building":"yes"},"nodes":["n2199109723","n2199109725","n2199109727","n2199109729","n2199109731","n2199109733","n2199109735","n2199109737","n2199109723"]},"w210822777":{"id":"w210822777","tags":{"amenity":"parking","area":"yes"},"nodes":["n2208608806","n2208608808","n2208608811","n2208608821","n2208608823","n2208608825","n2208608806"]},"n185954965":{"id":"n185954965","loc":[-85.6191189,41.9441922]},"n185954968":{"id":"n185954968","loc":[-85.6194384,41.9442405]},"n185954970":{"id":"n185954970","loc":[-85.6196543,41.9443252]},"n185954972":{"id":"n185954972","loc":[-85.6197862,41.9444539]},"n354002931":{"id":"n354002931","loc":[-85.6198991,41.9455269]},"n354030853":{"id":"n354030853","loc":[-85.6219444,41.9455556],"tags":{"amenity":"place_of_worship","name":"Grant Chapel","religion":"christian"}},"n367815963":{"id":"n367815963","loc":[-85.6202778,41.9461111],"tags":{"building":"yes","name":"George Washington Carver Community Center"}},"n185947331":{"id":"n185947331","loc":[-85.618779,41.943269]},"n185947333":{"id":"n185947333","loc":[-85.618795,41.943511]},"n185947336":{"id":"n185947336","loc":[-85.618711,41.94413]},"n185947338":{"id":"n185947338","loc":[-85.618704,41.944189]},"n185947339":{"id":"n185947339","loc":[-85.618597,41.944337]},"n185947340":{"id":"n185947340","loc":[-85.618485,41.944528]},"n185947343":{"id":"n185947343","loc":[-85.618442,41.944716]},"n185947345":{"id":"n185947345","loc":[-85.618457,41.945107]},"n185947347":{"id":"n185947347","loc":[-85.618296,41.945338]},"n185947374":{"id":"n185947374","loc":[-85.616748,41.944453]},"n185947375":{"id":"n185947375","loc":[-85.616813,41.944646]},"n185947376":{"id":"n185947376","loc":[-85.616859,41.945196]},"n185947377":{"id":"n185947377","loc":[-85.616941,41.945352]},"n185947406":{"id":"n185947406","loc":[-85.618184,41.944227]},"n185947409":{"id":"n185947409","loc":[-85.617911,41.943875]},"n185947410":{"id":"n185947410","loc":[-85.617579,41.943682]},"n185947411":{"id":"n185947411","loc":[-85.61713,41.943589]},"n185947412":{"id":"n185947412","loc":[-85.616549,41.943559]},"n185947414":{"id":"n185947414","loc":[-85.616482,41.943556]},"n185947464":{"id":"n185947464","loc":[-85.616526,41.943788]},"n185947466":{"id":"n185947466","loc":[-85.616504,41.944002]},"n185948863":{"id":"n185948863","loc":[-85.619017,41.943391]},"n185948865":{"id":"n185948865","loc":[-85.619059,41.943368]},"n185955022":{"id":"n185955022","loc":[-85.620088,41.945571]},"n185955025":{"id":"n185955025","loc":[-85.620051,41.945505]},"n185955028":{"id":"n185955028","loc":[-85.62001,41.94541]},"n185980371":{"id":"n185980371","loc":[-85.620982,41.944742]},"n185980398":{"id":"n185980398","loc":[-85.621305,41.944782]},"n185980401":{"id":"n185980401","loc":[-85.621174,41.944819]},"n185980403":{"id":"n185980403","loc":[-85.621029,41.944871]},"n185980405":{"id":"n185980405","loc":[-85.620741,41.945011]},"n185980407":{"id":"n185980407","loc":[-85.620616,41.945085]},"n185980409":{"id":"n185980409","loc":[-85.620506,41.945172]},"n185980411":{"id":"n185980411","loc":[-85.620394,41.945273]},"n185980413":{"id":"n185980413","loc":[-85.620316,41.94536]},"n185980415":{"id":"n185980415","loc":[-85.620257,41.945452]},"n185980417":{"id":"n185980417","loc":[-85.620212,41.945535]},"n185985910":{"id":"n185985910","loc":[-85.620101,41.945811]},"n185985912":{"id":"n185985912","loc":[-85.620081,41.945937]},"n1475283972":{"id":"n1475283972","loc":[-85.6198991,41.9437179]},"n1475283982":{"id":"n1475283982","loc":[-85.6195022,41.9433463]},"n1475284007":{"id":"n1475284007","loc":[-85.6193037,41.9433383]},"n1475284040":{"id":"n1475284040","loc":[-85.6197329,41.9434121]},"n1475284044":{"id":"n1475284044","loc":[-85.6198756,41.9435363]},"n1475284050":{"id":"n1475284050","loc":[-85.6199689,41.9432106]},"n1475284053":{"id":"n1475284053","loc":[-85.6198943,41.9432921]},"n185954974":{"id":"n185954974","loc":[-85.6198296,41.94473]},"n185954977":{"id":"n185954977","loc":[-85.6200474,41.9447384]},"n2196831365":{"id":"n2196831365","loc":[-85.6202259,41.9460883]},"n2196831366":{"id":"n2196831366","loc":[-85.6202245,41.9458642]},"n2196831367":{"id":"n2196831367","loc":[-85.6205184,41.9458631]},"n2196831368":{"id":"n2196831368","loc":[-85.6205189,41.9459437]},"n2196831369":{"id":"n2196831369","loc":[-85.6203879,41.9459441]},"n2196831370":{"id":"n2196831370","loc":[-85.6203888,41.9460878]},"n2196831371":{"id":"n2196831371","loc":[-85.6184046,41.9465663]},"n2196831372":{"id":"n2196831372","loc":[-85.6191563,41.9465618]},"n2196831373":{"id":"n2196831373","loc":[-85.6191536,41.946319]},"n2196831374":{"id":"n2196831374","loc":[-85.6187356,41.9463216]},"n2196831375":{"id":"n2196831375","loc":[-85.6187334,41.9461197]},"n2196831376":{"id":"n2196831376","loc":[-85.6193167,41.9461162]},"n2196831377":{"id":"n2196831377","loc":[-85.6193156,41.9460229]},"n2196831378":{"id":"n2196831378","loc":[-85.619622,41.946021]},"n2196831379":{"id":"n2196831379","loc":[-85.6196237,41.9461712]},"n2196831380":{"id":"n2196831380","loc":[-85.6197702,41.9461703]},"n2196831381":{"id":"n2196831381","loc":[-85.6197685,41.9460202]},"n2196831382":{"id":"n2196831382","loc":[-85.6197323,41.9460204]},"n2196831383":{"id":"n2196831383","loc":[-85.6197305,41.9458563]},"n2196831384":{"id":"n2196831384","loc":[-85.6196165,41.945857]},"n2196831385":{"id":"n2196831385","loc":[-85.6196156,41.9457764]},"n2196831386":{"id":"n2196831386","loc":[-85.6194472,41.9457775]},"n2196831387":{"id":"n2196831387","loc":[-85.6194151,41.9457777]},"n2196831388":{"id":"n2196831388","loc":[-85.6183779,41.9457883]},"n2196831389":{"id":"n2196831389","loc":[-85.6183842,41.9461317]},"n2196831390":{"id":"n2196831390","loc":[-85.6185026,41.9461304]},"n2196831391":{"id":"n2196831391","loc":[-85.6185061,41.9463194]},"n2196831392":{"id":"n2196831392","loc":[-85.6184001,41.9463205]},"n2196831393":{"id":"n2196831393","loc":[-85.6182482,41.9464163]},"n2196831394":{"id":"n2196831394","loc":[-85.6182467,41.9463193]},"n2196831395":{"id":"n2196831395","loc":[-85.6180389,41.946321]},"n2196831397":{"id":"n2196831397","loc":[-85.6180404,41.946418]},"n185947303":{"id":"n185947303","loc":[-85.611074,41.943389]},"n185947304":{"id":"n185947304","loc":[-85.611332,41.943267]},"n185947305":{"id":"n185947305","loc":[-85.611635,41.943218]},"n185947306":{"id":"n185947306","loc":[-85.612762,41.943311]},"n185947308":{"id":"n185947308","loc":[-85.613027,41.943327]},"n185947310":{"id":"n185947310","loc":[-85.615377,41.942996]},"n185947312":{"id":"n185947312","loc":[-85.615701,41.943007]},"n185947314":{"id":"n185947314","loc":[-85.61604,41.943067]},"n185947315":{"id":"n185947315","loc":[-85.61626,41.943083]},"n185947316":{"id":"n185947316","loc":[-85.616507,41.943048]},"n185947319":{"id":"n185947319","loc":[-85.616702,41.94299]},"n185947321":{"id":"n185947321","loc":[-85.617078,41.942918]},"n185947322":{"id":"n185947322","loc":[-85.617366,41.942973]},"n185947323":{"id":"n185947323","loc":[-85.617601,41.943033]},"n185947325":{"id":"n185947325","loc":[-85.617799,41.943027]},"n185947327":{"id":"n185947327","loc":[-85.618264,41.942961]},"n185947328":{"id":"n185947328","loc":[-85.618508,41.942972]},"n185947329":{"id":"n185947329","loc":[-85.618707,41.943076]},"n185947361":{"id":"n185947361","loc":[-85.615356,41.944922]},"n185947363":{"id":"n185947363","loc":[-85.61536,41.944893]},"n185947365":{"id":"n185947365","loc":[-85.615406,41.944547]},"n185947367":{"id":"n185947367","loc":[-85.61548,41.944351]},"n185947369":{"id":"n185947369","loc":[-85.615805,41.94419]},"n185947371":{"id":"n185947371","loc":[-85.616166,41.944156]},"n185947373":{"id":"n185947373","loc":[-85.616411,41.944197]},"n185947416":{"id":"n185947416","loc":[-85.616335,41.94343]},"n185947417":{"id":"n185947417","loc":[-85.616069,41.943293]},"n185947419":{"id":"n185947419","loc":[-85.615803,41.943249]},"n185947420":{"id":"n185947420","loc":[-85.615524,41.943342]},"n185947421":{"id":"n185947421","loc":[-85.615311,41.94353]},"n185947422":{"id":"n185947422","loc":[-85.614338,41.943558]},"n185947423":{"id":"n185947423","loc":[-85.61422,41.94369]},"n185947425":{"id":"n185947425","loc":[-85.614221,41.944224]},"n185947427":{"id":"n185947427","loc":[-85.614198,41.944888]},"n185947429":{"id":"n185947429","loc":[-85.614221,41.945439]},"n185947468":{"id":"n185947468","loc":[-85.615908,41.944756]},"n185947470":{"id":"n185947470","loc":[-85.615871,41.944888]},"n185947472":{"id":"n185947472","loc":[-85.615878,41.94507]},"n185955153":{"id":"n185955153","loc":[-85.620087,41.947701]},"n185960690":{"id":"n185960690","loc":[-85.620141,41.951901]},"n185978817":{"id":"n185978817","loc":[-85.617193,41.954706]},"n185985916":{"id":"n185985916","loc":[-85.620088,41.94758]},"n185985918":{"id":"n185985918","loc":[-85.620133,41.951538]},"n185985919":{"id":"n185985919","loc":[-85.62013,41.952104]},"n185985920":{"id":"n185985920","loc":[-85.620104,41.952305]},"n185985921":{"id":"n185985921","loc":[-85.620062,41.952499]},"n185985922":{"id":"n185985922","loc":[-85.619993,41.952702]},"n185985925":{"id":"n185985925","loc":[-85.619879,41.952986]},"n185985927":{"id":"n185985927","loc":[-85.619689,41.95329]},"n185985928":{"id":"n185985928","loc":[-85.619508,41.953521]},"n185985929":{"id":"n185985929","loc":[-85.619286,41.953728]},"n185985930":{"id":"n185985930","loc":[-85.618925,41.954007]},"n185985931":{"id":"n185985931","loc":[-85.618638,41.954189]},"n185985932":{"id":"n185985932","loc":[-85.61831,41.954358]},"n185985934":{"id":"n185985934","loc":[-85.618015,41.954485]},"n185985936":{"id":"n185985936","loc":[-85.617606,41.954611]},"n1475283975":{"id":"n1475283975","loc":[-85.6150935,41.9434118]},"n1475283979":{"id":"n1475283979","loc":[-85.6193367,41.9430252]},"n1475283989":{"id":"n1475283989","loc":[-85.6104771,41.9455269]},"n1475283990":{"id":"n1475283990","loc":[-85.6104771,41.9437179]},"n1475283994":{"id":"n1475283994","loc":[-85.6198042,41.9429763]},"n1475283998":{"id":"n1475283998","loc":[-85.6192101,41.9426716]},"n1475284000":{"id":"n1475284000","loc":[-85.6198622,41.942836]},"n1475284002":{"id":"n1475284002","loc":[-85.6163262,41.9427688]},"n1475284006":{"id":"n1475284006","loc":[-85.6179527,41.9429168]},"n1475284029":{"id":"n1475284029","loc":[-85.6197195,41.9427278]},"n1475284038":{"id":"n1475284038","loc":[-85.6194405,41.9427837]},"n1475284052":{"id":"n1475284052","loc":[-85.6153225,41.942841]},"n1475284055":{"id":"n1475284055","loc":[-85.6129233,41.9437179]},"n2139966627":{"id":"n2139966627","loc":[-85.61958,41.9427558]},"w17966773":{"id":"w17966773","tags":{"highway":"secondary","name":"E Michigan Ave","ref":"M 60"},"nodes":["n185980372","n185980398","n185980401","n185980403","n185980405","n185980407","n185980409","n185980411","n185980413","n185980415","n185980417","n185955019"]},"w17964043":{"id":"w17964043","tags":{"highway":"residential"},"nodes":["n185955019","n185955022","n185955025","n185955028","n185954977","n185971477","n1475284050","n1475284000","n1475284029","n2139966627","n1475284038"]},"w17962834":{"id":"w17962834","tags":{"highway":"service"},"nodes":["n185947316","n185947414","n185947464","n185947466","n185947373","n185947468","n185947470","n185947472","n185947474"]},"w209470310":{"id":"w209470310","tags":{"area":"yes","building":"yes"},"nodes":["n2196831393","n2196831394","n2196831395","n2196831397","n2196831393"]},"w17963058":{"id":"w17963058","tags":{"highway":"service"},"nodes":["n185947333","n185948863","n185948865","n1475284007","n1475283982","n1475284040","n1475284044"]},"w17962823":{"id":"w17962823","tags":{"highway":"service"},"nodes":["n185947359","n185947361","n185947363","n185947365","n185947367","n185947369","n185947371","n185947373","n185947374","n185947375","n185947376","n185947377","n185947378"]},"w17962821":{"id":"w17962821","tags":{"highway":"service"},"nodes":["n185947303","n185947304","n185947305","n185947306","n185947308","n185947310","n185947312","n185947314","n185947315","n185947316","n185947319","n185947321","n185947322","n185947323","n185947325","n185947327","n185947328","n185947329","n185947331","n185947333","n185947336","n185947338","n185947339","n185947340","n185947343","n185947345","n185947347","n185947349"]},"w134150798":{"id":"w134150798","tags":{"amenity":"grave_yard","name":"Riverside Cemetery"},"nodes":["n354002931","n1475283972","n1475284053","n1475283994","n1475283979","n1475283998","n1475284006","n1475284002","n1475284052","n1475283975","n1475284055","n1475283990","n1475283989","n354002931"]},"w17964040":{"id":"w17964040","tags":{"highway":"service"},"nodes":["n185947336","n185954965","n185954968","n185954970","n185954972","n185954974","n185954977"]},"w209470308":{"id":"w209470308","tags":{"area":"yes","building":"yes"},"nodes":["n2196831365","n2196831366","n2196831367","n2196831368","n2196831369","n2196831370","n2196831365"]},"w17962828":{"id":"w17962828","tags":{"highway":"service"},"nodes":["n185947340","n185947406","n185947409","n185947410","n185947411","n185947412","n185947414","n185947416","n185947417","n185947419","n185947420","n185947421","n185947422","n185947423","n185947425","n185947427","n185947429"]},"w209470309":{"id":"w209470309","tags":{"area":"yes","building":"yes"},"nodes":["n2196831371","n2196831372","n2196831373","n2196831374","n2196831375","n2196831376","n2196831377","n2196831378","n2196831379","n2196831380","n2196831381","n2196831382","n2196831383","n2196831384","n2196831385","n2196831386","n2196831387","n2196831388","n2196831389","n2196831390","n2196831391","n2196831392","n2196831371"]},"w17967415":{"id":"w17967415","tags":{"highway":"secondary","name":"Jefferson St","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185955019","n185985910","n185985912","n185985914","n185961367","n185985916","n185955153","n185965105","n185974697","n185955120","n185985918","n185960690","n185985919","n185985920","n185985921","n185985922","n185985925","n185985927","n185985928","n185985929","n185985930","n185985931","n185985932","n185985934","n185985936","n185978817"]},"w17966772":{"id":"w17966772","tags":{"highway":"unclassified","name":"E Michigan Ave","name_1":"State Highway 60"},"nodes":["n185954977","n185980371","n185980372"]},"n185958500":{"id":"n185958500","loc":[-85.621591,41.941075]},"n185963110":{"id":"n185963110","loc":[-85.6204416,41.9408882]},"n2139966628":{"id":"n2139966628","loc":[-85.6196431,41.9426467],"tags":{"leisure":"fishing"}},"n2139966630":{"id":"n2139966630","loc":[-85.6199354,41.9429616]},"n2199127051":{"id":"n2199127051","loc":[-85.6170556,41.939696]},"n2199127052":{"id":"n2199127052","loc":[-85.6170536,41.9392909]},"n2199127053":{"id":"n2199127053","loc":[-85.6172067,41.9392905]},"n2199127054":{"id":"n2199127054","loc":[-85.6172061,41.9391853]},"n2199127055":{"id":"n2199127055","loc":[-85.6171481,41.9391854]},"n2199127060":{"id":"n2199127060","loc":[-85.6167389,41.9392896]},"n2199127061":{"id":"n2199127061","loc":[-85.6168728,41.9392892]},"n2199127062":{"id":"n2199127062","loc":[-85.6168747,41.9396965]},"n2199127071":{"id":"n2199127071","loc":[-85.620196,41.9399446]},"n2199127072":{"id":"n2199127072","loc":[-85.620193,41.9397316]},"n2199127073":{"id":"n2199127073","loc":[-85.6200381,41.9397328]},"n2199127074":{"id":"n2199127074","loc":[-85.6200412,41.9399458]},"n2199127075":{"id":"n2199127075","loc":[-85.6203606,41.9399939]},"n2199127076":{"id":"n2199127076","loc":[-85.6205527,41.9399922]},"n2199127077":{"id":"n2199127077","loc":[-85.6205482,41.9397115]},"n2199127078":{"id":"n2199127078","loc":[-85.6204132,41.9397124]},"n2199127079":{"id":"n2199127079","loc":[-85.6204144,41.9396341]},"n2199127080":{"id":"n2199127080","loc":[-85.6205699,41.9396324]},"n2199127081":{"id":"n2199127081","loc":[-85.6205722,41.939498]},"n2199127082":{"id":"n2199127082","loc":[-85.6204064,41.9394997]},"n2199127083":{"id":"n2199127083","loc":[-85.6204087,41.939561]},"n2199127084":{"id":"n2199127084","loc":[-85.6203103,41.9395618]},"n2199127085":{"id":"n2199127085","loc":[-85.620308,41.9396069]},"n2199127086":{"id":"n2199127086","loc":[-85.6200347,41.9396086]},"n2199127087":{"id":"n2199127087","loc":[-85.6200382,41.9397141]},"n2199127088":{"id":"n2199127088","loc":[-85.6202257,41.9397149]},"n2199127089":{"id":"n2199127089","loc":[-85.6202269,41.9399182]},"n2199127090":{"id":"n2199127090","loc":[-85.6203595,41.9399199]},"n2199127091":{"id":"n2199127091","loc":[-85.6212335,41.939688]},"n2199127092":{"id":"n2199127092","loc":[-85.6212328,41.939595]},"n2199127093":{"id":"n2199127093","loc":[-85.6208807,41.9395966]},"n2199127094":{"id":"n2199127094","loc":[-85.6208815,41.9396896]},"n2199127095":{"id":"n2199127095","loc":[-85.6208676,41.9396872]},"n2199127096":{"id":"n2199127096","loc":[-85.6208583,41.9393539]},"n2199127097":{"id":"n2199127097","loc":[-85.6207006,41.9393563]},"n2199127098":{"id":"n2199127098","loc":[-85.6207099,41.9396896]},"n185967054":{"id":"n185967054","loc":[-85.6173384,41.9356126]},"n185967063":{"id":"n185967063","loc":[-85.617371,41.936243]},"n185967065":{"id":"n185967065","loc":[-85.617337,41.936299]},"n185967068":{"id":"n185967068","loc":[-85.617321,41.936373]},"n185967070":{"id":"n185967070","loc":[-85.6173562,41.9366969]},"n185967074":{"id":"n185967074","loc":[-85.6173635,41.9377414]},"n185967075":{"id":"n185967075","loc":[-85.6173696,41.9381886]},"n185967076":{"id":"n185967076","loc":[-85.617372,41.938535]},"n2199127056":{"id":"n2199127056","loc":[-85.617147,41.9389616]},"n2199127057":{"id":"n2199127057","loc":[-85.6172136,41.9389614]},"n2199127058":{"id":"n2199127058","loc":[-85.6172123,41.9386909]},"n2199127059":{"id":"n2199127059","loc":[-85.616736,41.9386922]},"n2203921041":{"id":"n2203921041","loc":[-85.6173018,41.9346369]},"w203983952":{"id":"w203983952","tags":{"highway":"service"},"nodes":["n2139966627","n1819800319"]},"w209718301":{"id":"w209718301","tags":{"area":"yes","building":"yes"},"nodes":["n2199127051","n2199127052","n2199127053","n2199127054","n2199127055","n2199127056","n2199127057","n2199127058","n2199127059","n2199127060","n2199127061","n2199127062","n2199127051"]},"w209718304":{"id":"w209718304","tags":{"area":"yes","building":"yes"},"nodes":["n2199127071","n2199127072","n2199127073","n2199127074","n2199127071"]},"w17964961":{"id":"w17964961","tags":{"highway":"residential","name":"Whipple St"},"nodes":["n185963099","n185963110"]},"w17964489":{"id":"w17964489","tags":{"highway":"residential","name":"Jackson St"},"nodes":["n185958498","n185958500"]},"w203983953":{"id":"w203983953","tags":{"area":"yes","leisure":"park","name":"Marina Park"},"nodes":["n1475283994","n1475283979","n1475283998","n2139966629","n2139966625","n1819800319","n2139966623","n2139966622","n2139966621","n2139966630","n1475283994"]},"w17965366":{"id":"w17965366","tags":{"highway":"residential","name":"14th St"},"nodes":["n2203921041","n185967054","n185967063","n185967065","n185967068","n185967070","n185967074","n185967075","n185967076","n185967077"]},"w209718306":{"id":"w209718306","tags":{"area":"yes","building":"yes"},"nodes":["n2199127091","n2199127092","n2199127093","n2199127094","n2199127091"]},"w209718307":{"id":"w209718307","tags":{"area":"yes","building":"yes"},"nodes":["n2199127095","n2199127096","n2199127097","n2199127098","n2199127095"]},"w209718305":{"id":"w209718305","tags":{"area":"yes","building":"yes"},"nodes":["n2199127075","n2199127076","n2199127077","n2199127078","n2199127079","n2199127080","n2199127081","n2199127082","n2199127083","n2199127084","n2199127085","n2199127086","n2199127087","n2199127088","n2199127089","n2199127090","n2199127075"]},"n185960199":{"id":"n185960199","loc":[-85.62965,41.95469]},"n185980737":{"id":"n185980737","loc":[-85.629083,41.953725]},"n2114807561":{"id":"n2114807561","loc":[-85.6297681,41.9524688]},"n2114807597":{"id":"n2114807597","loc":[-85.6296517,41.952563]},"n185960197":{"id":"n185960197","loc":[-85.629676,41.9537314]},"n185978791":{"id":"n185978791","loc":[-85.6244542,41.9547066]},"w17967573":{"id":"w17967573","tags":{"highway":"residential","name":"E Wheeler St"},"nodes":["n185960195","n2114807561","n185968102","n185967430","n185986157","n185978392"]},"w17966553":{"id":"w17966553","tags":{"highway":"residential","name":"East Hoffman Street"},"nodes":["n185971631","n185978784","n185967432","n185968106","n185960199","n185978787","n185978790","n185978791"]},"w17966787":{"id":"w17966787","tags":{"highway":"residential","name":"East Cushman Street"},"nodes":["n185980735","n185980737","n185960197","n185968104","n185960792"]},"w17964723":{"id":"w17964723","tags":{"highway":"residential","name":"Cushman Street"},"nodes":["n185960792","n185960794","n185960796"]},"w17964654":{"id":"w17964654","tags":{"highway":"residential","name":"Pine Street"},"nodes":["n185960195","n2114807597","n185960197","n185960199"]},"n1819848862":{"id":"n1819848862","loc":[-85.6346087,41.9545845]},"n1819848935":{"id":"n1819848935","loc":[-85.6345948,41.9537717]},"n1819848973":{"id":"n1819848973","loc":[-85.6334247,41.9537827]},"n1819848997":{"id":"n1819848997","loc":[-85.6334386,41.9545956]},"n2189015861":{"id":"n2189015861","loc":[-85.6375906,41.954836]},"n2189015865":{"id":"n2189015865","loc":[-85.6383307,41.9548291]},"n2189015867":{"id":"n2189015867","loc":[-85.6383337,41.9550072]},"n2189015868":{"id":"n2189015868","loc":[-85.6380986,41.9550094]},"n2189015869":{"id":"n2189015869","loc":[-85.6381005,41.9551226]},"n2199109808":{"id":"n2199109808","loc":[-85.6372702,41.9522894]},"n2199109810":{"id":"n2199109810","loc":[-85.6372677,41.9521583]},"n2199109812":{"id":"n2199109812","loc":[-85.6369505,41.9521617]},"n2199109814":{"id":"n2199109814","loc":[-85.636953,41.9522927]},"n185952156":{"id":"n185952156","loc":[-85.640983,41.9546557]},"n185953423":{"id":"n185953423","loc":[-85.641871,41.954652]},"n185971637":{"id":"n185971637","loc":[-85.641583,41.95465]},"n185971639":{"id":"n185971639","loc":[-85.6421344,41.9546444]},"n185971642":{"id":"n185971642","loc":[-85.6428264,41.9545612]},"n185971648":{"id":"n185971648","loc":[-85.6436023,41.9544262]},"n185975066":{"id":"n185975066","loc":[-85.640532,41.953638]},"n185975067":{"id":"n185975067","loc":[-85.64079,41.953638]},"n185982166":{"id":"n185982166","loc":[-85.6399012,41.9523817]},"n2189015858":{"id":"n2189015858","loc":[-85.6376104,41.9560138]},"n2189015870":{"id":"n2189015870","loc":[-85.6386794,41.9551172]},"n2189015871":{"id":"n2189015871","loc":[-85.6386817,41.955256]},"n2189015873":{"id":"n2189015873","loc":[-85.6385437,41.9552573]},"n2189015876":{"id":"n2189015876","loc":[-85.638555,41.9559278]},"n2189015879":{"id":"n2189015879","loc":[-85.6384954,41.9559283]},"n2189015882":{"id":"n2189015882","loc":[-85.6384965,41.9559935]},"n2189015885":{"id":"n2189015885","loc":[-85.6383533,41.9559949]},"n2189015888":{"id":"n2189015888","loc":[-85.638351,41.9558607]},"n2189015891":{"id":"n2189015891","loc":[-85.6382178,41.9558619]},"n2189015894":{"id":"n2189015894","loc":[-85.6382203,41.956008]},"w208627223":{"id":"w208627223","tags":{"area":"yes","building":"yes"},"nodes":["n2189015858","n2189015861","n2189015865","n2189015867","n2189015868","n2189015869","n2189015870","n2189015871","n2189015873","n2189015876","n2189015879","n2189015882","n2189015885","n2189015888","n2189015891","n2189015894","n2189015858"]},"w170848328":{"id":"w170848328","tags":{"leisure":"park","name":"Bowman Park"},"nodes":["n1819848935","n1819848973","n1819848997","n1819848862","n1819848935"]},"w17965866":{"id":"w17965866","tags":{"highway":"residential","name":"West Hoffman Street"},"nodes":["n185971631","n185971632","n185964359","n185965025","n1475293264","n185952156","n185971637","n185953423","n185971639","n185971642","n185971648"]},"w209717051":{"id":"w209717051","tags":{"amenity":"place_of_worship","area":"yes","building":"yes","denomination":"baptist","name":"Calvary Missionary Baptist Church","religion":"christian"},"nodes":["n2199109808","n2199109810","n2199109812","n2199109814","n2199109808"]},"w17966172":{"id":"w17966172","tags":{"highway":"residential","name":"West Cushman Street"},"nodes":["n185960796","n185975064","n185964358","n185965023","n1475293222","n185975066","n185975067"]},"w17966975":{"id":"w17966975","tags":{"highway":"residential","name":"W Wheeler St"},"nodes":["n185978392","n185982163","n185964357","n185965021","n1475293261","n185982166"]},"n185960684":{"id":"n185960684","loc":[-85.622687,41.951885]},"n185960686":{"id":"n185960686","loc":[-85.622492,41.951901]},"n185978795":{"id":"n185978795","loc":[-85.6240991,41.954708]},"n185978803":{"id":"n185978803","loc":[-85.623348,41.954547]},"n185978806":{"id":"n185978806","loc":[-85.623123,41.954502]},"n185978808":{"id":"n185978808","loc":[-85.622923,41.954469]},"n185978810":{"id":"n185978810","loc":[-85.622787,41.954457]},"n185978811":{"id":"n185978811","loc":[-85.622612,41.954458]},"n185978813":{"id":"n185978813","loc":[-85.622368,41.954472]},"n1819790545":{"id":"n1819790545","loc":[-85.6240295,41.9548949]},"n1819790621":{"id":"n1819790621","loc":[-85.6235789,41.954855]},"n1819790664":{"id":"n1819790664","loc":[-85.6238363,41.9549507]},"n1819790683":{"id":"n1819790683","loc":[-85.6224727,41.9545921]},"n1819790730":{"id":"n1819790730","loc":[-85.6227527,41.9545795]},"n1819790740":{"id":"n1819790740","loc":[-85.6240402,41.9550784]},"n1819790831":{"id":"n1819790831","loc":[-85.624126,41.9549986]},"n1819790861":{"id":"n1819790861","loc":[-85.6231712,41.9546872]},"n1819790887":{"id":"n1819790887","loc":[-85.6242762,41.955206]},"n2168544739":{"id":"n2168544739","loc":[-85.6249102,41.952801]},"n2168544740":{"id":"n2168544740","loc":[-85.6251859,41.9527564]},"n2168544741":{"id":"n2168544741","loc":[-85.6255515,41.9527921]},"n2168544742":{"id":"n2168544742","loc":[-85.626001,41.9529481]},"n2168544743":{"id":"n2168544743","loc":[-85.6265284,41.9529838]},"n2168544744":{"id":"n2168544744","loc":[-85.626942,41.9528857]},"n2168544745":{"id":"n2168544745","loc":[-85.6270918,41.9526851]},"n2168544746":{"id":"n2168544746","loc":[-85.6272117,41.95244]},"n2168544747":{"id":"n2168544747","loc":[-85.6271578,41.952226]},"n2168544748":{"id":"n2168544748","loc":[-85.6270019,41.9519719]},"n2168544749":{"id":"n2168544749","loc":[-85.6268221,41.9518382]},"n2168544750":{"id":"n2168544750","loc":[-85.6265284,41.951807]},"n2168544751":{"id":"n2168544751","loc":[-85.6256534,41.9518516]},"n2168544752":{"id":"n2168544752","loc":[-85.6253477,41.9518338]},"n2168544753":{"id":"n2168544753","loc":[-85.6251139,41.9517669]},"n185955747":{"id":"n185955747","loc":[-85.620674,41.954709]},"n185960688":{"id":"n185960688","loc":[-85.621032,41.951913]},"n185972054":{"id":"n185972054","loc":[-85.6186728,41.9547335]},"n185978814":{"id":"n185978814","loc":[-85.6201708,41.9547403]},"n1819790532":{"id":"n1819790532","loc":[-85.6244908,41.9555731]},"n1819790536":{"id":"n1819790536","loc":[-85.6217925,41.9583135]},"n1819790538":{"id":"n1819790538","loc":[-85.6233954,41.9600014]},"n1819790539":{"id":"n1819790539","loc":[-85.6204611,41.9562117]},"n1819790546":{"id":"n1819790546","loc":[-85.6210898,41.9567657]},"n1819790548":{"id":"n1819790548","loc":[-85.6202465,41.9562237]},"n1819790550":{"id":"n1819790550","loc":[-85.6250165,41.9560677]},"n1819790551":{"id":"n1819790551","loc":[-85.6227946,41.9597023]},"n1819790553":{"id":"n1819790553","loc":[-85.6215726,41.9584571]},"n1819790556":{"id":"n1819790556","loc":[-85.6196306,41.9573002]},"n1819790557":{"id":"n1819790557","loc":[-85.6209503,41.9563109]},"n1819790558":{"id":"n1819790558","loc":[-85.6196939,41.9574085]},"n1819790561":{"id":"n1819790561","loc":[-85.621079,41.957751]},"n1819790562":{"id":"n1819790562","loc":[-85.6224255,41.9611417]},"n1819790565":{"id":"n1819790565","loc":[-85.6232506,41.9604841]},"n1819790566":{"id":"n1819790566","loc":[-85.6190835,41.9562909]},"n1819790567":{"id":"n1819790567","loc":[-85.622227,41.9593028]},"n1819790569":{"id":"n1819790569","loc":[-85.620976,41.9591039]},"n1819790571":{"id":"n1819790571","loc":[-85.6212078,41.9565303]},"n1819790572":{"id":"n1819790572","loc":[-85.6235306,41.9595102]},"n1819790581":{"id":"n1819790581","loc":[-85.6235563,41.9579351]},"n1819790584":{"id":"n1819790584","loc":[-85.6230371,41.9574598]},"n1819790586":{"id":"n1819790586","loc":[-85.6211748,41.9564272]},"n1819790588":{"id":"n1819790588","loc":[-85.6226508,41.9601086]},"n1819790591":{"id":"n1819790591","loc":[-85.6218032,41.9607468]},"n1819790593":{"id":"n1819790593","loc":[-85.6207915,41.9618735]},"n1819790596":{"id":"n1819790596","loc":[-85.6252955,41.9567858]},"n1819790598":{"id":"n1819790598","loc":[-85.6196618,41.9568939]},"n1819790600":{"id":"n1819790600","loc":[-85.6224416,41.9587084]},"n1819790602":{"id":"n1819790602","loc":[-85.6217442,41.9558641]},"n1819790603":{"id":"n1819790603","loc":[-85.6213355,41.9592116]},"n1819790604":{"id":"n1819790604","loc":[-85.622801,41.9573042]},"n1819790608":{"id":"n1819790608","loc":[-85.6199729,41.9574325]},"n1819790610":{"id":"n1819790610","loc":[-85.6195555,41.9557165]},"n1819790611":{"id":"n1819790611","loc":[-85.622978,41.9586007]},"n1819790613":{"id":"n1819790613","loc":[-85.6253963,41.9562636]},"n1819790614":{"id":"n1819790614","loc":[-85.6235252,41.9580342]},"n1819790616":{"id":"n1819790616","loc":[-85.6232988,41.9596305]},"n1819790617":{"id":"n1819790617","loc":[-85.6226776,41.9598732]},"n1819790619":{"id":"n1819790619","loc":[-85.625553,41.9561794]},"n1819790620":{"id":"n1819790620","loc":[-85.6235574,41.959231]},"n1819790624":{"id":"n1819790624","loc":[-85.6228429,41.9573726]},"n1819790626":{"id":"n1819790626","loc":[-85.6193785,41.9556766]},"n1819790628":{"id":"n1819790628","loc":[-85.620092,41.9554253]},"n1819790630":{"id":"n1819790630","loc":[-85.6226658,41.9604402]},"n1819790638":{"id":"n1819790638","loc":[-85.6219964,41.9602561]},"n1819790640":{"id":"n1819790640","loc":[-85.6232731,41.9599969]},"n1819790643":{"id":"n1819790643","loc":[-85.6247698,41.9568895]},"n1819790650":{"id":"n1819790650","loc":[-85.6216412,41.9550149]},"n1819790652":{"id":"n1819790652","loc":[-85.6224952,41.9603918]},"n1819790656":{"id":"n1819790656","loc":[-85.61918,41.9555649]},"n1819790661":{"id":"n1819790661","loc":[-85.6200169,41.955505]},"n1819790662":{"id":"n1819790662","loc":[-85.6217389,41.9563149]},"n1819790666":{"id":"n1819790666","loc":[-85.6229566,41.9598373]},"n1819790667":{"id":"n1819790667","loc":[-85.6209117,41.9609189]},"n1819790669":{"id":"n1819790669","loc":[-85.6252311,41.9562353]},"n1819790670":{"id":"n1819790670","loc":[-85.6209758,41.961868]},"n1819790672":{"id":"n1819790672","loc":[-85.6209557,41.9589078]},"n1819790673":{"id":"n1819790673","loc":[-85.6190352,41.9561393]},"n1819790675":{"id":"n1819790675","loc":[-85.6236432,41.9586685]},"n1819790676":{"id":"n1819790676","loc":[-85.6194901,41.9565389]},"n1819790678":{"id":"n1819790678","loc":[-85.6219266,41.9582417]},"n1819790680":{"id":"n1819790680","loc":[-85.6208258,41.9557211]},"n1819790681":{"id":"n1819790681","loc":[-85.6212024,41.9613212]},"n1819790682":{"id":"n1819790682","loc":[-85.624877,41.9559401]},"n1819790684":{"id":"n1819790684","loc":[-85.6206499,41.9583693]},"n1819790699":{"id":"n1819790699","loc":[-85.6215243,41.956279]},"n1819790701":{"id":"n1819790701","loc":[-85.6246625,41.9559321]},"n1819790703":{"id":"n1819790703","loc":[-85.6230478,41.9585089]},"n1819790708":{"id":"n1819790708","loc":[-85.6211102,41.9575402]},"n1819790710":{"id":"n1819790710","loc":[-85.6215082,41.9548468]},"n1819790711":{"id":"n1819790711","loc":[-85.6206552,41.9586007]},"n1819790713":{"id":"n1819790713","loc":[-85.6215404,41.9549705]},"n1819790715":{"id":"n1819790715","loc":[-85.6216906,41.955521]},"n1819790717":{"id":"n1819790717","loc":[-85.6215404,41.9547391]},"n1819790722":{"id":"n1819790722","loc":[-85.6219964,41.9599131]},"n1819790723":{"id":"n1819790723","loc":[-85.622286,41.9606989]},"n1819790725":{"id":"n1819790725","loc":[-85.6228439,41.9572005]},"n1819790727":{"id":"n1819790727","loc":[-85.6202518,41.9554458]},"n1819790728":{"id":"n1819790728","loc":[-85.623434,41.9575276]},"n1819790729":{"id":"n1819790729","loc":[-85.6234287,41.9568576]},"n1819790732":{"id":"n1819790732","loc":[-85.6229566,41.9571369]},"n1819790733":{"id":"n1819790733","loc":[-85.6225543,41.9590275]},"n1819790734":{"id":"n1819790734","loc":[-85.6232892,41.9583135]},"n1819790736":{"id":"n1819790736","loc":[-85.622977,41.9608551]},"n1819790737":{"id":"n1819790737","loc":[-85.624008,41.9569533]},"n1819790741":{"id":"n1819790741","loc":[-85.6212775,41.9608545]},"n1819790742":{"id":"n1819790742","loc":[-85.6231282,41.9569932]},"n1819790743":{"id":"n1819790743","loc":[-85.6224523,41.9591831]},"n1819790744":{"id":"n1819790744","loc":[-85.6210951,41.9610819]},"n1819790745":{"id":"n1819790745","loc":[-85.6220114,41.960544]},"n1819790755":{"id":"n1819790755","loc":[-85.6216369,41.9553854]},"n1819790757":{"id":"n1819790757","loc":[-85.6209986,41.9592709]},"n1819790758":{"id":"n1819790758","loc":[-85.6200437,41.9563468]},"n1819790764":{"id":"n1819790764","loc":[-85.6219363,41.9596823]},"n1819790765":{"id":"n1819790765","loc":[-85.6237612,41.9568496]},"n1819790769":{"id":"n1819790769","loc":[-85.6212389,41.9593433]},"n1819790771":{"id":"n1819790771","loc":[-85.6210726,41.9560123]},"n1819790772":{"id":"n1819790772","loc":[-85.6212711,41.9561838]},"n1819790776":{"id":"n1819790776","loc":[-85.6234437,41.9577795]},"n1819790777":{"id":"n1819790777","loc":[-85.6212502,41.9618599]},"n1819790783":{"id":"n1819790783","loc":[-85.6216895,41.9610585]},"n1819790784":{"id":"n1819790784","loc":[-85.6200115,41.9556367]},"n1819790785":{"id":"n1819790785","loc":[-85.6210576,41.9573002]},"n1819790786":{"id":"n1819790786","loc":[-85.621138,41.9576632]},"n1819790788":{"id":"n1819790788","loc":[-85.6207733,41.9578946]},"n1819790789":{"id":"n1819790789","loc":[-85.6200705,41.9571566]},"n1819790790":{"id":"n1819790790","loc":[-85.6245337,41.9558443]},"n1819790792":{"id":"n1819790792","loc":[-85.621932,41.9608066]},"n1819790793":{"id":"n1819790793","loc":[-85.6233578,41.9581385]},"n1819790794":{"id":"n1819790794","loc":[-85.6204557,41.9555136]},"n1819790797":{"id":"n1819790797","loc":[-85.6235038,41.9576074]},"n1819790800":{"id":"n1819790800","loc":[-85.6214438,41.9607508]},"n1819790801":{"id":"n1819790801","loc":[-85.623492,41.9602129]},"n1819790802":{"id":"n1819790802","loc":[-85.6216691,41.9546553]},"n1819790803":{"id":"n1819790803","loc":[-85.6231057,41.9586851]},"n1819790804":{"id":"n1819790804","loc":[-85.6209224,41.9578673]},"n1819790813":{"id":"n1819790813","loc":[-85.620092,41.9572962]},"n1819790814":{"id":"n1819790814","loc":[-85.6216691,41.9552218]},"n1819790816":{"id":"n1819790816","loc":[-85.6216144,41.9609668]},"n1819790818":{"id":"n1819790818","loc":[-85.6216906,41.9557324]},"n1819790820":{"id":"n1819790820","loc":[-85.6192069,41.9564186]},"n1819790823":{"id":"n1819790823","loc":[-85.6211155,41.9566027]},"n1819790825":{"id":"n1819790825","loc":[-85.6233106,41.9569294]},"n1819790839":{"id":"n1819790839","loc":[-85.625671,41.9564986]},"n1819790842":{"id":"n1819790842","loc":[-85.6235252,41.9567379]},"n1819790844":{"id":"n1819790844","loc":[-85.6253813,41.9566342]},"n1819790847":{"id":"n1819790847","loc":[-85.6200963,41.9567702]},"n1819790849":{"id":"n1819790849","loc":[-85.6238031,41.9587449]},"n1819790851":{"id":"n1819790851","loc":[-85.6234984,41.9584571]},"n1819790856":{"id":"n1819790856","loc":[-85.6242226,41.9570092]},"n1819790865":{"id":"n1819790865","loc":[-85.6200265,41.9569458]},"n1819790869":{"id":"n1819790869","loc":[-85.6230049,41.9601245]},"n1819790871":{"id":"n1819790871","loc":[-85.6190727,41.9558322]},"n1819790873":{"id":"n1819790873","loc":[-85.6217442,41.9550104]},"n1819790875":{"id":"n1819790875","loc":[-85.6208044,41.9587808]},"n1819790879":{"id":"n1819790879","loc":[-85.6198444,41.9574484]},"n1819790883":{"id":"n1819790883","loc":[-85.623713,41.9588719]},"n1819790885":{"id":"n1819790885","loc":[-85.6223289,41.9605075]},"n1819790889":{"id":"n1819790889","loc":[-85.6208044,41.9562437]},"n1819790893":{"id":"n1819790893","loc":[-85.6218183,41.9559684]},"n1819790906":{"id":"n1819790906","loc":[-85.6214052,41.958697]},"n1819790913":{"id":"n1819790913","loc":[-85.6209981,41.9609957]},"n1819790917":{"id":"n1819790917","loc":[-85.6216208,41.9604436]},"n1819790919":{"id":"n1819790919","loc":[-85.6209406,41.9616373]},"n1819790920":{"id":"n1819790920","loc":[-85.6221948,41.9583334]},"n1819790922":{"id":"n1819790922","loc":[-85.6216681,41.9615292]},"n1819790924":{"id":"n1819790924","loc":[-85.6210147,41.9570489]},"n1819790929":{"id":"n1819790929","loc":[-85.6193678,41.955521]},"w17964707":{"id":"w17964707","tags":{"highway":"residential","name":"11th Ave"},"nodes":["n185960682","n185960684","n185960686","n185960688","n185960690"]},"w201484345":{"id":"w201484345","tags":{"bridge":"yes","highway":"residential","name":"E Hoffman St"},"nodes":["n185978791","n185978795"]},"w201484348":{"id":"w201484348","tags":{"highway":"residential","name":"E Hoffman St"},"nodes":["n185978795","n185978800","n185978803","n185978806","n185978808","n185978810","n185978811","n185978813","n185955747","n185978814","n185972054","n185978817"]},"w170843845":{"id":"w170843845","tags":{"landuse":"reservoir","name":"Hoffman Pond","natural":"water"},"nodes":["n1819790732","n1819790742","n1819790825","n1819790729","n1819790842","n1819790765","n1819790737","n1819790856","n1819790643","n1819790596","n1819790844","n1819790839","n1819849190","n1819790619","n1819790613","n1819790669","n1819790550","n1819790682","n1819790701","n1819790790","n1819790532","n1819790887","n1819790740","n1819790831","n1819790545","n1819790664","n1819790621","n1819790861","n1819790730","n1819790683","n1819790802","n1819790717","n1819790710","n1819790713","n1819790650","n1819790873","n1819790814","n1819790755","n1819790715","n1819790818","n1819790602","n1819790893","n1819790662","n1819790699","n1819790772","n1819790771","n1819790680","n1819790794","n1819790727","n1819790628","n1819790661","n1819790784","n1819790610","n1819790626","n1819790929","n1819790656","n1819790871","n1819790673","n1819790566","n1819790820","n1819790676","n1819790598","n1819790556","n1819790558","n1819790879","n1819790608","n1819790813","n1819790789","n1819790865","n1819790847","n1819790758","n1819790548","n1819790539","n1819790889","n1819790557","n1819790586","n1819790571","n1819790823","n1819790546","n1819790924","n1819790785","n1819790708","n1819790786","n1819790561","n1819790804","n1819790788","n1819790684","n1819790711","n1819790875","n1819790672","n1819790569","n1819790757","n1819790769","n1819790603","n1819790906","n1819790553","n1819790536","n1819790678","n1819790920","n1819790600","n1819790733","n1819790743","n1819790567","n1819790764","n1819790722","n1819790638","n1819790917","n1819790800","n1819790741","n1819790667","n1819790913","n1819790744","n1819790816","n1819790591","n1819790745","n1819790885","n1819790652","n1819790588","n1819790617","n1819790551","n1819790666","n1819790869","n1819790630","n1819790723","n1819790792","n1819790783","n1819790681","n1819790919","n1819790593","n1819790670","n1819790777","n1819790922","n1819790562","n1819790736","n1819790565","n1819790801","n1819790538","n1819790640","n1819790616","n1819790572","n1819790620","n1819790883","n1819790849","n1819790675","n1819790851","n1819790803","n1819790611","n1819790703","n1819790734","n1819790793","n1819790614","n1819790581","n1819790776","n1819790797","n1819790728","n1819790584","n1819790624","n1819790604","n1819790725","n1819790732"]},"w206805240":{"id":"w206805240","tags":{"waterway":"river"},"nodes":["n2168544738","n2168544739","n2168544740","n2168544741","n2168544742","n2168544743","n2168544744","n2168544745","n2168544746","n2168544747","n2168544748","n2168544749","n2168544750","n2168544751","n2168544752","n2168544753","n1819848944"]},"n394490429":{"id":"n394490429","loc":[-85.643883,41.954365]},"n185953421":{"id":"n185953421","loc":[-85.641876,41.954946]},"n185953417":{"id":"n185953417","loc":[-85.6418306,41.9551597]},"n185977233":{"id":"n185977233","loc":[-85.642987,41.95486]},"n185977232":{"id":"n185977232","loc":[-85.642894,41.9547842]},"n1475293244":{"id":"n1475293244","loc":[-85.63974,41.9521543]},"n1819848890":{"id":"n1819848890","loc":[-85.6410004,41.9552822]},"n1819848965":{"id":"n1819848965","loc":[-85.6409795,41.9553892]},"n2189015846":{"id":"n2189015846","loc":[-85.6420457,41.9549528]},"n2189015849":{"id":"n2189015849","loc":[-85.6425867,41.9551392]},"n2189015852":{"id":"n2189015852","loc":[-85.6426877,41.9549771]},"n2199109816":{"id":"n2199109816","loc":[-85.6399215,41.9540925]},"n2199109818":{"id":"n2199109818","loc":[-85.6399182,41.9538236]},"n2199109820":{"id":"n2199109820","loc":[-85.6402201,41.9538216]},"n2199109822":{"id":"n2199109822","loc":[-85.640222,41.9539771]},"n2199109825":{"id":"n2199109825","loc":[-85.6402904,41.9539766]},"n2199109827":{"id":"n2199109827","loc":[-85.6402918,41.95409]},"n2199109829":{"id":"n2199109829","loc":[-85.6395845,41.9544626]},"n2199109831":{"id":"n2199109831","loc":[-85.6395792,41.9540671]},"n2199109833":{"id":"n2199109833","loc":[-85.6397173,41.9540661]},"n2199109835":{"id":"n2199109835","loc":[-85.6397226,41.9544616]},"n2199109837":{"id":"n2199109837","loc":[-85.6399641,41.9545058]},"n2199109839":{"id":"n2199109839","loc":[-85.6399637,41.9541859]},"n2199109841":{"id":"n2199109841","loc":[-85.6401098,41.9541858]},"n2199109843":{"id":"n2199109843","loc":[-85.64011,41.9543272]},"n2199109845":{"id":"n2199109845","loc":[-85.6400783,41.9543273]},"n2199109847":{"id":"n2199109847","loc":[-85.6400785,41.9545058]},"n2199109853":{"id":"n2199109853","loc":[-85.6396184,41.9554049]},"n2199109855":{"id":"n2199109855","loc":[-85.6396825,41.9553713]},"n185949745":{"id":"n185949745","loc":[-85.6442727,41.9553112]},"n185949748":{"id":"n185949748","loc":[-85.6448804,41.9555238]},"n185949755":{"id":"n185949755","loc":[-85.6420011,41.9603536]},"n185949763":{"id":"n185949763","loc":[-85.6408843,41.9555822]},"n185949765":{"id":"n185949765","loc":[-85.6414548,41.9557751]},"n185952158":{"id":"n185952158","loc":[-85.640066,41.956854]},"n185952160":{"id":"n185952160","loc":[-85.639848,41.957229]},"n185952161":{"id":"n185952161","loc":[-85.6396089,41.9576192]},"n185952163":{"id":"n185952163","loc":[-85.63892,41.957957]},"n185953413":{"id":"n185953413","loc":[-85.64162,41.955475]},"n185971651":{"id":"n185971651","loc":[-85.6440766,41.9543462]},"n185977234":{"id":"n185977234","loc":[-85.645044,41.955581]},"n394490395":{"id":"n394490395","loc":[-85.657336,41.936762]},"n394490396":{"id":"n394490396","loc":[-85.653896,41.936978]},"n394490397":{"id":"n394490397","loc":[-85.653732,41.937386]},"n394490398":{"id":"n394490398","loc":[-85.65182,41.937378]},"n394490399":{"id":"n394490399","loc":[-85.651843,41.938445]},"n394490400":{"id":"n394490400","loc":[-85.652536,41.938447]},"n394490401":{"id":"n394490401","loc":[-85.652533,41.938901]},"n394490402":{"id":"n394490402","loc":[-85.652084,41.9389]},"n394490403":{"id":"n394490403","loc":[-85.6521,41.939627]},"n394490404":{"id":"n394490404","loc":[-85.652301,41.939628]},"n394490405":{"id":"n394490405","loc":[-85.652302,41.939755]},"n394490406":{"id":"n394490406","loc":[-85.652783,41.939747]},"n394490407":{"id":"n394490407","loc":[-85.652835,41.94112]},"n394490408":{"id":"n394490408","loc":[-85.651968,41.941123]},"n394490409":{"id":"n394490409","loc":[-85.651983,41.941969]},"n394490410":{"id":"n394490410","loc":[-85.652908,41.941961]},"n394490411":{"id":"n394490411","loc":[-85.65292,41.94278]},"n394490412":{"id":"n394490412","loc":[-85.651698,41.942816]},"n394490413":{"id":"n394490413","loc":[-85.651509,41.942823]},"n394490414":{"id":"n394490414","loc":[-85.651272,41.942837]},"n394490415":{"id":"n394490415","loc":[-85.651272,41.943325]},"n394490416":{"id":"n394490416","loc":[-85.65122,41.944053]},"n394490417":{"id":"n394490417","loc":[-85.651193,41.944449]},"n394490418":{"id":"n394490418","loc":[-85.651088,41.944969]},"n394490419":{"id":"n394490419","loc":[-85.650949,41.945554]},"n394490420":{"id":"n394490420","loc":[-85.650907,41.945719]},"n394490421":{"id":"n394490421","loc":[-85.650808,41.946016]},"n394490422":{"id":"n394490422","loc":[-85.650712,41.946516]},"n394490423":{"id":"n394490423","loc":[-85.650493,41.947166]},"n394490424":{"id":"n394490424","loc":[-85.650626,41.947213]},"n394490425":{"id":"n394490425","loc":[-85.650201,41.948109]},"n394490426":{"id":"n394490426","loc":[-85.649868,41.948797]},"n394490427":{"id":"n394490427","loc":[-85.649669,41.949161]},"n394490428":{"id":"n394490428","loc":[-85.64659,41.954067]},"n394490430":{"id":"n394490430","loc":[-85.644034,41.95444]},"n394490431":{"id":"n394490431","loc":[-85.644248,41.954507]},"n394490432":{"id":"n394490432","loc":[-85.64491,41.954481]},"n394490433":{"id":"n394490433","loc":[-85.645213,41.954433]},"n394490434":{"id":"n394490434","loc":[-85.645426,41.954477]},"n394490435":{"id":"n394490435","loc":[-85.6458,41.954704]},"n394490436":{"id":"n394490436","loc":[-85.64605,41.954804]},"n394490437":{"id":"n394490437","loc":[-85.646125,41.954817]},"n394490438":{"id":"n394490438","loc":[-85.646002,41.954997]},"n394490439":{"id":"n394490439","loc":[-85.645764,41.955366]},"n394490440":{"id":"n394490440","loc":[-85.645525,41.955734]},"n394490441":{"id":"n394490441","loc":[-85.64443,41.957424]},"n394490442":{"id":"n394490442","loc":[-85.641712,41.961723]},"n394490443":{"id":"n394490443","loc":[-85.640747,41.963246]},"n394490444":{"id":"n394490444","loc":[-85.637803,41.967894]},"n394490445":{"id":"n394490445","loc":[-85.637673,41.967861]},"n394490446":{"id":"n394490446","loc":[-85.636637,41.969275]},"n394490447":{"id":"n394490447","loc":[-85.634923,41.969269]},"n394490448":{"id":"n394490448","loc":[-85.634893,41.968537]},"n394490449":{"id":"n394490449","loc":[-85.634544,41.96927]},"n394490450":{"id":"n394490450","loc":[-85.630835,41.969274]},"n394490451":{"id":"n394490451","loc":[-85.630834,41.968348]},"n394490452":{"id":"n394490452","loc":[-85.630857,41.968179]},"n394490453":{"id":"n394490453","loc":[-85.630924,41.968044]},"n394490454":{"id":"n394490454","loc":[-85.631004,41.967925]},"n394490455":{"id":"n394490455","loc":[-85.631143,41.967811]},"n394490456":{"id":"n394490456","loc":[-85.631311,41.967736]},"n394490457":{"id":"n394490457","loc":[-85.631595,41.967693]},"n394490458":{"id":"n394490458","loc":[-85.63325,41.967702]},"n394490459":{"id":"n394490459","loc":[-85.633247,41.967021]},"n394490460":{"id":"n394490460","loc":[-85.634858,41.967021]},"n394490461":{"id":"n394490461","loc":[-85.634865,41.967711]},"n394490462":{"id":"n394490462","loc":[-85.634884,41.968231]},"n394490463":{"id":"n394490463","loc":[-85.636559,41.963867]},"n394490464":{"id":"n394490464","loc":[-85.634832,41.963866]},"n394490465":{"id":"n394490465","loc":[-85.63481,41.961899]},"n394490466":{"id":"n394490466","loc":[-85.637219,41.961842]},"n394490467":{"id":"n394490467","loc":[-85.637837,41.960019]},"n394490468":{"id":"n394490468","loc":[-85.637459,41.960022]},"n394490469":{"id":"n394490469","loc":[-85.635295,41.959987]},"n394490470":{"id":"n394490470","loc":[-85.634783,41.959979]},"n394490471":{"id":"n394490471","loc":[-85.634776,41.959834]},"n394490472":{"id":"n394490472","loc":[-85.634767,41.959009]},"n394490473":{"id":"n394490473","loc":[-85.634763,41.958292]},"n394490474":{"id":"n394490474","loc":[-85.633346,41.958287]},"n394490475":{"id":"n394490475","loc":[-85.632128,41.9583]},"n394490476":{"id":"n394490476","loc":[-85.631414,41.958318]},"n394490477":{"id":"n394490477","loc":[-85.63137,41.959033]},"n394490478":{"id":"n394490478","loc":[-85.631325,41.959753]},"n394490479":{"id":"n394490479","loc":[-85.631494,41.95977]},"n394490480":{"id":"n394490480","loc":[-85.631456,41.960673]},"n394490481":{"id":"n394490481","loc":[-85.631421,41.961494]},"n394490482":{"id":"n394490482","loc":[-85.631404,41.961887]},"n394490483":{"id":"n394490483","loc":[-85.631401,41.961968]},"n394490484":{"id":"n394490484","loc":[-85.630962,41.961967]},"n394490485":{"id":"n394490485","loc":[-85.6299,41.961973]},"n394490486":{"id":"n394490486","loc":[-85.624929,41.962002]},"n394490487":{"id":"n394490487","loc":[-85.623333,41.961987]},"n394490488":{"id":"n394490488","loc":[-85.621894,41.963956]},"n394490489":{"id":"n394490489","loc":[-85.62131,41.963727]},"n394490490":{"id":"n394490490","loc":[-85.621216,41.963868]},"n394490491":{"id":"n394490491","loc":[-85.620356,41.965119]},"n394490492":{"id":"n394490492","loc":[-85.620848,41.965341]},"n394490493":{"id":"n394490493","loc":[-85.620684,41.965558]},"n394490494":{"id":"n394490494","loc":[-85.620621,41.965658]},"n394490495":{"id":"n394490495","loc":[-85.618165,41.965759]},"n394490496":{"id":"n394490496","loc":[-85.618071,41.965759]},"n394490497":{"id":"n394490497","loc":[-85.617986,41.965759]},"n394490498":{"id":"n394490498","loc":[-85.605673,41.965764]},"n394490499":{"id":"n394490499","loc":[-85.605668,41.963548]},"n394490500":{"id":"n394490500","loc":[-85.605664,41.962094]},"n394490501":{"id":"n394490501","loc":[-85.595828,41.962159]},"n394490502":{"id":"n394490502","loc":[-85.587869,41.962169]},"n394490503":{"id":"n394490503","loc":[-85.586289,41.962179]},"n394490504":{"id":"n394490504","loc":[-85.583774,41.962178]},"n394490505":{"id":"n394490505","loc":[-85.583774,41.961789]},"n394490506":{"id":"n394490506","loc":[-85.581303,41.961783]},"n394490507":{"id":"n394490507","loc":[-85.581304,41.961616]},"n394490508":{"id":"n394490508","loc":[-85.581292,41.961616]},"n394490509":{"id":"n394490509","loc":[-85.581247,41.959244]},"n394490510":{"id":"n394490510","loc":[-85.581245,41.958394]},"n394490511":{"id":"n394490511","loc":[-85.581276,41.958372]},"n394490512":{"id":"n394490512","loc":[-85.581302,41.958353]},"n394490513":{"id":"n394490513","loc":[-85.581376,41.9583]},"n394490514":{"id":"n394490514","loc":[-85.582256,41.957663]},"n394490515":{"id":"n394490515","loc":[-85.585299,41.955483]},"n394490516":{"id":"n394490516","loc":[-85.585588,41.955331]},"n394490517":{"id":"n394490517","loc":[-85.586053,41.955163]},"n394490518":{"id":"n394490518","loc":[-85.58632,41.955076]},"n394490519":{"id":"n394490519","loc":[-85.586478,41.955025]},"n394490520":{"id":"n394490520","loc":[-85.58692,41.954947]},"n394490521":{"id":"n394490521","loc":[-85.587327,41.954914]},"n394490522":{"id":"n394490522","loc":[-85.587345,41.954913]},"n394490523":{"id":"n394490523","loc":[-85.587358,41.954913]},"n394490524":{"id":"n394490524","loc":[-85.58963,41.954877]},"n394490525":{"id":"n394490525","loc":[-85.591077,41.954865]},"n394490526":{"id":"n394490526","loc":[-85.594824,41.954843]},"n394490527":{"id":"n394490527","loc":[-85.594804,41.95331]},"n394490528":{"id":"n394490528","loc":[-85.599336,41.95331]},"n394490529":{"id":"n394490529","loc":[-85.599336,41.954825]},"n394490530":{"id":"n394490530","loc":[-85.597828,41.954839]},"n394490531":{"id":"n394490531","loc":[-85.597833,41.95614]},"n394490532":{"id":"n394490532","loc":[-85.596586,41.956151]},"n394490533":{"id":"n394490533","loc":[-85.596586,41.956394]},"n394490534":{"id":"n394490534","loc":[-85.595933,41.956394]},"n394490535":{"id":"n394490535","loc":[-85.595933,41.958176]},"n394490536":{"id":"n394490536","loc":[-85.597635,41.958179]},"n394490537":{"id":"n394490537","loc":[-85.597717,41.958177]},"n394490538":{"id":"n394490538","loc":[-85.601671,41.958194]},"n394490539":{"id":"n394490539","loc":[-85.605619,41.958194]},"n394490540":{"id":"n394490540","loc":[-85.608054,41.958187]},"n394490542":{"id":"n394490542","loc":[-85.6080762,41.9547864]},"n394490545":{"id":"n394490545","loc":[-85.6104354,41.9548263]},"n394490546":{"id":"n394490546","loc":[-85.610274,41.951106]},"n394490547":{"id":"n394490547","loc":[-85.610278,41.950829]},"n394490548":{"id":"n394490548","loc":[-85.610309,41.948377]},"n394490549":{"id":"n394490549","loc":[-85.610314,41.947986]},"n394490550":{"id":"n394490550","loc":[-85.610464,41.947985]},"n394490551":{"id":"n394490551","loc":[-85.610447,41.947468]},"n394490552":{"id":"n394490552","loc":[-85.612469,41.947471]},"n394490553":{"id":"n394490553","loc":[-85.612494,41.945576]},"n394490554":{"id":"n394490554","loc":[-85.610292,41.94558]},"n394490555":{"id":"n394490555","loc":[-85.608412,41.945625]},"n394490556":{"id":"n394490556","loc":[-85.608412,41.943036]},"n394490557":{"id":"n394490557","loc":[-85.608702,41.943087]},"n394490558":{"id":"n394490558","loc":[-85.609196,41.943224]},"n394490559":{"id":"n394490559","loc":[-85.609571,41.943263]},"n394490560":{"id":"n394490560","loc":[-85.610116,41.943295]},"n394490561":{"id":"n394490561","loc":[-85.610273,41.943275]},"n394490562":{"id":"n394490562","loc":[-85.611339,41.943075]},"n394490563":{"id":"n394490563","loc":[-85.611575,41.942997]},"n394490564":{"id":"n394490564","loc":[-85.611847,41.942849]},"n394490565":{"id":"n394490565","loc":[-85.612164,41.942568]},"n394490566":{"id":"n394490566","loc":[-85.612341,41.942529]},"n394490567":{"id":"n394490567","loc":[-85.612562,41.942524]},"n394490568":{"id":"n394490568","loc":[-85.612768,41.942546]},"n394490569":{"id":"n394490569","loc":[-85.612938,41.942633]},"n394490570":{"id":"n394490570","loc":[-85.6131,41.942782]},"n394490571":{"id":"n394490571","loc":[-85.613299,41.942919]},"n394490572":{"id":"n394490572","loc":[-85.613498,41.942996]},"n394490573":{"id":"n394490573","loc":[-85.614698,41.942842]},"n394490574":{"id":"n394490574","loc":[-85.615288,41.942698]},"n394490575":{"id":"n394490575","loc":[-85.616054,41.942693]},"n394490576":{"id":"n394490576","loc":[-85.61603,41.942175]},"n394490577":{"id":"n394490577","loc":[-85.616004,41.941741]},"n394490578":{"id":"n394490578","loc":[-85.615994,41.940156]},"n394490579":{"id":"n394490579","loc":[-85.615144,41.940159]},"n394490580":{"id":"n394490580","loc":[-85.614915,41.940161]},"n394490582":{"id":"n394490582","loc":[-85.614875,41.938532]},"n394490583":{"id":"n394490583","loc":[-85.616167,41.938787]},"n394490585":{"id":"n394490585","loc":[-85.616176,41.938589]},"n394490586":{"id":"n394490586","loc":[-85.614537,41.938282]},"n394490588":{"id":"n394490588","loc":[-85.610141,41.937459]},"n394490589":{"id":"n394490589","loc":[-85.610172,41.937298]},"n394490590":{"id":"n394490590","loc":[-85.609918,41.935495]},"n394490592":{"id":"n394490592","loc":[-85.610092,41.935451]},"n394490594":{"id":"n394490594","loc":[-85.610681,41.935247]},"n394490595":{"id":"n394490595","loc":[-85.611446,41.934955]},"n394490596":{"id":"n394490596","loc":[-85.612057,41.934696]},"n394490598":{"id":"n394490598","loc":[-85.613256,41.934084]},"n394490599":{"id":"n394490599","loc":[-85.613948,41.933682]},"n394490601":{"id":"n394490601","loc":[-85.61436,41.933417]},"n394490602":{"id":"n394490602","loc":[-85.614638,41.933212]},"n394490604":{"id":"n394490604","loc":[-85.615249,41.9332]},"n394490605":{"id":"n394490605","loc":[-85.618218,41.933223]},"n394490607":{"id":"n394490607","loc":[-85.618241,41.933479]},"n394490608":{"id":"n394490608","loc":[-85.618257,41.93365]},"n394490609":{"id":"n394490609","loc":[-85.618298,41.935067]},"n394490611":{"id":"n394490611","loc":[-85.619791,41.935067]},"n394490612":{"id":"n394490612","loc":[-85.619794,41.933301]},"n394490613":{"id":"n394490613","loc":[-85.619795,41.932692]},"n394490614":{"id":"n394490614","loc":[-85.619729,41.929517]},"n394490615":{"id":"n394490615","loc":[-85.619801,41.929305]},"n394490616":{"id":"n394490616","loc":[-85.619809,41.927391]},"n394490617":{"id":"n394490617","loc":[-85.620883,41.927378]},"n394490618":{"id":"n394490618","loc":[-85.620988,41.927368]},"n394490619":{"id":"n394490619","loc":[-85.621076,41.927368]},"n394490620":{"id":"n394490620","loc":[-85.621156,41.927376]},"n394490621":{"id":"n394490621","loc":[-85.621685,41.92737]},"n394490622":{"id":"n394490622","loc":[-85.624716,41.927359]},"n394490623":{"id":"n394490623","loc":[-85.625308,41.92737]},"n394490624":{"id":"n394490624","loc":[-85.625655,41.927377]},"n394490625":{"id":"n394490625","loc":[-85.625093,41.925591]},"n394490626":{"id":"n394490626","loc":[-85.625174,41.92559]},"n394490627":{"id":"n394490627","loc":[-85.625249,41.925597]},"n394490628":{"id":"n394490628","loc":[-85.625532,41.925604]},"n394490629":{"id":"n394490629","loc":[-85.625761,41.925597]},"n394490630":{"id":"n394490630","loc":[-85.625955,41.926153]},"n394490631":{"id":"n394490631","loc":[-85.626209,41.926155]},"n394490632":{"id":"n394490632","loc":[-85.627757,41.926151]},"n394490633":{"id":"n394490633","loc":[-85.627825,41.926298]},"n394490634":{"id":"n394490634","loc":[-85.627994,41.926315]},"n394490635":{"id":"n394490635","loc":[-85.628049,41.927196]},"n394490636":{"id":"n394490636","loc":[-85.62949,41.927221]},"n394490637":{"id":"n394490637","loc":[-85.629602,41.927277]},"n394490638":{"id":"n394490638","loc":[-85.6297102,41.9273279]},"n394490639":{"id":"n394490639","loc":[-85.630958,41.927398]},"n394490699":{"id":"n394490699","loc":[-85.632741,41.927388]},"n394490700":{"id":"n394490700","loc":[-85.632997,41.927391]},"n394490701":{"id":"n394490701","loc":[-85.633149,41.927393]},"n394490702":{"id":"n394490702","loc":[-85.633334,41.927393]},"n394490703":{"id":"n394490703","loc":[-85.633468,41.927561]},"n394490704":{"id":"n394490704","loc":[-85.633563,41.927755]},"n394490705":{"id":"n394490705","loc":[-85.633662,41.928192]},"n394490706":{"id":"n394490706","loc":[-85.633679,41.928807]},"n394490707":{"id":"n394490707","loc":[-85.633687,41.929107]},"n394490708":{"id":"n394490708","loc":[-85.633927,41.929109]},"n394490709":{"id":"n394490709","loc":[-85.634126,41.929111]},"n394490710":{"id":"n394490710","loc":[-85.634207,41.92911]},"n394490711":{"id":"n394490711","loc":[-85.634323,41.929111]},"n394490712":{"id":"n394490712","loc":[-85.636712,41.929128]},"n394490713":{"id":"n394490713","loc":[-85.63808,41.9291]},"n394490714":{"id":"n394490714","loc":[-85.639213,41.929088]},"n394490715":{"id":"n394490715","loc":[-85.639189,41.92852]},"n394490716":{"id":"n394490716","loc":[-85.639204,41.925488]},"n394490717":{"id":"n394490717","loc":[-85.644204,41.925452]},"n394490718":{"id":"n394490718","loc":[-85.651425,41.925406]},"n394490719":{"id":"n394490719","loc":[-85.651449,41.926321]},"n394490720":{"id":"n394490720","loc":[-85.651451,41.926969]},"n394490721":{"id":"n394490721","loc":[-85.651458,41.928052]},"n394490722":{"id":"n394490722","loc":[-85.651446,41.928892]},"n394490723":{"id":"n394490723","loc":[-85.651456,41.929447]},"n394490724":{"id":"n394490724","loc":[-85.651707,41.929454]},"n394490725":{"id":"n394490725","loc":[-85.652369,41.929473]},"n394490726":{"id":"n394490726","loc":[-85.6525,41.929452]},"n394490727":{"id":"n394490727","loc":[-85.654066,41.92946]},"n394490728":{"id":"n394490728","loc":[-85.654816,41.92946]},"n394490729":{"id":"n394490729","loc":[-85.654816,41.930337]},"n394490730":{"id":"n394490730","loc":[-85.654587,41.930337]},"n394490731":{"id":"n394490731","loc":[-85.654548,41.931072]},"n394490732":{"id":"n394490732","loc":[-85.654538,41.931701]},"n394490733":{"id":"n394490733","loc":[-85.654898,41.931689]},"n394490734":{"id":"n394490734","loc":[-85.654898,41.932505]},"n394490735":{"id":"n394490735","loc":[-85.654854,41.932514]},"n394490736":{"id":"n394490736","loc":[-85.655497,41.932499]},"n394490737":{"id":"n394490737","loc":[-85.656405,41.932493]},"n394490738":{"id":"n394490738","loc":[-85.656422,41.933416]},"n394490739":{"id":"n394490739","loc":[-85.657322,41.933438]},"n1475293233":{"id":"n1475293233","loc":[-85.6385522,41.9585167]},"n1475293242":{"id":"n1475293242","loc":[-85.64609,41.9540815]},"n1475293249":{"id":"n1475293249","loc":[-85.6358079,41.9692721]},"n1475293256":{"id":"n1475293256","loc":[-85.6387369,41.9581583]},"n1475293259":{"id":"n1475293259","loc":[-85.6455882,41.9541138]},"n1475293266":{"id":"n1475293266","loc":[-85.6451008,41.9541821]},"n1819800253":{"id":"n1819800253","loc":[-85.6134286,41.9429692]},"n2114807558":{"id":"n2114807558","loc":[-85.6365609,41.963866],"tags":{"railway":"level_crossing"}},"n2189015728":{"id":"n2189015728","loc":[-85.6383956,41.9590576]},"n2189015838":{"id":"n2189015838","loc":[-85.6435144,41.9563705]},"n2189015842":{"id":"n2189015842","loc":[-85.6415782,41.9557035]},"n2189015855":{"id":"n2189015855","loc":[-85.6440829,41.9554577]},"n2199109849":{"id":"n2199109849","loc":[-85.6393434,41.9565591]},"n2199109851":{"id":"n2199109851","loc":[-85.6393208,41.9565002]},"n2199109857":{"id":"n2199109857","loc":[-85.6401986,41.955545]},"n2199109859":{"id":"n2199109859","loc":[-85.6402362,41.955587]},"n2199109861":{"id":"n2199109861","loc":[-85.6395958,41.9565675]},"n2199109863":{"id":"n2199109863","loc":[-85.639528,41.9566011]},"w209717053":{"id":"w209717053","tags":{"area":"yes","building":"yes"},"nodes":["n2199109829","n2199109831","n2199109833","n2199109835","n2199109829"]},"w17966415":{"id":"w17966415","tags":{"access":"private","highway":"service","name":"Manufacturing Way"},"nodes":["n185971642","n185977232","n185977233","n185949745","n185949748","n185977234"]},"w209717054":{"id":"w209717054","tags":{"area":"yes","building":"yes"},"nodes":["n2199109837","n2199109839","n2199109841","n2199109843","n2199109845","n2199109847","n2199109837"]},"w208627214":{"id":"w208627214","tags":{"highway":"service"},"nodes":["n185949755","n2189015728","n1475293233","n1475293256","n185952163","n185952161","n185952160","n185952158","n185949763","n1819848965","n1819848890","n185952156"]},"w17963817":{"id":"w17963817","tags":{"access":"private","highway":"service"},"nodes":["n185949765","n185953413","n185953417","n185953421","n185953423"]},"w34369809":{"id":"w34369809","tags":{"admin_level":"8","boundary":"administrative","landuse":"residential"},"nodes":["n394490395","n394490396","n394490397","n394490398","n394490399","n394490400","n394490401","n394490402","n394490403","n394490404","n394490405","n394490406","n394490407","n394490408","n394490409","n394490410","n394490411","n394490412","n394490413","n394490414","n394490415","n394490416","n394490417","n394490418","n394490419","n394490420","n394490421","n394490422","n394490423","n394490424","n394490425","n394490426","n394490427","n394490428","n1475293242","n1475293259","n1475293266","n394490429","n394490430","n394490431","n394490432","n394490433","n394490434","n394490435","n394490436","n394490437","n394490438","n394490439","n394490440","n394490441","n394490442","n394490443","n394490444","n394490445","n394490446","n1475293249","n394490447","n394490448","n394490449","n394490450","n394490451","n394490452","n394490453","n394490454","n394490455","n394490456","n394490457","n394490458","n394490459","n394490460","n394490461","n394490462","n2114807558","n394490463","n1475293226","n394490464","n394490465","n394490466","n394490467","n394490468","n394490469","n394490470","n394490471","n394490472","n394490473","n394490474","n394490475","n394490476","n394490477","n394490478","n394490479","n394490480","n394490481","n394490482","n394490483","n394490484","n394490485","n394490486","n394490487","n394490488","n394490489","n394490490","n394490491","n394490492","n394490493","n394490494","n394490495","n394490496","n394490497","n394490498","n394490499","n394490500","n394490501","n394490502","n394490503","n394490504","n394490505","n394490506","n394490507","n394490508","n394490509","n394490510","n394490511","n394490512","n394490513","n394490514","n394490515","n394490516","n394490517","n394490518","n394490519","n394490520","n394490521","n394490522","n394490523","n394490524","n394490525","n394490526","n394490527","n394490528","n394490529","n394490530","n394490531","n394490532","n394490533","n394490534","n394490535","n394490536","n394490537","n394490538","n394490539","n394490540","n394490542","n394490545","n394490546","n394490547","n394490548","n394490549","n394490550","n394490551","n394490552","n394490553","n394490554","n394490555","n394490556","n394490557","n394490558","n394490559","n394490560","n394490561","n394490562","n394490563","n394490564","n394490565","n394490566","n394490567","n394490568","n394490569","n394490570","n394490571","n1819800253","n394490572","n394490573","n394490574","n394490575","n394490576","n394490577","n394490578","n394490579","n394490580","n394490582","n394490583","n394490585","n394490586","n394490588","n394490589","n394490590","n394490592","n394490594","n394490595","n394490596","n394490598","n394490599","n394490601","n394490602","n394490604","n394490605","n394490607","n394490608","n394490609","n394490611","n394490612","n394490613","n394490614","n394490615","n394490616","n394490617","n394490618","n394490619","n394490620","n394490621","n394490622","n394490623","n394490624","n394490625","n394490626","n394490627","n394490628","n394490629","n394490630","n394490631","n394490632","n394490633","n394490634","n394490635","n394490636","n394490637","n394490638","n394490639","n394490699","n394490700","n394490701","n394490702","n394490703","n394490704","n394490705","n394490706","n394490707","n394490708","n394490709","n394490710","n394490711","n394490712","n394490713","n394490714","n394490715","n394490716","n394490717","n394490718","n394490719","n394490720","n394490721","n394490722","n394490723","n394490724","n394490725","n394490726","n394490727","n394490728","n394490729","n394490730","n394490731","n394490732","n394490733","n394490734","n394490735","n394490736","n394490737","n394490738","n394490739","n394490395"]},"w208627221":{"id":"w208627221","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189015838","n2189015842","n2189015846","n2189015849","n2189015852","n2189015855","n2189015838"]},"w209717052":{"id":"w209717052","tags":{"area":"yes","building":"yes"},"nodes":["n2199109816","n2199109818","n2199109820","n2199109822","n2199109825","n2199109827","n2199109816"]},"w134151784":{"id":"w134151784","tags":{"bridge":"yes","highway":"residential","name":"W Hoffman St"},"nodes":["n185971648","n185971651"]},"w209717055":{"id":"w209717055","tags":{"area":"yes","landuse":"basin"},"nodes":["n2199109849","n2199109851","n2199109853","n2199109855","n2199109857","n2199109859","n2199109861","n2199109863","n2199109849"]},"w17967763":{"id":"w17967763","tags":{"highway":"residential","name":"Rock River Ave"},"nodes":["n1475293244","n185982166","n185975067","n185971637"]},"r134949":{"id":"r134949","tags":{"admin_level":"8","border_type":"city","boundary":"administrative","name":"Three Rivers","place":"city","type":"boundary"},"members":[{"id":"w34369809","type":"way","role":"outer"},{"id":"w34369821","type":"way","role":"outer"},{"id":"w34369822","type":"way","role":"outer"},{"id":"w34369823","type":"way","role":"outer"},{"id":"w34369824","type":"way","role":"outer"},{"id":"w34369825","type":"way","role":"outer"},{"id":"w34369826","type":"way","role":"outer"},{"id":"w34369810","type":"way","role":"inner"},{"id":"w34369811","type":"way","role":"inner"},{"id":"w34369812","type":"way","role":"inner"},{"id":"w34367079","type":"way","role":"inner"},{"id":"w34369814","type":"way","role":"inner"},{"id":"w34367080","type":"way","role":"inner"},{"id":"w34369815","type":"way","role":"inner"},{"id":"w34369820","type":"way","role":"inner"}]},"n1819848881":{"id":"n1819848881","loc":[-85.638562,41.9569965]},"n1819848947":{"id":"n1819848947","loc":[-85.6384348,41.9576565]},"n1819849044":{"id":"n1819849044","loc":[-85.6385749,41.9573345]},"n2114807547":{"id":"n2114807547","loc":[-85.6384626,41.9583756]},"n2114807564":{"id":"n2114807564","loc":[-85.638535,41.9581283]},"n2189015691":{"id":"n2189015691","loc":[-85.6435584,41.9565243]},"n2189015696":{"id":"n2189015696","loc":[-85.6435805,41.9566049]},"n2189015722":{"id":"n2189015722","loc":[-85.6435035,41.9567438]},"n2189015744":{"id":"n2189015744","loc":[-85.6437991,41.9569582]},"n2189015747":{"id":"n2189015747","loc":[-85.6433042,41.9567742]},"n2189015750":{"id":"n2189015750","loc":[-85.6433827,41.9566844]},"n2189015753":{"id":"n2189015753","loc":[-85.6430447,41.9565588]},"n2189015756":{"id":"n2189015756","loc":[-85.6431111,41.956451]},"n2189015759":{"id":"n2189015759","loc":[-85.6420247,41.956083]},"n2189015760":{"id":"n2189015760","loc":[-85.6419945,41.9561369]},"n2189015764":{"id":"n2189015764","loc":[-85.6413729,41.9558945]},"n2189015766":{"id":"n2189015766","loc":[-85.6412884,41.9560606]},"n2189015770":{"id":"n2189015770","loc":[-85.6411798,41.9560112]},"n2189015771":{"id":"n2189015771","loc":[-85.6410651,41.9562132]},"n2189015774":{"id":"n2189015774","loc":[-85.6409504,41.9561728]},"n2189015778":{"id":"n2189015778","loc":[-85.6407996,41.9564241]},"n2189015781":{"id":"n2189015781","loc":[-85.6406889,41.9563892]},"n2189015785":{"id":"n2189015785","loc":[-85.6404857,41.9567024]},"n2189015789":{"id":"n2189015789","loc":[-85.6406909,41.9567877]},"n2189015793":{"id":"n2189015793","loc":[-85.6405642,41.9570165]},"n2189015796":{"id":"n2189015796","loc":[-85.6415359,41.9573711]},"n2189015800":{"id":"n2189015800","loc":[-85.6411738,41.9579501]},"n2189015804":{"id":"n2189015804","loc":[-85.6411119,41.957921]},"n2189015808":{"id":"n2189015808","loc":[-85.6403186,41.9591751]},"n2189015909":{"id":"n2189015909","loc":[-85.6389293,41.9564636]},"n2189015926":{"id":"n2189015926","loc":[-85.6385431,41.9564617]},"n2189015929":{"id":"n2189015929","loc":[-85.6385457,41.9561823]},"n2189015932":{"id":"n2189015932","loc":[-85.6389319,41.9561843]},"n2199109865":{"id":"n2199109865","loc":[-85.6400768,41.956776]},"n2199109867":{"id":"n2199109867","loc":[-85.639902,41.9567153]},"n2199109869":{"id":"n2199109869","loc":[-85.640004,41.956553]},"n2199109871":{"id":"n2199109871","loc":[-85.6401788,41.9566137]},"n2199109873":{"id":"n2199109873","loc":[-85.6399316,41.9564506],"tags":{"man_made":"water_tower"}},"n2199109876":{"id":"n2199109876","loc":[-85.6397689,41.9572354]},"n2199109878":{"id":"n2199109878","loc":[-85.6399229,41.9569826]},"n2199109880":{"id":"n2199109880","loc":[-85.639706,41.9569095]},"n2199109882":{"id":"n2199109882","loc":[-85.639552,41.9571623]},"n2199109884":{"id":"n2199109884","loc":[-85.6391028,41.9569517]},"n2199109886":{"id":"n2199109886","loc":[-85.6392876,41.956646]},"n2199109888":{"id":"n2199109888","loc":[-85.639484,41.9567117]},"n2199109889":{"id":"n2199109889","loc":[-85.6394322,41.9567973]},"n2199109890":{"id":"n2199109890","loc":[-85.6393718,41.9567771]},"n2199109891":{"id":"n2199109891","loc":[-85.6392387,41.9569972]},"n1819848900":{"id":"n1819848900","loc":[-85.638281,41.9576578]},"n1819848978":{"id":"n1819848978","loc":[-85.6377186,41.9580867]},"n1819849039":{"id":"n1819849039","loc":[-85.6384217,41.9573405]},"n1819849050":{"id":"n1819849050","loc":[-85.6377011,41.9570042]},"n1819849088":{"id":"n1819849088","loc":[-85.6382879,41.9580817]},"n2114807549":{"id":"n2114807549","loc":[-85.6362551,41.96473]},"n2114807587":{"id":"n2114807587","loc":[-85.6368694,41.9629829]},"n2189015725":{"id":"n2189015725","loc":[-85.644156,41.9569753]},"n2189015741":{"id":"n2189015741","loc":[-85.6419825,41.9597632]},"w208627217":{"id":"w208627217","tags":{"area":"yes","building":"yes"},"nodes":["n2189015741","n2189015744","n2189015747","n2189015750","n2189015753","n2189015756","n2189015759","n2189015760","n2189015764","n2189015766","n2189015770","n2189015771","n2189015774","n2189015778","n2189015781","n2189015785","n2189015789","n2189015793","n2189015796","n2189015800","n2189015804","n2189015808","n2189015741"]},"w208627212":{"id":"w208627212","tags":{"highway":"service"},"nodes":["n2189015691","n2189015696","n2189015722","n2189015725"]},"w209717057":{"id":"w209717057","tags":{"area":"yes","building":"yes"},"nodes":["n2199109876","n2199109878","n2199109880","n2199109882","n2199109876"]},"w209717056":{"id":"w209717056","tags":{"area":"yes","building":"yes"},"nodes":["n2199109865","n2199109867","n2199109869","n2199109871","n2199109865"]},"w208627231":{"id":"w208627231","tags":{"area":"yes","building":"yes"},"nodes":["n2189015909","n2189015926","n2189015929","n2189015932","n2189015909"]},"w170848326":{"id":"w170848326","tags":{"building":"yes"},"nodes":["n1819848881","n1819849050","n1819848978","n1819849088","n1819848900","n1819848947","n1819849039","n1819849044","n1819848881"]},"w17963182":{"id":"w17963182","tags":{"highway":"service"},"nodes":["n185949763","n185949765","n2189015691","n185949745"]},"w201484340":{"id":"w201484340","tags":{"railway":"rail","service":"siding"},"nodes":["n2114807565","n2114807564","n2114807547","n2114807587","n2114807558","n2114807549","n2114807593"]},"w209717058":{"id":"w209717058","tags":{"area":"yes","building":"yes"},"nodes":["n2199109884","n2199109886","n2199109888","n2199109889","n2199109890","n2199109891","n2199109884"]},"n185954650":{"id":"n185954650","loc":[-85.627331,41.957439]},"n185966949":{"id":"n185966949","loc":[-85.626868,41.957314]},"n185989335":{"id":"n185989335","loc":[-85.62529,41.958568]},"n185989337":{"id":"n185989337","loc":[-85.624962,41.958453]},"n185989339":{"id":"n185989339","loc":[-85.624832,41.958399]},"n185989340":{"id":"n185989340","loc":[-85.624707,41.958325]},"n185989342":{"id":"n185989342","loc":[-85.624636,41.958251]},"n185989345":{"id":"n185989345","loc":[-85.624578,41.95818]},"n185989347":{"id":"n185989347","loc":[-85.624533,41.958099]},"n185989349":{"id":"n185989349","loc":[-85.624507,41.957985]},"n185989351":{"id":"n185989351","loc":[-85.624495,41.957807]},"n185989353":{"id":"n185989353","loc":[-85.624514,41.957663]},"n185989354":{"id":"n185989354","loc":[-85.624577,41.957593]},"n185989356":{"id":"n185989356","loc":[-85.624685,41.95754]},"n185989357":{"id":"n185989357","loc":[-85.624802,41.957523]},"n185989359":{"id":"n185989359","loc":[-85.624996,41.957524]},"n185989361":{"id":"n185989361","loc":[-85.625409,41.957515]},"n185989364":{"id":"n185989364","loc":[-85.625634,41.957496]},"n185989367":{"id":"n185989367","loc":[-85.625832,41.957453]},"n185989368":{"id":"n185989368","loc":[-85.626044,41.957394]},"n354031352":{"id":"n354031352","loc":[-85.6252778,41.9586111],"tags":{"amenity":"place_of_worship","denomination":"baptist","name":"First Baptist Church","religion":"christian"}},"n2199109892":{"id":"n2199109892","loc":[-85.6261578,41.9589963]},"n2199109893":{"id":"n2199109893","loc":[-85.6263191,41.9586865]},"n2199109894":{"id":"n2199109894","loc":[-85.6261186,41.9586288]},"n2199109895":{"id":"n2199109895","loc":[-85.6260644,41.9587329]},"n2199109896":{"id":"n2199109896","loc":[-85.6261547,41.9587589]},"n2199109898":{"id":"n2199109898","loc":[-85.6260476,41.9589646]},"n185966951":{"id":"n185966951","loc":[-85.628404,41.957438]},"w17965351":{"id":"w17965351","tags":{"highway":"residential","name":"Flower Street"},"nodes":["n185966948","n185966949","n185954650","n185966951","n185966953","n185966955","n185966957"]},"w17967809":{"id":"w17967809","tags":{"highway":"residential","name":"Azaleamum Drive"},"nodes":["n185982197","n185989335","n185989337","n185989339","n185989340","n185989342","n185989345","n185989347","n185989349","n185989351","n185989353","n185989354","n185989356","n185989357","n185989359","n185989361","n185989364","n185989367","n185989368","n185982196"]},"w209717059":{"id":"w209717059","tags":{"area":"yes","building":"yes"},"nodes":["n2199109892","n2199109893","n2199109894","n2199109895","n2199109896","n2199109898","n2199109892"]},"n185961390":{"id":"n185961390","loc":[-85.63137,41.959033]},"n185961393":{"id":"n185961393","loc":[-85.634315,41.959017]},"w17966214":{"id":"w17966214","tags":{"highway":"residential","name":"East Adams Street"},"nodes":["n185975351","n185967434","n185968108"]},"w17964793":{"id":"w17964793","tags":{"highway":"residential","name":"Morris Ave"},"nodes":["n185961389","n185961390","n185961391","n185961393","n185961396"]},"n185952166":{"id":"n185952166","loc":[-85.638174,41.95831]},"n2114807552":{"id":"n2114807552","loc":[-85.6383526,41.9593788]},"n2114807591":{"id":"n2114807591","loc":[-85.6383741,41.9593968]},"n2189015731":{"id":"n2189015731","loc":[-85.6368404,41.9592785]},"n2189015734":{"id":"n2189015734","loc":[-85.6368404,41.9585918]},"n2189015737":{"id":"n2189015737","loc":[-85.6376009,41.9585918]},"n2189015738":{"id":"n2189015738","loc":[-85.6376009,41.9592785]},"n2189015897":{"id":"n2189015897","loc":[-85.6376839,41.9566137]},"n2189015900":{"id":"n2189015900","loc":[-85.6376831,41.9564865]},"n2189015903":{"id":"n2189015903","loc":[-85.6381161,41.9564851]},"n2189015906":{"id":"n2189015906","loc":[-85.6381168,41.9566122]},"n2189015937":{"id":"n2189015937","loc":[-85.6364789,41.9590634]},"n2189015940":{"id":"n2189015940","loc":[-85.6361137,41.9590672]},"n2189015943":{"id":"n2189015943","loc":[-85.6361169,41.9594033]},"n2189015945":{"id":"n2189015945","loc":[-85.6363456,41.9594021]},"n2189015952":{"id":"n2189015952","loc":[-85.636112,41.958892]},"n2189015955":{"id":"n2189015955","loc":[-85.6364757,41.9588894]},"n2189015957":{"id":"n2189015957","loc":[-85.6364729,41.9586747]},"n2189015958":{"id":"n2189015958","loc":[-85.6361103,41.9586765]},"n2189015959":{"id":"n2189015959","loc":[-85.6364719,41.9585562]},"n2189015960":{"id":"n2189015960","loc":[-85.6361093,41.958558]},"n2189015961":{"id":"n2189015961","loc":[-85.6355494,41.9586403]},"n2189015962":{"id":"n2189015962","loc":[-85.635549,41.9584711]},"n2189015963":{"id":"n2189015963","loc":[-85.6351831,41.9584715]},"n2189015964":{"id":"n2189015964","loc":[-85.6351834,41.9586408]},"n2189015966":{"id":"n2189015966","loc":[-85.6359579,41.9586359]},"n2189015968":{"id":"n2189015968","loc":[-85.6359561,41.9585465]},"n2189015971":{"id":"n2189015971","loc":[-85.6355476,41.9585509]},"n2189015974":{"id":"n2189015974","loc":[-85.6359516,41.9592934]},"n2189015977":{"id":"n2189015977","loc":[-85.635949,41.9586697]},"n2189015980":{"id":"n2189015980","loc":[-85.6351329,41.9586716]},"n2189015983":{"id":"n2189015983","loc":[-85.6351318,41.9583949]},"n2189015986":{"id":"n2189015986","loc":[-85.6349148,41.9583954]},"n2189015989":{"id":"n2189015989","loc":[-85.6349186,41.9592958]},"n2189015995":{"id":"n2189015995","loc":[-85.6360173,41.9593286]},"n2189015998":{"id":"n2189015998","loc":[-85.6360278,41.9583079]},"n2114807550":{"id":"n2114807550","loc":[-85.6383392,41.9595404]},"n2114807551":{"id":"n2114807551","loc":[-85.6375855,41.9616107]},"n2114807559":{"id":"n2114807559","loc":[-85.6373978,41.9621273]},"n2114807562":{"id":"n2114807562","loc":[-85.6373361,41.9622609]},"n2114807563":{"id":"n2114807563","loc":[-85.6376472,41.9613953]},"n2114807574":{"id":"n2114807574","loc":[-85.636974,41.9627695]},"n2114807589":{"id":"n2114807589","loc":[-85.6383017,41.9595005]},"n2114807592":{"id":"n2114807592","loc":[-85.6377169,41.9613494]},"n2114807595":{"id":"n2114807595","loc":[-85.6371081,41.962574]},"n2189015934":{"id":"n2189015934","loc":[-85.6364855,41.9595098]},"n2189015949":{"id":"n2189015949","loc":[-85.6363466,41.9595105]},"w208627244":{"id":"w208627244","tags":{"highway":"service"},"nodes":["n2189015992","n2189015995","n2189015998"]},"w208627240":{"id":"w208627240","tags":{"area":"yes","building":"yes"},"nodes":["n2189015961","n2189015971","n2189015962","n2189015963","n2189015964","n2189015961"]},"w17967437":{"id":"w17967437","tags":{"highway":"residential","name":"Lyman St"},"nodes":["n185964361","n185984024"]},"w208627237":{"id":"w208627237","tags":{"area":"yes","building":"yes"},"nodes":["n2189015955","n2189015957","n2189015958","n2189015952","n2189015955"]},"w17967465":{"id":"w17967465","tags":{"highway":"residential","name":"W Adams St"},"nodes":["n185978394","n185984022","n185964360"]},"w208627228":{"id":"w208627228","tags":{"area":"yes","building":"yes"},"nodes":["n2189015897","n2189015900","n2189015903","n2189015906","n2189015897"]},"w201484351":{"id":"w201484351","tags":{"railway":"rail","service":"siding"},"nodes":["n2114807587","n2114807574","n2114807595","n2114807562","n2114807559","n2114807551","n2114807563","n2114807589","n2114807552"]},"w208627239":{"id":"w208627239","tags":{"area":"yes","building":"yes"},"nodes":["n2189015957","n2189015959","n2189015960","n2189015958","n2189015957"]},"w208627233":{"id":"w208627233","tags":{"area":"yes","building":"yes"},"nodes":["n2189015934","n2189015937","n2189015940","n2189015943","n2189015945","n2189015949","n2189015934"]},"w208627241":{"id":"w208627241","tags":{"area":"yes","building":"yes"},"nodes":["n2189015961","n2189015966","n2189015968","n2189015971","n2189015961"]},"w17967970":{"id":"w17967970","tags":{"highway":"residential","name":"Adams St"},"nodes":["n185975351","n185978394"]},"w208627235":{"id":"w208627235","tags":{"area":"yes","building":"yes"},"nodes":["n2189015940","n2189015952","n2189015955","n2189015937","n2189015940"]},"w17965468":{"id":"w17965468","tags":{"highway":"residential","name":"Armstrong Blvd"},"nodes":["n185967917","n2189015998","n185967918","n185964362","n185952166"]},"w201484346":{"id":"w201484346","tags":{"railway":"rail","service":"siding"},"nodes":["n2114807551","n2114807592","n2114807550","n2114807591"]},"w208627242":{"id":"w208627242","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189015974","n2189015977","n2189015980","n2189015983","n2189015986","n2189015989","n2189015974"]},"w208627216":{"id":"w208627216","tags":{"area":"yes","building":"yes"},"nodes":["n2189015731","n2189015734","n2189015737","n2189015738","n2189015731"]},"n185984309":{"id":"n185984309","loc":[-85.631421,41.961494]},"n185987987":{"id":"n185987987","loc":[-85.631456,41.960673]},"n185965397":{"id":"n185965397","loc":[-85.634603,41.959838]},"w17965196":{"id":"w17965196","tags":{"highway":"residential","name":"Burke Ave"},"nodes":["n185965395","n185965397","n185965399"]},"w17967215":{"id":"w17967215","tags":{"highway":"residential","name":"Kellogg Ave"},"nodes":["n185968114","n185984309","n185967440","n185978402"]},"w17967597":{"id":"w17967597","tags":{"highway":"residential","name":"Barnard Ave"},"nodes":["n185968112","n185987987","n185967438","n185978399"]},"n394490857":{"id":"n394490857","loc":[-85.633952,41.960664]},"n394490858":{"id":"n394490858","loc":[-85.633938,41.960227]},"n394490859":{"id":"n394490859","loc":[-85.634794,41.960212]},"n394490860":{"id":"n394490860","loc":[-85.634815,41.960662]},"n394490861":{"id":"n394490861","loc":[-85.634103,41.961268]},"n394490862":{"id":"n394490862","loc":[-85.634103,41.961001]},"n394490863":{"id":"n394490863","loc":[-85.634504,41.961003]},"n394490864":{"id":"n394490864","loc":[-85.634561,41.961269]},"n1057629869":{"id":"n1057629869","loc":[-85.6382599,41.9612134]},"n1057629937":{"id":"n1057629937","loc":[-85.6380035,41.9616137]},"n2189016014":{"id":"n2189016014","loc":[-85.6360365,41.9626496]},"n2189016017":{"id":"n2189016017","loc":[-85.6360374,41.9623228]},"n2189016020":{"id":"n2189016020","loc":[-85.6367557,41.9623239]},"n2189016022":{"id":"n2189016022","loc":[-85.6367566,41.9619919]},"n2189016025":{"id":"n2189016025","loc":[-85.6351794,41.9619893]},"n2189016028":{"id":"n2189016028","loc":[-85.6351788,41.9622011]},"n2189016031":{"id":"n2189016031","loc":[-85.6350855,41.9622009]},"n2189016034":{"id":"n2189016034","loc":[-85.6350845,41.962527]},"n2189016037":{"id":"n2189016037","loc":[-85.6352732,41.9625273]},"n2189016039":{"id":"n2189016039","loc":[-85.6352738,41.9623178]},"n2189016042":{"id":"n2189016042","loc":[-85.6357712,41.9623186]},"n2189016044":{"id":"n2189016044","loc":[-85.6357702,41.9626492]},"n1057629880":{"id":"n1057629880","loc":[-85.638817,41.9619017]},"n1057629923":{"id":"n1057629923","loc":[-85.6390733,41.9615014]},"w91092312":{"id":"w91092312","tags":{"power":"station"},"nodes":["n1057629923","n1057629869","n1057629937","n1057629880","n1057629923"]},"w34369826":{"id":"w34369826","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490861","n394490862","n394490863","n394490864","n394490861"]},"w34369825":{"id":"w34369825","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490857","n394490858","n394490859","n394490860","n394490857"]},"w208627248":{"id":"w208627248","tags":{"area":"yes","building":"yes"},"nodes":["n2189016014","n2189016017","n2189016020","n2189016022","n2189016025","n2189016028","n2189016031","n2189016034","n2189016037","n2189016039","n2189016042","n2189016044","n2189016014"]},"n394490766":{"id":"n394490766","loc":[-85.616777,41.955642]},"n394490768":{"id":"n394490768","loc":[-85.617239,41.955644]},"n394490792":{"id":"n394490792","loc":[-85.619034,41.95543]},"n185972055":{"id":"n185972055","loc":[-85.6185905,41.9568211]},"n185972057":{"id":"n185972057","loc":[-85.6186688,41.9570086]},"n185972059":{"id":"n185972059","loc":[-85.6186924,41.9581453]},"n185972060":{"id":"n185972060","loc":[-85.6187082,41.9588211],"tags":{"highway":"turning_circle"}},"n1819790724":{"id":"n1819790724","loc":[-85.6182155,41.9555703]},"n1819790735":{"id":"n1819790735","loc":[-85.6184059,41.9566188]},"n1819790799":{"id":"n1819790799","loc":[-85.6182372,41.9563771]},"n1819790896":{"id":"n1819790896","loc":[-85.6181431,41.9557227]},"n185971405":{"id":"n185971405","loc":[-85.6186766,41.9577468]},"n185971565":{"id":"n185971565","loc":[-85.6181613,41.9560879]},"n185967985":{"id":"n185967985","loc":[-85.6186798,41.9585791]},"n185955753":{"id":"n185955753","loc":[-85.620773,41.9555854]},"n185955755":{"id":"n185955755","loc":[-85.6212652,41.9559891]},"n185955748":{"id":"n185955748","loc":[-85.620722,41.954858]},"n185955751":{"id":"n185955751","loc":[-85.6206912,41.955367]},"n185967987":{"id":"n185967987","loc":[-85.6159351,41.9585809]},"n185971407":{"id":"n185971407","loc":[-85.6159142,41.9577578]},"n185971570":{"id":"n185971570","loc":[-85.6162248,41.95603]},"n185971572":{"id":"n185971572","loc":[-85.6160402,41.9560749]},"n185971574":{"id":"n185971574","loc":[-85.61593,41.956201]},"n185981301":{"id":"n185981301","loc":[-85.6158973,41.9581601]},"n394490762":{"id":"n394490762","loc":[-85.617193,41.954706]},"n394490764":{"id":"n394490764","loc":[-85.616773,41.954737]},"n394490787":{"id":"n394490787","loc":[-85.618972,41.954737]},"n394490790":{"id":"n394490790","loc":[-85.619046,41.954929]},"n394490794":{"id":"n394490794","loc":[-85.619922,41.955296]},"n394490796":{"id":"n394490796","loc":[-85.61991,41.95501]},"n394490798":{"id":"n394490798","loc":[-85.619974,41.954751]},"n1819790677":{"id":"n1819790677","loc":[-85.6187031,41.9550522]},"n1819790787":{"id":"n1819790787","loc":[-85.6186436,41.9552022]},"n1819790828":{"id":"n1819790828","loc":[-85.6185127,41.9553393]},"w17966857":{"id":"w17966857","tags":{"access":"private","highway":"service","name":"Sable River Rd"},"nodes":["n185972059","n185981301"]},"w34369814":{"id":"w34369814","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490787","n394490790","n394490792","n394490794","n394490796","n394490798","n394490787"]},"w17964176":{"id":"w17964176","tags":{"highway":"residential"},"nodes":["n185955747","n185955748","n185955751","n185955753","n185955755"]},"w17965838":{"id":"w17965838","tags":{"access":"private","highway":"service","name":"Pine River Rd"},"nodes":["n185971405","n185971407"]},"w17965476":{"id":"w17965476","tags":{"access":"private","highway":"service","name":"Raisin River Rd"},"nodes":["n185967985","n185967987"]},"w17965913":{"id":"w17965913","tags":{"access":"private","highway":"service","name":"Shiawassee River Rd"},"nodes":["n185972054","n1819790677","n1819790787","n1819790828","n1819790724","n1819790896","n185971565","n1819790799","n1819790735","n185972055","n185972057","n185971405","n185972059","n185967985","n185972060"]},"w34369811":{"id":"w34369811","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490762","n394490764","n394490766","n394490768","n394490762"]},"w17965854":{"id":"w17965854","tags":{"access":"private","highway":"service","name":"Sturgeon River Rd"},"nodes":["n185971565","n185971570","n185971572","n185971574"]},"n2139795769":{"id":"n2139795769","loc":[-85.6250804,41.9608796]},"n2139795770":{"id":"n2139795770","loc":[-85.6250315,41.9613684]},"n2139795771":{"id":"n2139795771","loc":[-85.6249671,41.9614362]},"n2139795772":{"id":"n2139795772","loc":[-85.6249698,41.961522]},"n2139795773":{"id":"n2139795773","loc":[-85.6250798,41.9615838]},"n2139795774":{"id":"n2139795774","loc":[-85.6252273,41.9615639]},"n2139795775":{"id":"n2139795775","loc":[-85.6252863,41.9614622]},"n2139795776":{"id":"n2139795776","loc":[-85.6252273,41.9613764]},"n2139795777":{"id":"n2139795777","loc":[-85.6251227,41.9613525]},"n2139795778":{"id":"n2139795778","loc":[-85.6249564,41.9612527]},"n2139795779":{"id":"n2139795779","loc":[-85.6249846,41.9610254]},"n2139795780":{"id":"n2139795780","loc":[-85.6266725,41.9599647]},"n2139795781":{"id":"n2139795781","loc":[-85.6259162,41.9599711]},"n2139795782":{"id":"n2139795782","loc":[-85.6257185,41.960019]},"n2139795783":{"id":"n2139795783","loc":[-85.6255509,41.9601213]},"n185963539":{"id":"n185963539","loc":[-85.615718,41.983893]},"n185964418":{"id":"n185964418","loc":[-85.616626,42.049512]},"n185966614":{"id":"n185966614","loc":[-85.615514,41.976603]},"n185966635":{"id":"n185966635","loc":[-85.616118,42.013017]},"n185969040":{"id":"n185969040","loc":[-85.615632,41.972357]},"n185969070":{"id":"n185969070","loc":[-85.619145,41.967648]},"n185972156":{"id":"n185972156","loc":[-85.621894,41.963956]},"n185972157":{"id":"n185972157","loc":[-85.621806,41.964077]},"n185972158":{"id":"n185972158","loc":[-85.620848,41.965341]},"n185972159":{"id":"n185972159","loc":[-85.620684,41.965558]},"n185972160":{"id":"n185972160","loc":[-85.620621,41.965658]},"n185972161":{"id":"n185972161","loc":[-85.617844,41.969359]},"n185972162":{"id":"n185972162","loc":[-85.616843,41.97068]},"n185972164":{"id":"n185972164","loc":[-85.616714,41.970839]},"n185972166":{"id":"n185972166","loc":[-85.615879,41.971969]},"n185972168":{"id":"n185972168","loc":[-85.615748,41.972159]},"n185972170":{"id":"n185972170","loc":[-85.615589,41.972502]},"n185972172":{"id":"n185972172","loc":[-85.615542,41.972733]},"n185972175":{"id":"n185972175","loc":[-85.615524,41.972947]},"n185972177":{"id":"n185972177","loc":[-85.615512,41.973715]},"n185972179":{"id":"n185972179","loc":[-85.615513,41.976496]},"n185972180":{"id":"n185972180","loc":[-85.615538,41.977246]},"n185972181":{"id":"n185972181","loc":[-85.61558,41.982139]},"n185972184":{"id":"n185972184","loc":[-85.61557,41.983317]},"n185972186":{"id":"n185972186","loc":[-85.615591,41.983463]},"n185972188":{"id":"n185972188","loc":[-85.615763,41.984146]},"n185972190":{"id":"n185972190","loc":[-85.615814,41.98435]},"n185972192":{"id":"n185972192","loc":[-85.615965,41.998453]},"n185972194":{"id":"n185972194","loc":[-85.615982,42.001237]},"n185972195":{"id":"n185972195","loc":[-85.616055,42.00555]},"n185972197":{"id":"n185972197","loc":[-85.616134,42.014887]},"n185972199":{"id":"n185972199","loc":[-85.616177,42.018465]},"n185972201":{"id":"n185972201","loc":[-85.616298,42.027627]},"n185972203":{"id":"n185972203","loc":[-85.616513,42.042212]},"w203968015":{"id":"w203968015","tags":{"highway":"residential"},"nodes":["n2139795768","n2139795769"]},"w17965932":{"id":"w17965932","tags":{"highway":"residential","name":"Buckhorn Road","name_1":"County Highway 122"},"nodes":["n185972155","n185972156","n185972157","n185972158","n185972159","n185972160","n185969070","n185972161","n185972162","n185972164","n185972166","n185972168","n185969040","n185972170","n185972172","n185972175","n185972177","n185972179","n185966614","n185972180","n185972181","n185972184","n185972186","n185963539","n185972188","n185972190","n185972192","n185972194","n185972195","n185966635","n185972197","n185972199","n185972201","n185972203","n185964418"]},"w203968016":{"id":"w203968016","tags":{"highway":"residential","name":"New Jersey Court"},"nodes":["n2139795770","n2139795771","n2139795772","n2139795773","n2139795774","n2139795775","n2139795776","n2139795777","n2139795770","n2139795778","n2139795779","n2139795769"]},"w203968017":{"id":"w203968017","tags":{"highway":"residential","name":"Oklahoma Drive"},"nodes":["n2139795780","n2139795781","n2139795782","n2139795783","n2139795769"]},"n1819790528":{"id":"n1819790528","loc":[-85.6184827,41.960025]},"n1819790530":{"id":"n1819790530","loc":[-85.6168626,41.9605834]},"n1819790534":{"id":"n1819790534","loc":[-85.6197379,41.9617163]},"n1819790541":{"id":"n1819790541","loc":[-85.6198881,41.9620833]},"n1819790543":{"id":"n1819790543","loc":[-85.619695,41.9619397]},"n1819790547":{"id":"n1819790547","loc":[-85.6190298,41.9609504]},"n1819790555":{"id":"n1819790555","loc":[-85.6180471,41.9609788]},"n1819790559":{"id":"n1819790559","loc":[-85.6203817,41.9605436]},"n1819790583":{"id":"n1819790583","loc":[-85.6201564,41.9603282]},"n1819790590":{"id":"n1819790590","loc":[-85.617045,41.9598894]},"n1819790609":{"id":"n1819790609","loc":[-85.6177638,41.9598495]},"n1819790618":{"id":"n1819790618","loc":[-85.6195234,41.9610143]},"n1819790642":{"id":"n1819790642","loc":[-85.6181179,41.9627933]},"n1819790659":{"id":"n1819790659","loc":[-85.6174634,41.962897]},"n1819790665":{"id":"n1819790665","loc":[-85.6170343,41.9630885]},"n1819790674":{"id":"n1819790674","loc":[-85.6194697,41.9601925]},"n1819790685":{"id":"n1819790685","loc":[-85.6207722,41.9610665]},"n1819790687":{"id":"n1819790687","loc":[-85.6202315,41.9622109]},"n1819790697":{"id":"n1819790697","loc":[-85.6184505,41.9624662]},"n1819790726":{"id":"n1819790726","loc":[-85.6178926,41.9628492]},"n1819790738":{"id":"n1819790738","loc":[-85.6173347,41.9598016]},"n1819790762":{"id":"n1819790762","loc":[-85.6186221,41.9609105]},"n1819790774":{"id":"n1819790774","loc":[-85.6175922,41.9608308]},"n1819790781":{"id":"n1819790781","loc":[-85.6167768,41.9633198]},"n1819790796":{"id":"n1819790796","loc":[-85.619856,41.961461]},"n1819790811":{"id":"n1819790811","loc":[-85.6208215,41.9620195]},"n1819790833":{"id":"n1819790833","loc":[-85.618311,41.9612536]},"n1819790854":{"id":"n1819790854","loc":[-85.6183646,41.9626417]},"n1819790863":{"id":"n1819790863","loc":[-85.6204997,41.9608547]},"n1819790867":{"id":"n1819790867","loc":[-85.6184934,41.9621391]},"n1819790877":{"id":"n1819790877","loc":[-85.6206928,41.9621152]},"n1819790881":{"id":"n1819790881","loc":[-85.6170879,41.960735]},"n1819790891":{"id":"n1819790891","loc":[-85.6168304,41.9601207]},"n1819790898":{"id":"n1819790898","loc":[-85.619813,41.9612297]},"n1819790909":{"id":"n1819790909","loc":[-85.6167982,41.960376]},"n1819790912":{"id":"n1819790912","loc":[-85.6205855,41.9610462]},"n1819790544":{"id":"n1819790544","loc":[-85.612968,41.9707781]},"n1819790549":{"id":"n1819790549","loc":[-85.614395,41.9697172]},"n1819790552":{"id":"n1819790552","loc":[-85.6180535,41.9655536]},"n1819790554":{"id":"n1819790554","loc":[-85.6111227,41.9703713]},"n1819790560":{"id":"n1819790560","loc":[-85.6112729,41.9701958]},"n1819790563":{"id":"n1819790563","loc":[-85.6137512,41.9689917]},"n1819790564":{"id":"n1819790564","loc":[-85.6181072,41.9659205]},"n1819790595":{"id":"n1819790595","loc":[-85.6170021,41.9666863]},"n1819790605":{"id":"n1819790605","loc":[-85.6168948,41.9644527]},"n1819790606":{"id":"n1819790606","loc":[-85.6128071,41.9701081]},"n1819790607":{"id":"n1819790607","loc":[-85.6129251,41.9704032]},"n1819790612":{"id":"n1819790612","loc":[-85.6177638,41.9663912]},"n1819790615":{"id":"n1819790615","loc":[-85.6152533,41.9670373]},"n1819790622":{"id":"n1819790622","loc":[-85.6146739,41.9673804]},"n1819790623":{"id":"n1819790623","loc":[-85.6180428,41.9661838]},"n1819790625":{"id":"n1819790625","loc":[-85.6172918,41.9646202]},"n1819790645":{"id":"n1819790645","loc":[-85.6178067,41.965043]},"n1819790647":{"id":"n1819790647","loc":[-85.6143306,41.9712488]},"n1819790649":{"id":"n1819790649","loc":[-85.6147383,41.9707702]},"n1819790654":{"id":"n1819790654","loc":[-85.6157361,41.9668459]},"n1819790657":{"id":"n1819790657","loc":[-85.6145666,41.9710733]},"n1819790668":{"id":"n1819790668","loc":[-85.6166909,41.9642692]},"n1819790671":{"id":"n1819790671","loc":[-85.6141482,41.9696538]},"n1819790679":{"id":"n1819790679","loc":[-85.6148349,41.9705388]},"n1819790686":{"id":"n1819790686","loc":[-85.6139551,41.9695501]},"n1819790696":{"id":"n1819790696","loc":[-85.6119703,41.9699087]},"n1819790704":{"id":"n1819790704","loc":[-85.6140731,41.9684174]},"n1819790706":{"id":"n1819790706","loc":[-85.6124745,41.9699246]},"n1819790718":{"id":"n1819790718","loc":[-85.6165407,41.9636868]},"n1819790720":{"id":"n1819790720","loc":[-85.61388,41.9687365]},"n1819790731":{"id":"n1819790731","loc":[-85.6165193,41.9639421]},"n1819790739":{"id":"n1819790739","loc":[-85.6146739,41.9699964]},"n1819790753":{"id":"n1819790753","loc":[-85.6173883,41.9665747]},"n1819790760":{"id":"n1819790760","loc":[-85.6133221,41.9712089]},"n1819790767":{"id":"n1819790767","loc":[-85.6116698,41.9699246]},"n1819790779":{"id":"n1819790779","loc":[-85.6130753,41.9710573]},"n1819790791":{"id":"n1819790791","loc":[-85.6137083,41.9692869]},"n1819790795":{"id":"n1819790795","loc":[-85.6141482,41.9679627]},"n1819790798":{"id":"n1819790798","loc":[-85.6137727,41.9694305]},"n1819790836":{"id":"n1819790836","loc":[-85.6143842,41.9676037]},"n1819790915":{"id":"n1819790915","loc":[-85.6148456,41.9702756]},"n1819790926":{"id":"n1819790926","loc":[-85.6138371,41.9713525]},"n1819790927":{"id":"n1819790927","loc":[-85.6141053,41.9713525]},"n1819790931":{"id":"n1819790931","loc":[-85.6162832,41.966814]},"n1821014625":{"id":"n1821014625","loc":[-85.5960611,41.9808498]},"n1821014627":{"id":"n1821014627","loc":[-85.5565843,42.010982]},"n1821014629":{"id":"n1821014629","loc":[-85.5971541,41.9805808]},"n1821014632":{"id":"n1821014632","loc":[-85.6061837,41.9725907]},"n1821014633":{"id":"n1821014633","loc":[-85.5247773,42.025766]},"n1821014635":{"id":"n1821014635","loc":[-85.5908938,41.9902384]},"n1821014636":{"id":"n1821014636","loc":[-85.5917682,41.9860637]},"n1821014637":{"id":"n1821014637","loc":[-85.5456556,42.0166797]},"n1821014638":{"id":"n1821014638","loc":[-85.5795749,42.0032352]},"n1821014639":{"id":"n1821014639","loc":[-85.6103988,41.9723456]},"n1821014642":{"id":"n1821014642","loc":[-85.5818816,42.0022466]},"n1821014643":{"id":"n1821014643","loc":[-85.5570604,42.0091586]},"n1821014644":{"id":"n1821014644","loc":[-85.5952886,41.9803792]},"n1821014645":{"id":"n1821014645","loc":[-85.5780366,42.0040343]},"n1821014646":{"id":"n1821014646","loc":[-85.6050505,41.9751971]},"n1821014647":{"id":"n1821014647","loc":[-85.5854435,41.9946162]},"n1821014648":{"id":"n1821014648","loc":[-85.5452278,42.0168768]},"n1821014649":{"id":"n1821014649","loc":[-85.6023254,41.9780166]},"n1821014651":{"id":"n1821014651","loc":[-85.5761899,42.0046783]},"n1821014653":{"id":"n1821014653","loc":[-85.5897351,41.9876707]},"n1821014657":{"id":"n1821014657","loc":[-85.5963601,41.9808998]},"n1821014658":{"id":"n1821014658","loc":[-85.5892952,41.9951983]},"n1821014660":{"id":"n1821014660","loc":[-85.5778328,42.0037194]},"n1821014661":{"id":"n1821014661","loc":[-85.5541475,42.0125705]},"n1821014663":{"id":"n1821014663","loc":[-85.5914047,41.9856469]},"n1821014664":{"id":"n1821014664","loc":[-85.6101681,41.9727723]},"n1821014665":{"id":"n1821014665","loc":[-85.5910172,41.9854696]},"n1821014666":{"id":"n1821014666","loc":[-85.5398688,42.0187699]},"n1821014667":{"id":"n1821014667","loc":[-85.5218752,42.0282884]},"n1821014668":{"id":"n1821014668","loc":[-85.5159582,42.0329384]},"n1821014669":{"id":"n1821014669","loc":[-85.5898102,41.9847319]},"n1821014670":{"id":"n1821014670","loc":[-85.5734809,42.0066235]},"n1821014671":{"id":"n1821014671","loc":[-85.5922939,41.980852]},"n1821014672":{"id":"n1821014672","loc":[-85.6023629,41.9781163]},"n1821014674":{"id":"n1821014674","loc":[-85.5409953,42.0191724]},"n1821014676":{"id":"n1821014676","loc":[-85.584435,41.9949909]},"n1821014677":{"id":"n1821014677","loc":[-85.5972399,41.9783835]},"n1821014678":{"id":"n1821014678","loc":[-85.5616738,42.0071337]},"n1821014681":{"id":"n1821014681","loc":[-85.5202994,42.0310755]},"n1821014682":{"id":"n1821014682","loc":[-85.5915912,41.9857767]},"n1821014684":{"id":"n1821014684","loc":[-85.6022288,41.977897]},"n1821014687":{"id":"n1821014687","loc":[-85.5933024,41.9846362]},"n1821014688":{"id":"n1821014688","loc":[-85.5846871,41.9956169]},"n1821014689":{"id":"n1821014689","loc":[-85.5898209,41.99037]},"n1821014691":{"id":"n1821014691","loc":[-85.5448939,42.0149261]},"n1821014692":{"id":"n1821014692","loc":[-85.5977763,41.9786348]},"n1821014694":{"id":"n1821014694","loc":[-85.5767706,42.0034523]},"n1821014695":{"id":"n1821014695","loc":[-85.6103559,41.9726766]},"n1821014697":{"id":"n1821014697","loc":[-85.5922134,41.9809876]},"n1821014698":{"id":"n1821014698","loc":[-85.5935277,41.9831728]},"n1821014700":{"id":"n1821014700","loc":[-85.5674674,42.0078273]},"n1821014703":{"id":"n1821014703","loc":[-85.6021,41.9778053]},"n1821014704":{"id":"n1821014704","loc":[-85.5756763,42.0053737]},"n1821014705":{"id":"n1821014705","loc":[-85.5887695,41.9895207]},"n1821014707":{"id":"n1821014707","loc":[-85.6061073,41.9746866]},"n1821014708":{"id":"n1821014708","loc":[-85.6033446,41.9751692]},"n1821014710":{"id":"n1821014710","loc":[-85.5180986,42.0322332]},"n1821014711":{"id":"n1821014711","loc":[-85.543365,42.0163569]},"n1821014712":{"id":"n1821014712","loc":[-85.6030656,41.9753646]},"n1821014713":{"id":"n1821014713","loc":[-85.6104417,41.9704792]},"n1821014714":{"id":"n1821014714","loc":[-85.5205716,42.030998]},"n1821014716":{"id":"n1821014716","loc":[-85.516382,42.032536]},"n1821014717":{"id":"n1821014717","loc":[-85.5932863,41.9820882]},"n1821014718":{"id":"n1821014718","loc":[-85.5361928,42.0194974]},"n1821014720":{"id":"n1821014720","loc":[-85.6011613,41.9773586]},"n1821014721":{"id":"n1821014721","loc":[-85.554287,42.0109124]},"n1821014722":{"id":"n1821014722","loc":[-85.5577524,42.0103425]},"n1821014725":{"id":"n1821014725","loc":[-85.5867256,41.9921004]},"n1821014726":{"id":"n1821014726","loc":[-85.5856045,41.9968807]},"n1821014727":{"id":"n1821014727","loc":[-85.5545445,42.0106454]},"n1821014728":{"id":"n1821014728","loc":[-85.5923797,41.9842534]},"n1821014729":{"id":"n1821014729","loc":[-85.5696346,42.0081462]},"n1821014730":{"id":"n1821014730","loc":[-85.5998322,41.9786884]},"n1821014735":{"id":"n1821014735","loc":[-85.5337426,42.0218266]},"n1821014736":{"id":"n1821014736","loc":[-85.5847944,41.994672]},"n1821014740":{"id":"n1821014740","loc":[-85.5315271,42.0238669]},"n1821014741":{"id":"n1821014741","loc":[-85.5248846,42.027085]},"n1821014742":{"id":"n1821014742","loc":[-85.5853376,41.997018]},"n1821014743":{"id":"n1821014743","loc":[-85.5894883,41.988811]},"n1821014745":{"id":"n1821014745","loc":[-85.6095311,41.9726226]},"n1821014746":{"id":"n1821014746","loc":[-85.5531511,42.0133416]},"n1821014747":{"id":"n1821014747","loc":[-85.5735882,42.007058]},"n1821014749":{"id":"n1821014749","loc":[-85.5428554,42.0164366]},"n1821014751":{"id":"n1821014751","loc":[-85.5395255,42.0186304]},"n1821014752":{"id":"n1821014752","loc":[-85.571378,42.0083176]},"n1821014754":{"id":"n1821014754","loc":[-85.5541918,42.0113925]},"n1821014755":{"id":"n1821014755","loc":[-85.5278029,42.0250806]},"n1821014756":{"id":"n1821014756","loc":[-85.5936725,41.9827102]},"n1821014757":{"id":"n1821014757","loc":[-85.5176266,42.0346677]},"n1821014758":{"id":"n1821014758","loc":[-85.6096692,41.9714245]},"n1821014759":{"id":"n1821014759","loc":[-85.5770321,42.0034266]},"n1821014761":{"id":"n1821014761","loc":[-85.5988921,41.9779369]},"n1821014762":{"id":"n1821014762","loc":[-85.5811788,42.0024499]},"n1821014763":{"id":"n1821014763","loc":[-85.5154003,42.0381101]},"n1821014764":{"id":"n1821014764","loc":[-85.5155827,42.0374089]},"n1821014765":{"id":"n1821014765","loc":[-85.5891249,41.9884978]},"n1821014766":{"id":"n1821014766","loc":[-85.5313863,42.0238293]},"n1821014768":{"id":"n1821014768","loc":[-85.593297,41.9833363]},"n1821014769":{"id":"n1821014769","loc":[-85.5849446,41.9957245]},"n1821014770":{"id":"n1821014770","loc":[-85.5537774,42.0130847]},"n1821014771":{"id":"n1821014771","loc":[-85.6111766,41.9706069]},"n1821014772":{"id":"n1821014772","loc":[-85.5585477,42.008989]},"n1821014774":{"id":"n1821014774","loc":[-85.5928142,41.9852623]},"n1821014777":{"id":"n1821014777","loc":[-85.5891933,41.9882608]},"n1821014778":{"id":"n1821014778","loc":[-85.5926909,41.9817532]},"n1821014779":{"id":"n1821014779","loc":[-85.5260272,42.0252201]},"n1821014781":{"id":"n1821014781","loc":[-85.5894615,41.9950468]},"n1821014782":{"id":"n1821014782","loc":[-85.5461063,42.0143242]},"n1821014783":{"id":"n1821014783","loc":[-85.5711527,42.0085886]},"n1821014784":{"id":"n1821014784","loc":[-85.5329379,42.0218624]},"n1821014786":{"id":"n1821014786","loc":[-85.583047,42.0020252]},"n1821014787":{"id":"n1821014787","loc":[-85.5758962,42.0054095]},"n1821014788":{"id":"n1821014788","loc":[-85.5626354,42.0077733]},"n1821014789":{"id":"n1821014789","loc":[-85.6029852,41.9755999]},"n1821014790":{"id":"n1821014790","loc":[-85.5892362,41.9886755]},"n1821014791":{"id":"n1821014791","loc":[-85.5157597,42.0372017]},"n1821014793":{"id":"n1821014793","loc":[-85.6054582,41.9751094]},"n1821014794":{"id":"n1821014794","loc":[-85.5986936,41.9778412]},"n1821014795":{"id":"n1821014795","loc":[-85.5880775,41.98976]},"n1821014796":{"id":"n1821014796","loc":[-85.5858727,41.9963624]},"n1821014798":{"id":"n1821014798","loc":[-85.5792543,42.0035958]},"n1821014799":{"id":"n1821014799","loc":[-85.5921665,41.9838326]},"n1821014801":{"id":"n1821014801","loc":[-85.599214,41.9782599]},"n1821014802":{"id":"n1821014802","loc":[-85.5571905,42.0090967]},"n1821014803":{"id":"n1821014803","loc":[-85.5426891,42.0173612]},"n1821014804":{"id":"n1821014804","loc":[-85.5889626,41.9896404]},"n1821014805":{"id":"n1821014805","loc":[-85.5491264,42.0141648]},"n1821014806":{"id":"n1821014806","loc":[-85.5618897,42.0072631]},"n1821014808":{"id":"n1821014808","loc":[-85.5573501,42.0109802]},"n1821014809":{"id":"n1821014809","loc":[-85.5983463,41.9778031]},"n1821014810":{"id":"n1821014810","loc":[-85.5885173,41.9895128]},"n1821014811":{"id":"n1821014811","loc":[-85.6084998,41.9721143]},"n1821014812":{"id":"n1821014812","loc":[-85.5737598,42.0056389]},"n1821014814":{"id":"n1821014814","loc":[-85.5542173,42.0118132]},"n1821014816":{"id":"n1821014816","loc":[-85.5277868,42.024451]},"n1821014817":{"id":"n1821014817","loc":[-85.5403999,42.0191724]},"n1821014819":{"id":"n1821014819","loc":[-85.5983879,41.9791452]},"n1821014820":{"id":"n1821014820","loc":[-85.5891302,41.9897578]},"n1821014822":{"id":"n1821014822","loc":[-85.5930731,41.9805108]},"n1821014824":{"id":"n1821014824","loc":[-85.515395,42.0378471]},"n1821014825":{"id":"n1821014825","loc":[-85.5352755,42.0205136]},"n1821014826":{"id":"n1821014826","loc":[-85.5502744,42.0133398]},"n1821014828":{"id":"n1821014828","loc":[-85.5701295,42.0088256]},"n1821014830":{"id":"n1821014830","loc":[-85.5888929,41.9953099]},"n1821014832":{"id":"n1821014832","loc":[-85.5880077,41.9901547]},"n1821014833":{"id":"n1821014833","loc":[-85.5451192,42.0157072]},"n1821014834":{"id":"n1821014834","loc":[-85.6096478,41.9711932]},"n1821014835":{"id":"n1821014835","loc":[-85.5806424,42.0026532]},"n1821014836":{"id":"n1821014836","loc":[-85.5911674,41.9868732]},"n1821014838":{"id":"n1821014838","loc":[-85.5930302,41.9836571]},"n1821014839":{"id":"n1821014839","loc":[-85.588925,41.9938148]},"n1821014840":{"id":"n1821014840","loc":[-85.6111874,41.9705311]},"n1821014841":{"id":"n1821014841","loc":[-85.5680843,42.0075842]},"n1821014842":{"id":"n1821014842","loc":[-85.6012793,41.9775062]},"n1821014843":{"id":"n1821014843","loc":[-85.5855562,41.9989777]},"n1821014844":{"id":"n1821014844","loc":[-85.5506137,42.0131662]},"n1821014845":{"id":"n1821014845","loc":[-85.5270049,42.025457]},"n1821014846":{"id":"n1821014846","loc":[-85.5257054,42.025244]},"n1821014847":{"id":"n1821014847","loc":[-85.6011184,41.9771832]},"n1821014848":{"id":"n1821014848","loc":[-85.515534,42.0389234]},"n1821014850":{"id":"n1821014850","loc":[-85.5847032,42.0010347]},"n1821014853":{"id":"n1821014853","loc":[-85.5361499,42.019063]},"n1821014854":{"id":"n1821014854","loc":[-85.5439176,42.0165721]},"n1821014855":{"id":"n1821014855","loc":[-85.5838825,42.0017284]},"n1821014857":{"id":"n1821014857","loc":[-85.5542173,42.0122317]},"n1821014859":{"id":"n1821014859","loc":[-85.5708201,42.0089195]},"n1821014860":{"id":"n1821014860","loc":[-85.5844833,41.9954415]},"n1821014862":{"id":"n1821014862","loc":[-85.5223204,42.0295396]},"n1821014863":{"id":"n1821014863","loc":[-85.5777898,42.0035918]},"n1821014864":{"id":"n1821014864","loc":[-85.591044,41.9898078]},"n1821014865":{"id":"n1821014865","loc":[-85.5973204,41.980182]},"n1821014866":{"id":"n1821014866","loc":[-85.5699578,42.0085825]},"n1821014867":{"id":"n1821014867","loc":[-85.5210598,42.0305278]},"n1821014868":{"id":"n1821014868","loc":[-85.5929108,41.9819008]},"n1821014869":{"id":"n1821014869","loc":[-85.5279799,42.0242995]},"n1821014870":{"id":"n1821014870","loc":[-85.5196114,42.0320539]},"n1821014871":{"id":"n1821014871","loc":[-85.5785449,42.0040883]},"n1821014872":{"id":"n1821014872","loc":[-85.588292,41.9895766]},"n1821014873":{"id":"n1821014873","loc":[-85.5160172,42.0331775]},"n1821014874":{"id":"n1821014874","loc":[-85.5688849,42.0077016]},"n1821014876":{"id":"n1821014876","loc":[-85.5857976,41.9996036]},"n1821014879":{"id":"n1821014879","loc":[-85.5990906,41.9780765]},"n1821014881":{"id":"n1821014881","loc":[-85.5483647,42.0144279]},"n1821014883":{"id":"n1821014883","loc":[-85.5691209,42.0077972]},"n1821014885":{"id":"n1821014885","loc":[-85.6076844,41.9721103]},"n1821014886":{"id":"n1821014886","loc":[-85.6015489,41.9766147]},"n1821014887":{"id":"n1821014887","loc":[-85.574822,42.0052802]},"n1821014888":{"id":"n1821014888","loc":[-85.5880024,41.9899593]},"n1821014890":{"id":"n1821014890","loc":[-85.5909421,41.9893772]},"n1821014892":{"id":"n1821014892","loc":[-85.5497326,42.0138141]},"n1821014893":{"id":"n1821014893","loc":[-85.5167106,42.0357811]},"n1821014895":{"id":"n1821014895","loc":[-85.5844404,41.9952501]},"n1821014896":{"id":"n1821014896","loc":[-85.5362465,42.0192662]},"n1821014898":{"id":"n1821014898","loc":[-85.5906095,41.9889147]},"n1821014899":{"id":"n1821014899","loc":[-85.5590667,42.0089354]},"n1821014900":{"id":"n1821014900","loc":[-85.5921598,41.9844209]},"n1821014902":{"id":"n1821014902","loc":[-85.5778971,42.0039266]},"n1821014903":{"id":"n1821014903","loc":[-85.603012,41.9761981]},"n1821014904":{"id":"n1821014904","loc":[-85.6108977,41.9706787]},"n1821014905":{"id":"n1821014905","loc":[-85.5685738,42.0076139]},"n1821014906":{"id":"n1821014906","loc":[-85.5392787,42.0186304]},"n1821014907":{"id":"n1821014907","loc":[-85.5227885,42.0274972]},"n1821014908":{"id":"n1821014908","loc":[-85.5857547,41.9961431]},"n1821014910":{"id":"n1821014910","loc":[-85.5610354,42.0072812]},"n1821014911":{"id":"n1821014911","loc":[-85.5209632,42.0308705]},"n1821014912":{"id":"n1821014912","loc":[-85.5709757,42.0087959]},"n1821014913":{"id":"n1821014913","loc":[-85.59231,41.9839344]},"n1821014914":{"id":"n1821014914","loc":[-85.5375245,42.0185865]},"n1821014916":{"id":"n1821014916","loc":[-85.5901548,41.9839841]},"n1821014917":{"id":"n1821014917","loc":[-85.5611213,42.0086405]},"n1821014918":{"id":"n1821014918","loc":[-85.5360426,42.0198122]},"n1821014919":{"id":"n1821014919","loc":[-85.5862817,41.9948691]},"n1821014921":{"id":"n1821014921","loc":[-85.5469807,42.0144438]},"n1821014922":{"id":"n1821014922","loc":[-85.5761309,42.0053838]},"n1821014924":{"id":"n1821014924","loc":[-85.516264,42.0332971]},"n1821014925":{"id":"n1821014925","loc":[-85.5277224,42.0246661]},"n1821014926":{"id":"n1821014926","loc":[-85.5980016,41.9798231]},"n1821014928":{"id":"n1821014928","loc":[-85.5924548,41.9806965]},"n1821014930":{"id":"n1821014930","loc":[-85.5899121,41.985023]},"n1821014931":{"id":"n1821014931","loc":[-85.5706015,42.0089492]},"n1821014932":{"id":"n1821014932","loc":[-85.515926,42.033046]},"n1821014933":{"id":"n1821014933","loc":[-85.5982377,41.9796796]},"n1821014936":{"id":"n1821014936","loc":[-85.5475721,42.0145253]},"n1821014938":{"id":"n1821014938","loc":[-85.5895701,41.9902323]},"n1821014939":{"id":"n1821014939","loc":[-85.6030495,41.9759947]},"n1821014942":{"id":"n1821014942","loc":[-85.6094721,41.9724989]},"n1821014944":{"id":"n1821014944","loc":[-85.5921973,41.9811112]},"n1821014945":{"id":"n1821014945","loc":[-85.5223526,42.0291332]},"n1821014946":{"id":"n1821014946","loc":[-85.5965103,41.9808998]},"n1821014948":{"id":"n1821014948","loc":[-85.517766,42.0349227]},"n1821014950":{"id":"n1821014950","loc":[-85.5889894,41.990996]},"n1821014951":{"id":"n1821014951","loc":[-85.5601932,42.0092902]},"n1821014954":{"id":"n1821014954","loc":[-85.6028135,41.9764055]},"n1821014955":{"id":"n1821014955","loc":[-85.5520621,42.0130666]},"n1821014956":{"id":"n1821014956","loc":[-85.593002,41.9839344]},"n1821014957":{"id":"n1821014957","loc":[-85.515926,42.0369666]},"n1821014960":{"id":"n1821014960","loc":[-85.5761255,42.003877]},"n1821014961":{"id":"n1821014961","loc":[-85.5716355,42.007911]},"n1821014962":{"id":"n1821014962","loc":[-85.5575378,42.0109045]},"n1821014963":{"id":"n1821014963","loc":[-85.5735667,42.0068188]},"n1821014964":{"id":"n1821014964","loc":[-85.5915214,41.9865861]},"n1821014965":{"id":"n1821014965","loc":[-85.5866344,41.9923157]},"n1821014967":{"id":"n1821014967","loc":[-85.5283138,42.0242256]},"n1821014968":{"id":"n1821014968","loc":[-85.5177875,42.0355801]},"n1821014969":{"id":"n1821014969","loc":[-85.548071,42.0144934]},"n1821014972":{"id":"n1821014972","loc":[-85.5611159,42.0088557]},"n1821014973":{"id":"n1821014973","loc":[-85.541686,42.0188757]},"n1821014974":{"id":"n1821014974","loc":[-85.5917628,41.9862631]},"n1821014975":{"id":"n1821014975","loc":[-85.5854864,41.9959478]},"n1821014977":{"id":"n1821014977","loc":[-85.609102,41.9722317]},"n1821014980":{"id":"n1821014980","loc":[-85.5761202,42.0042438]},"n1821014982":{"id":"n1821014982","loc":[-85.5465944,42.0143601]},"n1821014983":{"id":"n1821014983","loc":[-85.5173261,42.0342732]},"n1821014984":{"id":"n1821014984","loc":[-85.5897297,41.9888509]},"n1821014985":{"id":"n1821014985","loc":[-85.5856688,41.999181]},"n1821014986":{"id":"n1821014986","loc":[-85.5344011,42.0217251]},"n1821014987":{"id":"n1821014987","loc":[-85.601467,41.9768203]},"n1821014988":{"id":"n1821014988","loc":[-85.5457254,42.0165123]},"n1821014989":{"id":"n1821014989","loc":[-85.6023482,41.9784332]},"n1821014991":{"id":"n1821014991","loc":[-85.5361606,42.01823]},"n1821014992":{"id":"n1821014992","loc":[-85.5178465,42.0351139]},"n1821014995":{"id":"n1821014995","loc":[-85.5634293,42.0078092]},"n1821014996":{"id":"n1821014996","loc":[-85.573497,42.0072015]},"n1821014997":{"id":"n1821014997","loc":[-85.5976328,41.9799725]},"n1821014998":{"id":"n1821014998","loc":[-85.5210651,42.0303166]},"n1821015003":{"id":"n1821015003","loc":[-85.5222131,42.0288064]},"n1821015004":{"id":"n1821015004","loc":[-85.5897941,41.984405]},"n1821015005":{"id":"n1821015005","loc":[-85.5975725,41.9776099]},"n1821015006":{"id":"n1821015006","loc":[-85.5765708,42.0034903]},"n1821015007":{"id":"n1821015007","loc":[-85.5250187,42.026559]},"n1821015009":{"id":"n1821015009","loc":[-85.5426998,42.0166279]},"n1821015010":{"id":"n1821015010","loc":[-85.5957606,41.9806584]},"n1821015011":{"id":"n1821015011","loc":[-85.5262753,42.0252497]},"n1821015012":{"id":"n1821015012","loc":[-85.5266455,42.0253374]},"n1821015014":{"id":"n1821015014","loc":[-85.5515632,42.0130187]},"n1821015015":{"id":"n1821015015","loc":[-85.6024058,41.9765212]},"n1821015017":{"id":"n1821015017","loc":[-85.5175032,42.0357156]},"n1821015018":{"id":"n1821015018","loc":[-85.5302718,42.0236039]},"n1821015019":{"id":"n1821015019","loc":[-85.6024005,41.9782759]},"n1821015020":{"id":"n1821015020","loc":[-85.5907758,41.9890821]},"n1821015021":{"id":"n1821015021","loc":[-85.6019445,41.9777215]},"n1821015022":{"id":"n1821015022","loc":[-85.5942854,41.9800881]},"n1821015024":{"id":"n1821015024","loc":[-85.5325826,42.0222711]},"n1821015029":{"id":"n1821015029","loc":[-85.555093,42.0105316]},"n1821015033":{"id":"n1821015033","loc":[-85.5249704,42.0270372]},"n1821015034":{"id":"n1821015034","loc":[-85.5243965,42.0272205]},"n1821015038":{"id":"n1821015038","loc":[-85.5413426,42.0190749]},"n1821015039":{"id":"n1821015039","loc":[-85.5920431,41.9848175]},"n1821015041":{"id":"n1821015041","loc":[-85.5577685,42.0106015]},"n1821015042":{"id":"n1821015042","loc":[-85.5453606,42.0158866]},"n1821015045":{"id":"n1821015045","loc":[-85.5333228,42.0217889]},"n1821015046":{"id":"n1821015046","loc":[-85.5426891,42.0175924]},"n1821015048":{"id":"n1821015048","loc":[-85.5886836,41.9936474]},"n1821015050":{"id":"n1821015050","loc":[-85.6001152,41.9786467]},"n1821015051":{"id":"n1821015051","loc":[-85.6094064,41.9723655]},"n1821015053":{"id":"n1821015053","loc":[-85.605721,41.9749738]},"n1821015055":{"id":"n1821015055","loc":[-85.6106791,41.9705048]},"n1821015057":{"id":"n1821015057","loc":[-85.5210437,42.0307071]},"n1821015059":{"id":"n1821015059","loc":[-85.5995694,41.9786725]},"n1821015060":{"id":"n1821015060","loc":[-85.5371638,42.0182938]},"n1821015062":{"id":"n1821015062","loc":[-85.6111766,41.9704593]},"n1821015065":{"id":"n1821015065","loc":[-85.577704,42.0034921]},"n1821015067":{"id":"n1821015067","loc":[-85.5570067,42.0093699]},"n1821015068":{"id":"n1821015068","loc":[-85.5920364,41.9845525]},"n1821015069":{"id":"n1821015069","loc":[-85.5252065,42.0253954]},"n1821015072":{"id":"n1821015072","loc":[-85.5664159,42.0088517]},"n1821015073":{"id":"n1821015073","loc":[-85.5880399,41.991905]},"n1821015075":{"id":"n1821015075","loc":[-85.6099871,41.9727861]},"n1821015076":{"id":"n1821015076","loc":[-85.5319603,42.0231478]},"n1821015078":{"id":"n1821015078","loc":[-85.6036088,41.9751112]},"n1821015080":{"id":"n1821015080","loc":[-85.5983128,41.9789179]},"n1821015082":{"id":"n1821015082","loc":[-85.5614069,42.0071395]},"n1821015083":{"id":"n1821015083","loc":[-85.60968,41.9709738]},"n1821015086":{"id":"n1821015086","loc":[-85.5914195,41.9837351]},"n1821015087":{"id":"n1821015087","loc":[-85.5895473,41.9948036]},"n1821015090":{"id":"n1821015090","loc":[-85.5929913,41.9851905]},"n1821015093":{"id":"n1821015093","loc":[-85.5907396,41.9838485]},"n1821015095":{"id":"n1821015095","loc":[-85.5893864,41.9880176]},"n1821015096":{"id":"n1821015096","loc":[-85.5788024,42.0039807]},"n1821015097":{"id":"n1821015097","loc":[-85.5630592,42.0078411]},"n1821015098":{"id":"n1821015098","loc":[-85.5350609,42.0211274]},"n1821015099":{"id":"n1821015099","loc":[-85.5967195,41.9808679]},"n1821015100":{"id":"n1821015100","loc":[-85.5666734,42.0088119]},"n1821015101":{"id":"n1821015101","loc":[-85.564694,42.0077675]},"n1821015103":{"id":"n1821015103","loc":[-85.6066544,41.9726527]},"n1821015104":{"id":"n1821015104","loc":[-85.6011827,41.9769838]},"n1821015105":{"id":"n1821015105","loc":[-85.5972131,41.9776697]},"n1821015106":{"id":"n1821015106","loc":[-85.5880828,41.9903341]},"n1821015107":{"id":"n1821015107","loc":[-85.5510268,42.0130626]},"n1821015108":{"id":"n1821015108","loc":[-85.6102164,41.970543]},"n1821015109":{"id":"n1821015109","loc":[-85.5905344,41.9853899]},"n1821015111":{"id":"n1821015111","loc":[-85.5888821,41.9913429]},"n1821015112":{"id":"n1821015112","loc":[-85.606295,41.9741921]},"n1821015114":{"id":"n1821015114","loc":[-85.5969556,41.9807443]},"n1821015115":{"id":"n1821015115","loc":[-85.5882223,41.9934081]},"n1821015116":{"id":"n1821015116","loc":[-85.6104471,41.9724971]},"n1821015118":{"id":"n1821015118","loc":[-85.5406091,42.0192162]},"n1821015120":{"id":"n1821015120","loc":[-85.589955,41.9888429]},"n1821015121":{"id":"n1821015121","loc":[-85.5598821,42.0092304]},"n1821015122":{"id":"n1821015122","loc":[-85.545598,42.0144097]},"n1821015123":{"id":"n1821015123","loc":[-85.5649528,42.0079965]},"n1821015125":{"id":"n1821015125","loc":[-85.5883993,41.9917814]},"n1821015126":{"id":"n1821015126","loc":[-85.5295785,42.0239967]},"n1821015129":{"id":"n1821015129","loc":[-85.5648723,42.0078809]},"n1821015132":{"id":"n1821015132","loc":[-85.564989,42.0081103]},"n1821015133":{"id":"n1821015133","loc":[-85.5946127,41.9800841]},"n1821015134":{"id":"n1821015134","loc":[-85.583448,42.0019078]},"n1821015135":{"id":"n1821015135","loc":[-85.5905934,41.9871842]},"n1821015137":{"id":"n1821015137","loc":[-85.610608,41.9704752]},"n1821015138":{"id":"n1821015138","loc":[-85.5752257,42.0052939]},"n1821015139":{"id":"n1821015139","loc":[-85.5893864,41.9943491]},"n1821015140":{"id":"n1821015140","loc":[-85.5426247,42.0169866]},"n1821015141":{"id":"n1821015141","loc":[-85.562001,42.0074526]},"n1821015142":{"id":"n1821015142","loc":[-85.5212046,42.0301094]},"n1821015143":{"id":"n1821015143","loc":[-85.602214,41.9784531]},"n1821015144":{"id":"n1821015144","loc":[-85.5858687,41.9948293]},"n1821015145":{"id":"n1821015145","loc":[-85.5608477,42.0074805]},"n1821015146":{"id":"n1821015146","loc":[-85.5651607,42.0083614]},"n1821015147":{"id":"n1821015147","loc":[-85.5288288,42.0242495]},"n1821015149":{"id":"n1821015149","loc":[-85.5450334,42.0146989]},"n1821015151":{"id":"n1821015151","loc":[-85.5578275,42.0092304]},"n1821015154":{"id":"n1821015154","loc":[-85.6056634,41.9724511]},"n1821015155":{"id":"n1821015155","loc":[-85.5902179,41.9852742]},"n1821015156":{"id":"n1821015156","loc":[-85.5156256,42.0387157]},"n1821015157":{"id":"n1821015157","loc":[-85.5734433,42.0059459]},"n1821015158":{"id":"n1821015158","loc":[-85.6050773,41.9731273]},"n1821015160":{"id":"n1821015160","loc":[-85.5223419,42.0275233]},"n1821015163":{"id":"n1821015163","loc":[-85.6053562,41.972525]},"n1821015164":{"id":"n1821015164","loc":[-85.5850412,41.9946082]},"n1821015165":{"id":"n1821015165","loc":[-85.5359031,42.0186326]},"n1821015166":{"id":"n1821015166","loc":[-85.5608745,42.0077635]},"n1821015169":{"id":"n1821015169","loc":[-85.572876,42.0073189]},"n1821015171":{"id":"n1821015171","loc":[-85.5875424,41.9919188]},"n1821015172":{"id":"n1821015172","loc":[-85.5240116,42.0272581]},"n1821015173":{"id":"n1821015173","loc":[-85.5318369,42.0236818]},"n1821015174":{"id":"n1821015174","loc":[-85.566888,42.0086923]},"n1821015175":{"id":"n1821015175","loc":[-85.5931522,41.9850669]},"n1821015176":{"id":"n1821015176","loc":[-85.5604842,42.0093199]},"n1821015177":{"id":"n1821015177","loc":[-85.5868168,41.9927543]},"n1821015178":{"id":"n1821015178","loc":[-85.6052275,41.9732549]},"n1821015179":{"id":"n1821015179","loc":[-85.5910118,41.9900431]},"n1821015182":{"id":"n1821015182","loc":[-85.5610032,42.0082897]},"n1821015183":{"id":"n1821015183","loc":[-85.5425443,42.0179431]},"n1821015184":{"id":"n1821015184","loc":[-85.5843277,42.0014055]},"n1821015186":{"id":"n1821015186","loc":[-85.5733307,42.0063564]},"n1821015188":{"id":"n1821015188","loc":[-85.5277385,42.0248694]},"n1821015189":{"id":"n1821015189","loc":[-85.5558427,42.0108168]},"n1821015190":{"id":"n1821015190","loc":[-85.5650587,42.0082618]},"n1821015191":{"id":"n1821015191","loc":[-85.5660351,42.0088278]},"n1821015192":{"id":"n1821015192","loc":[-85.5849768,41.9980049]},"n1821015194":{"id":"n1821015194","loc":[-85.5359139,42.0188199]},"n1821015195":{"id":"n1821015195","loc":[-85.593238,41.9849194]},"n1821015197":{"id":"n1821015197","loc":[-85.5850841,41.9983239]},"n1821015199":{"id":"n1821015199","loc":[-85.5983396,41.9794283]},"n1821015204":{"id":"n1821015204","loc":[-85.5452801,42.0145355]},"n1821015205":{"id":"n1821015205","loc":[-85.5340685,42.0218407]},"n1821015207":{"id":"n1821015207","loc":[-85.5773272,42.0034186]},"n1821015209":{"id":"n1821015209","loc":[-85.5535212,42.0132419]},"n1821015211":{"id":"n1821015211","loc":[-85.6107703,41.9706045]},"n1821015212":{"id":"n1821015212","loc":[-85.6030066,41.9758193]},"n1821015213":{"id":"n1821015213","loc":[-85.5359943,42.0184213]},"n1821015214":{"id":"n1821015214","loc":[-85.5922993,41.9813305]},"n1821015215":{"id":"n1821015215","loc":[-85.5672689,42.0080465]},"n1821015217":{"id":"n1821015217","loc":[-85.5160494,42.0365682]},"n1821015218":{"id":"n1821015218","loc":[-85.5401142,42.0190351]},"n1821015219":{"id":"n1821015219","loc":[-85.5607632,42.0092282]},"n1821015220":{"id":"n1821015220","loc":[-85.5866197,41.9947894]},"n1821015221":{"id":"n1821015221","loc":[-85.6017889,41.9765132]},"n1821015222":{"id":"n1821015222","loc":[-85.5595978,42.009059]},"n1821015226":{"id":"n1821015226","loc":[-85.5871494,41.9929018]},"n1821015227":{"id":"n1821015227","loc":[-85.5857708,41.9998866]},"n1821015228":{"id":"n1821015228","loc":[-85.5317135,42.0238094]},"n1821015231":{"id":"n1821015231","loc":[-85.5733521,42.0061372]},"n1821015233":{"id":"n1821015233","loc":[-85.5855991,42.0001936]},"n1821015234":{"id":"n1821015234","loc":[-85.5213924,42.029962]},"n1821015235":{"id":"n1821015235","loc":[-85.6052221,41.9726567]},"n1821015236":{"id":"n1821015236","loc":[-85.5763723,42.0035422]},"n1821015237":{"id":"n1821015237","loc":[-85.5858512,41.9966215]},"n1821015238":{"id":"n1821015238","loc":[-85.567061,42.008439]},"n1821015239":{"id":"n1821015239","loc":[-85.5250563,42.0269057]},"n1821015240":{"id":"n1821015240","loc":[-85.5347551,42.0214263]},"n1821015241":{"id":"n1821015241","loc":[-85.6098463,41.9707066]},"n1821015242":{"id":"n1821015242","loc":[-85.5676927,42.0076519]},"n1821015243":{"id":"n1821015243","loc":[-85.516775,42.0322669]},"n1821015244":{"id":"n1821015244","loc":[-85.5762275,42.0036538]},"n1821015245":{"id":"n1821015245","loc":[-85.5583639,42.0090949]},"n1821015246":{"id":"n1821015246","loc":[-85.5554041,42.0106432]},"n1821015247":{"id":"n1821015247","loc":[-85.5973364,41.9776099]},"n1821015248":{"id":"n1821015248","loc":[-85.6098945,41.9717513]},"n1821015249":{"id":"n1821015249","loc":[-85.6045315,41.9751511]},"n1821015250":{"id":"n1821015250","loc":[-85.5579938,42.0092264]},"n1821015253":{"id":"n1821015253","loc":[-85.6058873,41.9724652]},"n1821015254":{"id":"n1821015254","loc":[-85.5869456,41.9947517]},"n1821015255":{"id":"n1821015255","loc":[-85.5936565,41.9823713]},"n1821015256":{"id":"n1821015256","loc":[-85.5218269,42.0278102]},"n1821015258":{"id":"n1821015258","loc":[-85.5887802,41.9905534]},"n1821015259":{"id":"n1821015259","loc":[-85.5901924,41.9904515]},"n1821015263":{"id":"n1821015263","loc":[-85.5249222,42.0255787]},"n1821015265":{"id":"n1821015265","loc":[-85.5175206,42.0321672]},"n1821015266":{"id":"n1821015266","loc":[-85.5275722,42.0254034]},"n1821015267":{"id":"n1821015267","loc":[-85.6016226,41.9765451]},"n1821015269":{"id":"n1821015269","loc":[-85.5569316,42.011032]},"n1821015271":{"id":"n1821015271","loc":[-85.6010714,41.9785209]},"n1821015272":{"id":"n1821015272","loc":[-85.6050666,41.9729917]},"n1821015273":{"id":"n1821015273","loc":[-85.5891235,41.99529]},"n1821015274":{"id":"n1821015274","loc":[-85.515454,42.0376439]},"n1821015276":{"id":"n1821015276","loc":[-85.5776021,42.0034443]},"n1821015277":{"id":"n1821015277","loc":[-85.6041707,41.9751453]},"n1821015278":{"id":"n1821015278","loc":[-85.5444701,42.0167435]},"n1821015280":{"id":"n1821015280","loc":[-85.5923274,41.9852202]},"n1821015283":{"id":"n1821015283","loc":[-85.5893649,41.9900271]},"n1821015284":{"id":"n1821015284","loc":[-85.5933453,41.9804412]},"n1821015285":{"id":"n1821015285","loc":[-85.5247237,42.026017]},"n1821015286":{"id":"n1821015286","loc":[-85.5286182,42.0242477]},"n1821015287":{"id":"n1821015287","loc":[-85.5904003,41.9888549]},"n1821015288":{"id":"n1821015288","loc":[-85.6062146,41.9739369]},"n1821015290":{"id":"n1821015290","loc":[-85.5762596,42.0052602]},"n1821015292":{"id":"n1821015292","loc":[-85.5849715,41.9975465]},"n1821015293":{"id":"n1821015293","loc":[-85.585229,42.0006241]},"n1821015294":{"id":"n1821015294","loc":[-85.5926922,41.9805946]},"n1821015295":{"id":"n1821015295","loc":[-85.5703387,42.0089133]},"n1821015299":{"id":"n1821015299","loc":[-85.5789955,42.0038611]},"n1821015301":{"id":"n1821015301","loc":[-85.6072888,41.9721918]},"n1821015302":{"id":"n1821015302","loc":[-85.5356349,42.0200992]},"n1821015304":{"id":"n1821015304","loc":[-85.5891772,41.994066]},"n1821015306":{"id":"n1821015306","loc":[-85.606295,41.9744952]},"n1821015307":{"id":"n1821015307","loc":[-85.538871,42.0186583]},"n1821015308":{"id":"n1821015308","loc":[-85.587997,41.994971]},"n1821015311":{"id":"n1821015311","loc":[-85.606869,41.9725809]},"n1821015312":{"id":"n1821015312","loc":[-85.5171974,42.0339943]},"n1821015314":{"id":"n1821015314","loc":[-85.5327435,42.0220479]},"n1821015315":{"id":"n1821015315","loc":[-85.5383439,42.0187282]},"n1821015316":{"id":"n1821015316","loc":[-85.5248095,42.0263119]},"n1821015318":{"id":"n1821015318","loc":[-85.5732502,42.0073051]},"n1821015319":{"id":"n1821015319","loc":[-85.5924226,41.9852663]},"n1821015321":{"id":"n1821015321","loc":[-85.5179001,42.0353052]},"n1821015322":{"id":"n1821015322","loc":[-85.5456771,42.0162413]},"n1821015323":{"id":"n1821015323","loc":[-85.5936618,41.9829096]},"n1821015325":{"id":"n1821015325","loc":[-85.5656931,42.0086582]},"n1821015326":{"id":"n1821015326","loc":[-85.5448456,42.0150975]},"n1821015327":{"id":"n1821015327","loc":[-85.5220039,42.027615]},"n1821015329":{"id":"n1821015329","loc":[-85.517884,42.0354885]},"n1821015330":{"id":"n1821015330","loc":[-85.5576666,42.0101671]},"n1821015332":{"id":"n1821015332","loc":[-85.5368754,42.0181402]},"n1821015333":{"id":"n1821015333","loc":[-85.5367078,42.0181145]},"n1821015334":{"id":"n1821015334","loc":[-85.5903909,41.9904316]},"n1821015335":{"id":"n1821015335","loc":[-85.5430767,42.0163587]},"n1821015336":{"id":"n1821015336","loc":[-85.5277492,42.0252878]},"n1821015337":{"id":"n1821015337","loc":[-85.5312146,42.0236898]},"n1821015338":{"id":"n1821015338","loc":[-85.5886568,41.991614]},"n1821015339":{"id":"n1821015339","loc":[-85.5782498,42.0040883]},"n1821015341":{"id":"n1821015341","loc":[-85.562233,42.0076457]},"n1821015342":{"id":"n1821015342","loc":[-85.588626,41.9952479]},"n1821015343":{"id":"n1821015343","loc":[-85.5762865,42.005033]},"n1821015344":{"id":"n1821015344","loc":[-85.5850841,41.9971478]},"n1821015346":{"id":"n1821015346","loc":[-85.5643144,42.0076936]},"n1821015347":{"id":"n1821015347","loc":[-85.5164893,42.0359467]},"n1821015348":{"id":"n1821015348","loc":[-85.5906846,41.9903541]},"n1821015349":{"id":"n1821015349","loc":[-85.557688,42.0107769]},"n1821015350":{"id":"n1821015350","loc":[-85.5363698,42.0181424]},"n1821015351":{"id":"n1821015351","loc":[-85.5939636,41.9801918]},"n1821015352":{"id":"n1821015352","loc":[-85.5524041,42.0131644]},"n1821015354":{"id":"n1821015354","loc":[-85.5308606,42.0236221]},"n1821015355":{"id":"n1821015355","loc":[-85.5877449,41.9932367]},"n1821015356":{"id":"n1821015356","loc":[-85.519885,42.0318586]},"n1821015357":{"id":"n1821015357","loc":[-85.5454035,42.0168431]},"n1821015358":{"id":"n1821015358","loc":[-85.5970629,41.9781881]},"n1821015359":{"id":"n1821015359","loc":[-85.5932541,41.9844767]},"n1821015360":{"id":"n1821015360","loc":[-85.5970736,41.9778252]},"n1821015361":{"id":"n1821015361","loc":[-85.537031,42.0181601]},"n1821015362":{"id":"n1821015362","loc":[-85.5548355,42.0105156]},"n1821015363":{"id":"n1821015363","loc":[-85.5168648,42.0336158]},"n1821015365":{"id":"n1821015365","loc":[-85.5870435,41.9919507]},"n1821015366":{"id":"n1821015366","loc":[-85.5719681,42.0075443]},"n1821015367":{"id":"n1821015367","loc":[-85.5969985,41.9780446]},"n1821015368":{"id":"n1821015368","loc":[-85.5926761,41.98528]},"n1821015369":{"id":"n1821015369","loc":[-85.5224009,42.0293444]},"n1821015371":{"id":"n1821015371","loc":[-85.518737,42.0322651]},"n1821015372":{"id":"n1821015372","loc":[-85.6064573,41.9726465]},"n1821015373":{"id":"n1821015373","loc":[-85.5201103,42.0313088]},"n1821015375":{"id":"n1821015375","loc":[-85.5378182,42.0186844]},"n1821015376":{"id":"n1821015376","loc":[-85.6109741,41.9706882]},"n1821015377":{"id":"n1821015377","loc":[-85.5993333,41.9785488]},"n1821015378":{"id":"n1821015378","loc":[-85.5889787,41.9907368]},"n1821015380":{"id":"n1821015380","loc":[-85.6060161,41.9737375]},"n1821015381":{"id":"n1821015381","loc":[-85.5743016,42.0053679]},"n1821015382":{"id":"n1821015382","loc":[-85.6014724,41.9776099]},"n1821015383":{"id":"n1821015383","loc":[-85.5574426,42.0091644]},"n1821015385":{"id":"n1821015385","loc":[-85.5208613,42.0309302]},"n1821015386":{"id":"n1821015386","loc":[-85.5919023,41.9837789]},"n1821015387":{"id":"n1821015387","loc":[-85.5455484,42.0160221]},"n1821015392":{"id":"n1821015392","loc":[-85.5801757,42.0028964]},"n1821015395":{"id":"n1821015395","loc":[-85.5493785,42.0139974]},"n1821015396":{"id":"n1821015396","loc":[-85.5449475,42.015488]},"n1821015398":{"id":"n1821015398","loc":[-85.611123,41.9706627]},"n1821015400":{"id":"n1821015400","loc":[-85.5935706,41.9822477]},"n1821015401":{"id":"n1821015401","loc":[-85.5724254,42.0073508]},"n1821015403":{"id":"n1821015403","loc":[-85.5486812,42.0143442]},"n1821015404":{"id":"n1821015404","loc":[-85.5161835,42.0327711]},"n1821015406":{"id":"n1821015406","loc":[-85.5921705,41.9851107]},"n1821015407":{"id":"n1821015407","loc":[-85.531912,42.0234069]},"n1821015410":{"id":"n1821015410","loc":[-85.5292566,42.024176]},"n1821015411":{"id":"n1821015411","loc":[-85.5845316,41.9948315]},"n1821015413":{"id":"n1821015413","loc":[-85.5217947,42.0280413]},"n1821015414":{"id":"n1821015414","loc":[-85.5527367,42.013272]},"n1821015415":{"id":"n1821015415","loc":[-85.5191179,42.0321973]},"n1821015416":{"id":"n1821015416","loc":[-85.5540241,42.0128655]},"n1821015418":{"id":"n1821015418","loc":[-85.5272892,42.0254849]},"n1821015419":{"id":"n1821015419","loc":[-85.5449744,42.016867]},"n1821015420":{"id":"n1821015420","loc":[-85.5852665,41.9986787]},"n1821015421":{"id":"n1821015421","loc":[-85.6102701,41.972186]},"n1821015423":{"id":"n1821015423","loc":[-85.6026365,41.9764972]},"n1821015427":{"id":"n1821015427","loc":[-85.5898692,41.9841498]},"n1821015429":{"id":"n1821015429","loc":[-85.5422546,42.0183855]},"n1821015430":{"id":"n1821015430","loc":[-85.5866505,41.9925549]},"n1821015431":{"id":"n1821015431","loc":[-85.5234376,42.0273577]},"n1821015432":{"id":"n1821015432","loc":[-85.6096746,41.9727284]},"n1821015433":{"id":"n1821015433","loc":[-85.5824891,42.0021567]},"n1821015434":{"id":"n1821015434","loc":[-85.5923905,41.9841139]},"n1821015435":{"id":"n1821015435","loc":[-85.5874565,41.9948014]},"n1821015437":{"id":"n1821015437","loc":[-85.6055279,41.9734423]},"n1821015438":{"id":"n1821015438","loc":[-85.5299379,42.0237376]},"n1821015439":{"id":"n1821015439","loc":[-85.5155022,42.0383651]},"n1821015442":{"id":"n1821015442","loc":[-85.527422,42.0254711]},"n1821015443":{"id":"n1821015443","loc":[-85.5920699,41.9849291]},"n1821015444":{"id":"n1821015444","loc":[-85.5639711,42.0077494]},"n1821015445":{"id":"n1821015445","loc":[-85.5162586,42.0361777]},"n1821015446":{"id":"n1821015446","loc":[-85.5220039,42.029695]},"n1821015448":{"id":"n1821015448","loc":[-85.5176641,42.0356956]},"n1821015449":{"id":"n1821015449","loc":[-85.5930556,41.9841577]},"n1821015451":{"id":"n1821015451","loc":[-85.5320783,42.0228848]},"n1821015452":{"id":"n1821015452","loc":[-85.5170096,42.0357235]},"n1821015453":{"id":"n1821015453","loc":[-85.5571355,42.009613]},"n1821015454":{"id":"n1821015454","loc":[-85.5609979,42.009059]},"n1821015455":{"id":"n1821015455","loc":[-85.6097336,41.9708342]},"n1821015456":{"id":"n1821015456","loc":[-85.5884476,41.9904218]},"w170843846":{"id":"w170843846","tags":{"waterway":"river"},"nodes":["n1819790555","n1819790762","n1819790547","n1819790618","n1819790898","n1819790796","n1819790534","n1819790543","n1819790541","n1819790687","n1819790877","n1819790811","n1819790670"]},"w209083541":{"id":"w209083541","tags":{"name":"Portage River","waterway":"river"},"nodes":["n1821014848","n1821015156","n1821015439","n1821014763","n1821014824","n1821015274","n1821014764","n1821014791","n1821014957","n1821015217","n1821015445","n1821015347","n1821014893","n1821015452","n1821015017","n1821015448","n1821014968","n1821015329","n1821015321","n1821014992","n1821014948","n1821014757","n1821014983","n1821015312","n1821015363","n1821014924","n1821014873","n1821014932","n1821014668","n1821015404","n1821014716","n1821015243","n1821015265","n1821014710","n1821015371","n1821015415","n1821014870","n1821015356","n1821015373","n1821014681","n1821014714","n1821015385","n1821014911","n1821015057","n1821014867","n1821014998","n1821015142","n1821015234","n1821015446","n1821014862","n1821015369","n1821014945","n1821015003","n1821014667","n1821015413","n1821015256","n1821015327","n1821015160","n1821014907","n1821015431","n1821015172","n1821015034","n1821014741","n1821015033","n1821015239","n1821015007","n1821015316","n1821015285","n1821014633","n1821015263","n1821015069","n1821014846","n1821014779","n1821015011","n1821015012","n1821014845","n1821015418","n1821015442","n1821015266","n1821015336","n1821014755","n1821015188","n1821014925","n1821014816","n1821014869","n1821014967","n1821015286","n1821015147","n1821015410","n1821015126","n1821015438","n1821015018","n1821015354","n1821015337","n1821014766","n1821014740","n1821015228","n1821015173","n1821015407","n1821015076","n1821015451","n1821015024","n1821015314","n1821014784","n1821015045","n1821014735","n1821015205","n1821014986","n1821015240","n1821015098","n1821014825","n1821015302","n1821014918","n1821014718","n1821014896","n1821014853","n1821015194","n1821015165","n1821015213","n1821014991","n1821015350","n1821015333","n1821015332","n1821015361","n1821015060","n1821014914","n1821015375","n1821015315","n1821015307","n1821014906","n1821014751","n1821014666","n1821015218","n1821014817","n1821015118","n1821014674","n1821015038","n1821014973","n1821015429","n1821015183","n1821015046","n1821014803","n1821015140","n1821015009","n1821014749","n1821015335","n1821014711","n1821014854","n1821015278","n1821015419","n1821014648","n1821015357","n1821014637","n1821014988","n1821015322","n1821015387","n1821015042","n1821014833","n1821015396","n1821015326","n1821014691","n1821015149","n1821015204","n1821015122","n1821014782","n1821014982","n1821014921","n1821014936","n1821014969","n1821014881","n1821015403","n1821014805","n1821015395","n1821014892","n1821014826","n1821014844","n1821015107","n1821015014","n1821014955","n1821015352","n1821015414","n1821014746","n1821015209","n1821014770","n1821015416","n1821014661","n1821014857","n1821014814","n1821014754","n1821014721","n1821014727","n1821015362","n1821015029","n1821015246","n1821015189","n1821014627","n1821015269","n1821014808","n1821014962","n1821015349","n1821015041","n1821014722","n1821015330","n1821015453","n1821015067","n1821014643","n1821014802","n1821015383","n1821015151","n1821015250","n1821015245","n1821014772","n1821014899","n1821015222","n1821015121","n1821014951","n1821015176","n1821015219","n1821015454","n1821014972","n1821014917","n1821015182","n1821015166","n1821015145","n1821014910","n1821015082","n1821014678","n1821014806","n1821015141","n1821015341","n1821014788","n1821015097","n1821014995","n1821015444","n1821015346","n1821015101","n1821015129","n1821015123","n1821015132","n1821015190","n1821015146","n1821015325","n1821015191","n1821015072","n1821015100","n1821015174","n1821015238","n1821015215","n1821014700","n1821015242","n1821014841","n1821014905","n1821014874","n1821014883","n1821014729","n1821014866","n1821014828","n1821015295","n1821014931","n1821014859","n1821014912","n1821014783","n1821014752","n1821014961","n1821015366","n1821015401","n1821015169","n1821015318","n1821014996","n1821014747","n1821014963","n1821014670","n1821015186","n1821015231","n1821015157","n1821014812","n1821015381","n1821014887","n1821015138","n1821014704","n1821014787","n1821014922","n1821015290","n1821015343","n1821014651","n1821014980","n1821014960","n1821015244","n1821015236","n1821015006","n1821014694","n1821014759","n1821015207","n1821015276","n1821015065","n1821014863","n1821014660","n1821014902","n1821014645","n1821015339","n1821014871","n1821015096","n1821015299","n1821014798","n1821014638","n1821015392","n1821014835","n1821014762","n1821014642","n1821015433","n1821014786","n1821015134","n1821014855","n1821015184","n1821014850","n1821015293","n1821015233","n1821015227","n1821014876","n1821014985","n1821014843","n1821015420","n1821015197","n1821015192","n1821015292","n1821015344","n1821014742","n1821014726","n1821015237","n1821014796","n1821014908","n1821014975","n1821014769","n1821014688","n1821014860","n1821014895","n1821014676","n1821015411","n1821014736","n1821015164","n1821014647","n1821015144","n1821014919","n1821015220","n1821015254","n1821015435","n1821015308","n1821015342","n1821014830","n1821015273","n1821014658","n1821014781","n1821015087","n1821015139","n1821015304","n1821014839","n1821015048","n1821015115","n1821015355","n1821015226","n1821015177","n1821015430","n1821014965","n1821014725","n1821015365","n1821015171","n1821015073","n1821015125","n1821015338","n1821015111","n1821014950","n1821015378","n1821015258","n1821015456","n1821015106","n1821014832","n1821014888","n1821014795","n1821014872","n1821014810","n1821014705","n1821014804","n1821014820","n1821015283","n1821014938","n1821014689","n1821015259","n1821015334","n1821015348","n1821014635","n1821015179","n1821014864","n1821014890","n1821015020","n1821014898","n1821015287","n1821015120","n1821014984","n1821014743","n1821014790","n1821014765","n1821014777","n1821015095","n1821014653","n1821015135","n1821014836","n1821014964","n1821014974","n1821014636","n1821014682","n1821014663","n1821014665","n1821015109","n1821015155","n1821014930","n1821014669","n1821015004","n1821015427","n1821014916","n1821015093","n1821015086","n1821015386","n1821014799","n1821014913","n1821015434","n1821014728","n1821014900","n1821015068","n1821015039","n1821015443","n1821015406","n1821015280","n1821015319","n1821015368","n1821014774","n1821015090","n1821015175","n1821015195","n1821014687","n1821015359","n1821015449","n1821014956","n1821014838","n1821014768","n1821014698","n1821015323","n1821014756","n1821015255","n1821015400","n1821014717","n1821014868","n1821014778","n1821015214","n1821014944","n1821014697","n1821014671","n1821014928","n1821015294","n1821014822","n1821015284","n1821015351","n1821015022","n1821015133","n1821014644","n1821015010","n1821014625","n1821014657","n1821014946","n1821015099","n1821015114","n1821014629","n1821014865","n1821014997","n1821014926","n1821014933","n1821015199","n1821014819","n1821015080","n1821014692","n1821014677","n1821015358","n1821015367","n1821015360","n1821015105","n1821015247","n1821015005","n1821014809","n1821014794","n1821014761","n1821014879","n1821014801","n1821015377","n1821015059","n1821014730","n1821015050","n1821015271","n1821015143","n1821014989","n1821015019","n1821014672","n1821014649","n1821014684","n1821014703","n1821015021","n1821015382","n1821014842","n1821014720","n1821014847","n1821015104","n1821014987","n1821014886","n1821015267","n1821015221","n1821015015","n1821015423","n1821014954","n1821014903","n1821014939","n1821015212","n1821014789","n1821014712","n1821014708","n1821015078","n1821015277","n1821015249","n1821014646","n1821014793","n1821015053","n1821014707","n1821015306","n1821015112","n1821015288","n1821015380","n1821015437","n1821015178","n1821015158","n1821015272","n1821015235","n1821015163","n1821015154","n1821015253","n1821014632","n1821015372","n1821015103","n1821015311","n1821015301","n1821014885","n1821014811","n1821014977","n1821015051","n1821014942","n1821014745","n1821015432","n1821015075","n1821014664","n1821014695","n1821015116","n1821014639","n1821015421","n1821015248","n1821014758","n1821014834","n1821015083","n1821015455","n1821015241","n1821015108","n1821014713","n1821015137","n1821015055","n1821015211","n1821014904","n1821015376","n1821015398","n1821014771","n1821014840","n1821015062","n1819790554","n1819790560","n1819790767","n1819790696","n1819790706","n1819790606","n1819790607","n1819790544","n1819790779","n1819790760","n1819790926","n1819790927","n1819790647","n1819790657","n1819790649","n1819790679","n1819790915","n1819790739","n1819790549","n1819790671","n1819790686","n1819790798","n1819790791","n1819790563","n1819790720","n1819790704","n1819790795","n1819790836","n1819790622","n1819790615","n1819790654","n1819790931","n1819790595","n1819790753","n1819790612","n1819790623","n1819790564","n1819790552","n1819790645","n1819790625","n1819790605","n1819790668","n1819790731","n1819790718","n1819790781","n1819790665","n1819790659","n1819790726","n1819790642","n1819790854","n1819790697","n1819790867","n1819790833","n1819790555","n1819790774","n1819790881","n1819790530","n1819790909","n1819790891","n1819790590","n1819790738","n1819790609","n1819790528","n1819790674","n1819790583","n1819790559","n1819790863","n1819790912","n1819790685","n1819790913"]},"n185955128":{"id":"n185955128","loc":[-85.6189367,41.9519432]},"n185948818":{"id":"n185948818","loc":[-85.616755,41.952231]},"n185978819":{"id":"n185978819","loc":[-85.616773,41.954737]},"n185978821":{"id":"n185978821","loc":[-85.616699,41.954742]},"n2138420714":{"id":"n2138420714","loc":[-85.6176304,41.9515154]},"n2138420715":{"id":"n2138420715","loc":[-85.6177355,41.9515717]},"n2138420716":{"id":"n2138420716","loc":[-85.6192901,41.951573]},"n2138420718":{"id":"n2138420718","loc":[-85.6171481,41.9513579]},"n2138420719":{"id":"n2138420719","loc":[-85.6165981,41.9519199]},"n2138420720":{"id":"n2138420720","loc":[-85.6165719,41.9519922]},"n2138420721":{"id":"n2138420721","loc":[-85.6165832,41.9520757]},"n2138420722":{"id":"n2138420722","loc":[-85.6166355,41.9521453]},"n2138420723":{"id":"n2138420723","loc":[-85.6169161,41.9522788]},"n2138420724":{"id":"n2138420724","loc":[-85.6170882,41.9522538]},"n2138420725":{"id":"n2138420725","loc":[-85.6189204,41.9514674]},"n2138420726":{"id":"n2138420726","loc":[-85.6180346,41.9514735]},"n2138420727":{"id":"n2138420727","loc":[-85.6180362,41.9515719]},"n2138420728":{"id":"n2138420728","loc":[-85.6189204,41.9515727]},"n2138420744":{"id":"n2138420744","loc":[-85.618919,41.9519571]},"n2138420745":{"id":"n2138420745","loc":[-85.6194575,41.9522374]},"n2138420746":{"id":"n2138420746","loc":[-85.6181777,41.9536179]},"n2138420747":{"id":"n2138420747","loc":[-85.6176582,41.9533658]},"n2138420748":{"id":"n2138420748","loc":[-85.6179871,41.9530242]},"n2138420749":{"id":"n2138420749","loc":[-85.618429,41.9532476]},"n2138420750":{"id":"n2138420750","loc":[-85.6185538,41.9531194]},"n2138420751":{"id":"n2138420751","loc":[-85.6180765,41.9528677]},"n2138420752":{"id":"n2138420752","loc":[-85.6180394,41.9528855]},"n2138420753":{"id":"n2138420753","loc":[-85.6193752,41.9521695]},"n2138420754":{"id":"n2138420754","loc":[-85.6181374,41.9535376]},"n2138420755":{"id":"n2138420755","loc":[-85.6179898,41.9535545]},"n2138420756":{"id":"n2138420756","loc":[-85.6177286,41.9534228]},"n2138420757":{"id":"n2138420757","loc":[-85.6181011,41.9530292]},"n2138420759":{"id":"n2138420759","loc":[-85.6185158,41.9531194]},"n2138420760":{"id":"n2138420760","loc":[-85.6191318,41.9520425]},"n2138420761":{"id":"n2138420761","loc":[-85.6182348,41.9529815]},"n2138420762":{"id":"n2138420762","loc":[-85.6184853,41.9524248]},"n2138420763":{"id":"n2138420763","loc":[-85.6186764,41.9525193]},"n2138420764":{"id":"n2138420764","loc":[-85.6189421,41.9526483]},"n2138420765":{"id":"n2138420765","loc":[-85.6182875,41.9531222]},"n2138420766":{"id":"n2138420766","loc":[-85.6179141,41.9535163]},"n2138420767":{"id":"n2138420767","loc":[-85.6178363,41.9535735]},"n185948824":{"id":"n185948824","loc":[-85.6165667,41.9529715]},"n2138420758":{"id":"n2138420758","loc":[-85.6184408,41.953201]},"n2138422349":{"id":"n2138422349","loc":[-85.6175136,41.9533346]},"n2138422350":{"id":"n2138422350","loc":[-85.6171867,41.9531679]},"n2138422351":{"id":"n2138422351","loc":[-85.61722,41.9531305]},"n2138422352":{"id":"n2138422352","loc":[-85.6171889,41.9531158]},"n2138422353":{"id":"n2138422353","loc":[-85.6171733,41.9531284]},"n2138422354":{"id":"n2138422354","loc":[-85.616765,41.9529207]},"n2138422355":{"id":"n2138422355","loc":[-85.6167565,41.9529355]},"n2138422356":{"id":"n2138422356","loc":[-85.6164772,41.9527911]},"n2138422357":{"id":"n2138422357","loc":[-85.6168227,41.9524261]},"n2138422358":{"id":"n2138422358","loc":[-85.6171913,41.9526158]},"n2138422359":{"id":"n2138422359","loc":[-85.6172403,41.9525589]},"n2138422360":{"id":"n2138422360","loc":[-85.6172097,41.952542]},"n2138422361":{"id":"n2138422361","loc":[-85.6173948,41.9523512]},"n2138422362":{"id":"n2138422362","loc":[-85.6174256,41.9523678]},"n2138422363":{"id":"n2138422363","loc":[-85.6174831,41.9523086]},"n2138422364":{"id":"n2138422364","loc":[-85.6173316,41.9522289]},"n2138422365":{"id":"n2138422365","loc":[-85.6174507,41.9521024]},"n2138422366":{"id":"n2138422366","loc":[-85.6174773,41.9521155]},"n2138422367":{"id":"n2138422367","loc":[-85.6176577,41.9519232]},"n2138422368":{"id":"n2138422368","loc":[-85.6176336,41.9519105]},"n2138422369":{"id":"n2138422369","loc":[-85.617747,41.9517861]},"n2138422370":{"id":"n2138422370","loc":[-85.6182675,41.9520559]},"n2138422371":{"id":"n2138422371","loc":[-85.6182105,41.9521219]},"n2138422372":{"id":"n2138422372","loc":[-85.6183863,41.9522203]},"n2138422373":{"id":"n2138422373","loc":[-85.6180984,41.9525266]},"n2138422374":{"id":"n2138422374","loc":[-85.6179159,41.9524295]},"n2138422375":{"id":"n2138422375","loc":[-85.617854,41.9524979]},"n2138422376":{"id":"n2138422376","loc":[-85.6177686,41.9524531]},"n2138422377":{"id":"n2138422377","loc":[-85.6174716,41.9527765]},"n2138422378":{"id":"n2138422378","loc":[-85.6178545,41.9529756]},"n2138425424":{"id":"n2138425424","loc":[-85.6171736,41.9536385]},"n2138425425":{"id":"n2138425425","loc":[-85.6180159,41.9535782]},"n2138425426":{"id":"n2138425426","loc":[-85.6181068,41.9536282]},"n2138425427":{"id":"n2138425427","loc":[-85.6180673,41.9542678]},"n2138425428":{"id":"n2138425428","loc":[-85.6178636,41.9542634]},"n2138425429":{"id":"n2138425429","loc":[-85.6176204,41.9542046]},"n2138425430":{"id":"n2138425430","loc":[-85.6174366,41.9541031]},"n2138425431":{"id":"n2138425431","loc":[-85.6172942,41.9539781]},"n2138425432":{"id":"n2138425432","loc":[-85.6172171,41.9538399]},"n2138425433":{"id":"n2138425433","loc":[-85.6168138,41.9543266]},"n2138425434":{"id":"n2138425434","loc":[-85.6167779,41.9538098]},"n2138425435":{"id":"n2138425435","loc":[-85.6165849,41.9537073]},"n2138425441":{"id":"n2138425441","loc":[-85.616458,41.9543184]},"n2138425442":{"id":"n2138425442","loc":[-85.6166428,41.954345]},"n2138425445":{"id":"n2138425445","loc":[-85.6181332,41.9514117]},"n2138425446":{"id":"n2138425446","loc":[-85.6183263,41.9514111]},"n2138425447":{"id":"n2138425447","loc":[-85.6185033,41.9514102]},"n2138425449":{"id":"n2138425449","loc":[-85.6186809,41.9514093]},"n2138425451":{"id":"n2138425451","loc":[-85.6188681,41.9514082]},"n2138436008":{"id":"n2138436008","loc":[-85.6170474,41.9513604]},"n2138436009":{"id":"n2138436009","loc":[-85.6164937,41.9519586]},"n2138436010":{"id":"n2138436010","loc":[-85.616497,41.9520725]},"n2138436011":{"id":"n2138436011","loc":[-85.6165654,41.9521645]},"n2138436012":{"id":"n2138436012","loc":[-85.6166631,41.9522178]},"n2138436013":{"id":"n2138436013","loc":[-85.6167327,41.9522554]},"n2138436014":{"id":"n2138436014","loc":[-85.6172383,41.9525125]},"n2138439319":{"id":"n2138439319","loc":[-85.6170432,41.9524057]},"n2138439320":{"id":"n2138439320","loc":[-85.617691,41.9517107]},"n2138439321":{"id":"n2138439321","loc":[-85.6177727,41.9516794]},"n2138439322":{"id":"n2138439322","loc":[-85.619085,41.9516811]},"n2138439323":{"id":"n2138439323","loc":[-85.6179432,41.952895]},"n2138439324":{"id":"n2138439324","loc":[-85.6180389,41.9529384]},"n2138439325":{"id":"n2138439325","loc":[-85.6176303,41.9533604]},"n2138439326":{"id":"n2138439326","loc":[-85.6175538,41.9534396]},"n2138439327":{"id":"n2138439327","loc":[-85.6173806,41.9523658]},"n2138439328":{"id":"n2138439328","loc":[-85.6171841,41.9522542]},"n2138439329":{"id":"n2138439329","loc":[-85.6172077,41.9524958]},"n2138439330":{"id":"n2138439330","loc":[-85.6171235,41.9525809]},"n2138439331":{"id":"n2138439331","loc":[-85.6180938,41.9527349]},"n2138439332":{"id":"n2138439332","loc":[-85.6177023,41.9525253]},"n2138439333":{"id":"n2138439333","loc":[-85.6175543,41.9526865]},"n2138439334":{"id":"n2138439334","loc":[-85.6179589,41.9528783]},"n185948820":{"id":"n185948820","loc":[-85.6163249,41.952701]},"n185948822":{"id":"n185948822","loc":[-85.6163757,41.952855]},"n185955123":{"id":"n185955123","loc":[-85.6198103,41.9510408]},"n185958839":{"id":"n185958839","loc":[-85.611651,41.954761]},"n185965033":{"id":"n185965033","loc":[-85.614195,41.954754]},"n185976502":{"id":"n185976502","loc":[-85.617375,41.947559]},"n185976504":{"id":"n185976504","loc":[-85.6174164,41.9510804]},"n185978828":{"id":"n185978828","loc":[-85.613542,41.954756]},"n185978830":{"id":"n185978830","loc":[-85.610373,41.954774]},"n2138420713":{"id":"n2138420713","loc":[-85.6174641,41.9506942]},"n2138420717":{"id":"n2138420717","loc":[-85.6173027,41.9512895]},"n2138420768":{"id":"n2138420768","loc":[-85.61745,41.9501974]},"n2138420773":{"id":"n2138420773","loc":[-85.6174135,41.9489136]},"n2138425436":{"id":"n2138425436","loc":[-85.6159148,41.9538036]},"n2138425437":{"id":"n2138425437","loc":[-85.6159534,41.9539677]},"n2138425438":{"id":"n2138425438","loc":[-85.6160306,41.9540846]},"n2138425439":{"id":"n2138425439","loc":[-85.6161354,41.954181]},"n2138425440":{"id":"n2138425440","loc":[-85.6162733,41.954263]},"n2138425443":{"id":"n2138425443","loc":[-85.6183273,41.9510826]},"n2138425444":{"id":"n2138425444","loc":[-85.6181354,41.9510835]},"n2138425448":{"id":"n2138425448","loc":[-85.6185033,41.9510816]},"n2138425450":{"id":"n2138425450","loc":[-85.6186816,41.9510808]},"n2138425452":{"id":"n2138425452","loc":[-85.6188641,41.9510818]},"n2138435984":{"id":"n2138435984","loc":[-85.6167607,41.9501009]},"n2138436000":{"id":"n2138436000","loc":[-85.6173169,41.947558]},"n2138436001":{"id":"n2138436001","loc":[-85.6173362,41.948883]},"n2138436002":{"id":"n2138436002","loc":[-85.6167791,41.9492952]},"n2138436003":{"id":"n2138436003","loc":[-85.6167543,41.949349]},"n2138436004":{"id":"n2138436004","loc":[-85.6167648,41.9509125]},"n2138436005":{"id":"n2138436005","loc":[-85.6168832,41.9510412]},"n2138436006":{"id":"n2138436006","loc":[-85.6170045,41.9511417]},"n2138436007":{"id":"n2138436007","loc":[-85.6170624,41.9512483]},"n2138436017":{"id":"n2138436017","loc":[-85.6168094,41.9492729]},"n2138436021":{"id":"n2138436021","loc":[-85.6167553,41.9494886]},"n2138436023":{"id":"n2138436023","loc":[-85.6167585,41.9499707]},"n2138436025":{"id":"n2138436025","loc":[-85.6167567,41.9497018]},"w203838284":{"id":"w203838284","tags":{"area":"yes","leisure":"pitch","sport":"baseball"},"nodes":["n2138425424","n2138425425","n2138425426","n2138425427","n2138425428","n2138425429","n2138425430","n2138425431","n2138425432","n2138425424"]},"w203837928":{"id":"w203837928","tags":{"highway":"service"},"nodes":["n2138420717","n2138420718","n2138420719","n2138420720","n2138420721","n2138420722","n185948818","n2138420723","n2138420724","n2138420715"]},"w203839364":{"id":"w203839364","tags":{"highway":"footway"},"nodes":["n2138439331","n2138439332"]},"w203837932":{"id":"w203837932","tags":{"amenity":"parking","area":"yes"},"nodes":["n2138420744","n2138420745","n2138420746","n2138420747","n2138420748","n2138420749","n2138420750","n2138420751","n2138420744"]},"w203839362":{"id":"w203839362","tags":{"highway":"footway"},"nodes":["n2138439327","n2138439328"]},"w203839363":{"id":"w203839363","tags":{"highway":"footway"},"nodes":["n2138439329","n2138439330"]},"w203837933":{"id":"w203837933","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n185955128","n2138420760","n2138420753","n2138420764","n2138420759","n2138420758","n2138420754","n2138420755","n2138420766","n2138420756"]},"w203837936":{"id":"w203837936","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420765","n2138420766"]},"w17966364":{"id":"w17966364","tags":{"access":"private","highway":"service","name":"Collins Dr"},"nodes":["n185961362","n185976502","n2138420773","n2138420768","n2138420713","n185976504","n2138420717","n2138420714","n2138420715","n2138420727","n2138420728","n2138420716"]},"w203838040":{"id":"w203838040","tags":{"amenity":"school","area":"yes","building":"yes","name":"Three Rivers Middle School"},"nodes":["n2138422349","n2138422350","n2138422351","n2138422352","n2138422353","n2138422354","n2138422355","n2138422356","n2138422357","n2138439330","n2138422358","n2138422359","n2138422360","n2138436014","n2138439327","n2138422361","n2138422362","n2138422363","n2138422364","n2138422365","n2138422366","n2138422367","n2138422368","n2138422369","n2138422370","n2138422371","n2138422372","n2138422373","n2138422374","n2138422375","n2138422376","n2138439332","n2138439333","n2138422377","n2138422378","n2138422349"]},"w17964049":{"id":"w17964049","tags":{"highway":"service"},"nodes":["n185955120","n185955123","n2138420716","n185955128","n2138420762","n2138420752","n2138420761","n2138420759"]},"w41074899":{"id":"w41074899","tags":{"highway":"secondary","name":"E Hoffman St","ref":"M 60"},"nodes":["n185978817","n185978819","n185978821","n185965033","n185978828","n185958839","n185978830"]},"w203839365":{"id":"w203839365","tags":{"highway":"footway"},"nodes":["n2138439333","n2138439334"]},"w203837935":{"id":"w203837935","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420762","n2138420763","n2138420764"]},"w203838287":{"id":"w203838287","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425446","n2138425447","n2138425448","n2138425443","n2138425446"]},"w203837934":{"id":"w203837934","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420760","n2138420763","n2138420761"]},"w203838289":{"id":"w203838289","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425449","n2138425451","n2138425452","n2138425450","n2138425449"]},"w17963047":{"id":"w17963047","tags":{"highway":"service"},"nodes":["n185948818","n2138436013","n185948820","n185948822","n185948824","n2138439326","n2138420767","n2138420766"]},"w203839091":{"id":"w203839091","tags":{"highway":"footway"},"nodes":["n185976502","n2138436000","n2138436001","n2138436017","n2138436002","n2138436003","n2138436021","n2138436025","n2138436023","n2138435984","n2138436004","n2138436005","n2138436006","n2138436007","n2138436008","n2138436009","n2138436010","n2138436011","n2138436012","n2138436013","n2138439319","n2138439329","n2138436014"]},"w204830797":{"id":"w204830797","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420756","n2138420757","n2138420765","n2138420758"]},"w203838288":{"id":"w203838288","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425447","n2138425449","n2138425450","n2138425448","n2138425447"]},"w203838285":{"id":"w203838285","tags":{"area":"yes","leisure":"pitch","sport":"baseball"},"nodes":["n2138425433","n2138425434","n2138425435","n2138425436","n2138425437","n2138425438","n2138425439","n2138425440","n2138425441","n2138425442","n2138425433"]},"w203838286":{"id":"w203838286","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425443","n2138425444","n2138425445","n2138425446","n2138425443"]},"w203837929":{"id":"w203837929","tags":{"amenity":"parking","area":"yes"},"nodes":["n2138420725","n2138420726","n2138420727","n2138420728","n2138420725"]},"w203839361":{"id":"w203839361","tags":{"highway":"footway"},"nodes":["n2138439319","n2138439328","n2138439320","n2138439321","n2138439322","n2138439331","n2138439334","n2138439323","n2138439324","n2138439325","n2138439326"]},"n394381698":{"id":"n394381698","loc":[-85.614471,41.954755]},"n394381699":{"id":"n394381699","loc":[-85.6152,41.954744]},"n394381700":{"id":"n394381700","loc":[-85.615201,41.954081]},"n394381701":{"id":"n394381701","loc":[-85.614426,41.954042]},"n394381702":{"id":"n394381702","loc":[-85.616319,41.954749]},"n394381704":{"id":"n394381704","loc":[-85.616152,41.954752]},"n394381706":{"id":"n394381706","loc":[-85.615201,41.95483]},"n394490775":{"id":"n394490775","loc":[-85.613971,41.954839]},"n394490782":{"id":"n394490782","loc":[-85.614372,41.954841]},"n185958835":{"id":"n185958835","loc":[-85.611615,41.953704]},"n185958837":{"id":"n185958837","loc":[-85.611636,41.953938]},"n185958842":{"id":"n185958842","loc":[-85.611187,41.951686]},"n185958844":{"id":"n185958844","loc":[-85.611087,41.951741]},"n185958845":{"id":"n185958845","loc":[-85.611034,41.951852]},"n185958847":{"id":"n185958847","loc":[-85.611016,41.95196]},"n185958849":{"id":"n185958849","loc":[-85.610989,41.95328]},"n185958851":{"id":"n185958851","loc":[-85.611021,41.953484]},"n185958852":{"id":"n185958852","loc":[-85.611091,41.953603]},"n185958853":{"id":"n185958853","loc":[-85.6112,41.953661]},"n185958855":{"id":"n185958855","loc":[-85.611364,41.953686]},"n185965031":{"id":"n185965031","loc":[-85.614204,41.953696]},"n185965032":{"id":"n185965032","loc":[-85.6142,41.953978]},"n185965062":{"id":"n185965062","loc":[-85.614617,41.951639]},"n185965064":{"id":"n185965064","loc":[-85.61463,41.951852]},"n185965066":{"id":"n185965066","loc":[-85.614642,41.953436]},"n185965068":{"id":"n185965068","loc":[-85.6146,41.953551]},"n185965071":{"id":"n185965071","loc":[-85.614487,41.95363]},"n185965073":{"id":"n185965073","loc":[-85.614354,41.953672]},"n185966288":{"id":"n185966288","loc":[-85.61179,41.953695]},"n185966290":{"id":"n185966290","loc":[-85.612232,41.953685]},"n185966293":{"id":"n185966293","loc":[-85.613438,41.953677]},"n185966349":{"id":"n185966349","loc":[-85.611323,41.951653]},"n185966351":{"id":"n185966351","loc":[-85.611892,41.951642]},"n185966352":{"id":"n185966352","loc":[-85.612216,41.951641]},"n185966353":{"id":"n185966353","loc":[-85.613111,41.951639]},"n185966354":{"id":"n185966354","loc":[-85.613396,41.95164]},"n185966355":{"id":"n185966355","loc":[-85.614221,41.95164]},"n185973839":{"id":"n185973839","loc":[-85.61341,41.951919]},"n185973840":{"id":"n185973840","loc":[-85.613438,41.953308]},"n185980222":{"id":"n185980222","loc":[-85.613781,41.955164]},"n185980223":{"id":"n185980223","loc":[-85.613815,41.955237]},"n185980225":{"id":"n185980225","loc":[-85.613837,41.955316]},"n185990345":{"id":"n185990345","loc":[-85.612211,41.951977]},"n185955743":{"id":"n185955743","loc":[-85.613873,41.95635]},"n185980227":{"id":"n185980227","loc":[-85.613851,41.955415]},"n185980229":{"id":"n185980229","loc":[-85.613918,41.957134]},"n394381703":{"id":"n394381703","loc":[-85.616287,41.955674]},"n394381705":{"id":"n394381705","loc":[-85.615164,41.955676]},"n394490777":{"id":"n394490777","loc":[-85.613973,41.955979]},"n394490780":{"id":"n394490780","loc":[-85.614364,41.955987]},"w17965307":{"id":"w17965307","tags":{"highway":"residential","name":"Bates Ave"},"nodes":["n185958842","n185966349","n185966351","n185966352","n185966353","n185966354","n185966355","n185965062"]},"w17967957":{"id":"w17967957","tags":{"highway":"residential","name":"Krum Ave"},"nodes":["n185966352","n185990345","n185966290"]},"w17964508":{"id":"w17964508","tags":{"highway":"residential","name":"Blossom Dr"},"nodes":["n185958842","n185958844","n185958845","n185958847","n185958849","n185958851","n185958852","n185958853","n185958855","n185958835"]},"w17964507":{"id":"w17964507","tags":{"highway":"residential","name":"Blossom Dr"},"nodes":["n185958835","n185958837","n185958839"]},"w34367080":{"id":"w34367080","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394381699","n394381706","n394381705","n394381703","n394381702","n394381704","n394381699"]},"w17965302":{"id":"w17965302","tags":{"highway":"residential","name":"Clausen Ave"},"nodes":["n185958835","n185966288","n185966290","n185966293","n185965031"]},"w17965156":{"id":"w17965156","tags":{"highway":"residential","name":"Orchard Dr"},"nodes":["n185965062","n185965064","n185965066","n185965068","n185965071","n185965073","n185965031"]},"w34369812":{"id":"w34369812","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490775","n394490777","n394490780","n394490782","n394490775"]},"w17965151":{"id":"w17965151","tags":{"highway":"residential","name":"Orchard Dr"},"nodes":["n185965031","n185965032","n185965033"]},"w17966756":{"id":"w17966756","tags":{"access":"private","highway":"service","name":"Lockport Dr"},"nodes":["n185978828","n185980222","n185980223","n185980225","n185980227","n185955743","n185980229"]},"w17966056":{"id":"w17966056","tags":{"highway":"residential","name":"Angell Ave"},"nodes":["n185966354","n185973839","n185973840","n185966293"]},"w34367079":{"id":"w34367079","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394381700","n394381701","n394381698","n394381699","n394381700"]},"n185955744":{"id":"n185955744","loc":[-85.611753,41.956208]},"n185988932":{"id":"n185988932","loc":[-85.6159,41.956336]},"n185988934":{"id":"n185988934","loc":[-85.6159158,41.9590646]},"n185988935":{"id":"n185988935","loc":[-85.6157358,41.959364],"tags":{"highway":"turning_circle"}},"n2138447007":{"id":"n2138447007","loc":[-85.6130784,41.9590689]},"n2138447008":{"id":"n2138447008","loc":[-85.6133328,41.9593805]},"n2138447003":{"id":"n2138447003","loc":[-85.610238,41.9547745]},"n2138447004":{"id":"n2138447004","loc":[-85.6102652,41.9566041]},"n2138447005":{"id":"n2138447005","loc":[-85.610325,41.9568823]},"n2138447006":{"id":"n2138447006","loc":[-85.6105644,41.9571383]},"n2138447009":{"id":"n2138447009","loc":[-85.6135946,41.959948]},"n2138447010":{"id":"n2138447010","loc":[-85.6136071,41.9629372]},"n2138447011":{"id":"n2138447011","loc":[-85.6134392,41.9633182]},"n2138447012":{"id":"n2138447012","loc":[-85.6130151,41.9636073]},"n2138447013":{"id":"n2138447013","loc":[-85.6122729,41.9637125]},"n2138447014":{"id":"n2138447014","loc":[-85.6056682,41.963752]},"w17964174":{"id":"w17964174","tags":{"access":"private","highway":"service"},"nodes":["n185955743","n185955744"]},"w17967743":{"id":"w17967743","tags":{"access":"private","highway":"service","name":"Manistee River Rd"},"nodes":["n185971574","n185988932","n185971407","n185981301","n185967987","n185988934","n185988935"]},"w203839666":{"id":"w203839666","tags":{"highway":"residential","name":"Hov Aire Drive"},"nodes":["n2138447003","n2138447004","n2138447005","n2138447006","n2138447007","n2138447008","n2138447009","n2138447010","n2138447011","n2138447012","n2138447013","n2138447014"]}}';iD.data = {"deprecated":[{"old":{"amenity":"firepit"},"replace":{"leisure":"firepit"}},{"old":{"barrier":"wire_fence"},"replace":{"barrier":"fence","fence_type":"chain"}},{"old":{"barrier":"wood_fence"},"replace":{"barrier":"fence","fence_type":"wood"}},{"old":{"highway":"ford"},"replace":{"ford":"yes"}},{"old":{"highway":"stile"},"replace":{"barrier":"stile"}},{"old":{"highway":"incline"},"replace":{"highway":"road","incline":"up"}},{"old":{"highway":"incline_steep"},"replace":{"highway":"road","incline":"up"}},{"old":{"highway":"unsurfaced"},"replace":{"highway":"road","incline":"unpaved"}},{"old":{"landuse":"wood"},"replace":{"landuse":"forest","natural":"wood"}},{"old":{"natural":"marsh"},"replace":{"natural":"wetland","wetland":"marsh"}},{"old":{"power_source":"*"},"replace":{"generator:source":"$1"}},{"old":{"power_rating":"*"},"replace":{"generator:output":"$1"}},{"old":{"shop":"organic"},"replace":{"shop":"supermarket","organic":"only"}}],"discarded":["created_by","odbl","odbl:note","tiger:upload_uuid","tiger:tlid","tiger:source","tiger:separated","geobase:datasetName","geobase:uuid","sub_sea:type","KSJ2:ADS","KSJ2:ARE","KSJ2:AdminArea","KSJ2:COP_label","KSJ2:DFD","KSJ2:INT","KSJ2:INT_label","KSJ2:LOC","KSJ2:LPN","KSJ2:OPC","KSJ2:PubFacAdmin","KSJ2:RAC","KSJ2:RAC_label","KSJ2:RIC","KSJ2:RIN","KSJ2:WSC","KSJ2:coordinate","KSJ2:curve_id","KSJ2:curve_type","KSJ2:filename","KSJ2:lake_id","KSJ2:lat","KSJ2:long","KSJ2:river_id","yh:LINE_NAME","yh:LINE_NUM","yh:STRUCTURE","yh:TOTYUMONO","yh:TYPE","yh:WIDTH","yh:WIDTH_RANK","SK53_bulk:load"],"wikipedia":[["Abkhazian","Аҧсшәа","ab"],["Achinese","Acèh","ace"],["Afrikaans","Afrikaans","af"],["Akan","Akan","ak"],["Alemannisch","Alemannisch","als"],["Amharic","አማርኛ","am"],["Aragonese","aragonés","an"],["Old English","Ænglisc","ang"],["Arabic","العربية","ar"],["Aramaic","ܐܪܡܝܐ","arc"],["Egyptian Arabic","مصرى","arz"],["Assamese","অসমীয়া","as"],["Asturian","asturianu","ast"],["Avaric","авар","av"],["Aymara","Aymar aru","ay"],["Azerbaijani","azərbaycanca","az"],["South Azerbaijani","تۆرکجه","azb"],["Bashkir","башҡортса","ba"],["Bavarian","Boarisch","bar"],["Samogitian","žemaitėška","bat-smg"],["Bikol Central","Bikol Central","bcl"],["Belarusian","беларуская","be"],["беларуская (тарашкевіца)","беларуская (тарашкевіца)","be-x-old"],["Bulgarian","български","bg"],["भोजपुरी","भोजपुरी","bh"],["Bislama","Bislama","bi"],["Banjar","Bahasa Banjar","bjn"],["Bambara","bamanankan","bm"],["Bengali","বাংলা","bn"],["Tibetan","བོད་ཡིག","bo"],["Bishnupriya","বিষ্ণুপ্রিয়া মণিপুরী","bpy"],["Breton","brezhoneg","br"],["Bosnian","bosanski","bs"],["Buginese","ᨅᨔ ᨕᨘᨁᨗ","bug"],["буряад","буряад","bxr"],["Catalan","català","ca"],["Chavacano de Zamboanga","Chavacano de Zamboanga","cbk-zam"],["Min Dong Chinese","Mìng-dĕ̤ng-ngṳ̄","cdo"],["Chechen","нохчийн","ce"],["Cebuano","Cebuano","ceb"],["Chamorro","Chamoru","ch"],["Cherokee","ᏣᎳᎩ","chr"],["Cheyenne","Tsetsêhestâhese","chy"],["Central Kurdish","کوردیی ناوەندی","ckb"],["Corsican","corsu","co"],["Cree","Nēhiyawēwin / ᓀᐦᐃᔭᐍᐏᐣ","cr"],["Crimean Turkish","qırımtatarca","crh"],["Czech","čeština","cs"],["Kashubian","kaszëbsczi","csb"],["Church Slavic","словѣньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ","cu"],["Chuvash","Чӑвашла","cv"],["Welsh","Cymraeg","cy"],["Danish","dansk","da"],["German","Deutsch","de"],["Zazaki","Zazaki","diq"],["Lower Sorbian","dolnoserbski","dsb"],["Divehi","ދިވެހިބަސް","dv"],["Dzongkha","ཇོང་ཁ","dz"],["Ewe","eʋegbe","ee"],["Greek","Ελληνικά","el"],["Emiliano-Romagnolo","emiliàn e rumagnòl","eml"],["English","English","en"],["Esperanto","Esperanto","eo"],["Spanish","español","es"],["Estonian","eesti","et"],["Basque","euskara","eu"],["Extremaduran","estremeñu","ext"],["Persian","فارسی","fa"],["Fulah","Fulfulde","ff"],["Finnish","suomi","fi"],["Võro","Võro","fiu-vro"],["Fijian","Na Vosa Vakaviti","fj"],["Faroese","føroyskt","fo"],["French","français","fr"],["Arpitan","arpetan","frp"],["Northern Frisian","Nordfriisk","frr"],["Friulian","furlan","fur"],["Western Frisian","Frysk","fy"],["Irish","Gaeilge","ga"],["Gagauz","Gagauz","gag"],["Gan Chinese","贛語","gan"],["Scottish Gaelic","Gàidhlig","gd"],["Galician","galego","gl"],["Gilaki","گیلکی","glk"],["Guarani","Avañe'ẽ","gn"],["Goan Konkani","गोवा कोंकणी / Gova Konknni","gom"],["Gothic","𐌲𐌿𐍄𐌹𐍃𐌺","got"],["Gujarati","ગુજરાતી","gu"],["Manx","Gaelg","gv"],["Hausa","Hausa","ha"],["Hakka Chinese","客家語/Hak-kâ-ngî","hak"],["Hawaiian","Hawai`i","haw"],["Hebrew","עברית","he"],["Hindi","हिन्दी","hi"],["Fiji Hindi","Fiji Hindi","hif"],["Croatian","hrvatski","hr"],["Upper Sorbian","hornjoserbsce","hsb"],["Haitian","Kreyòl ayisyen","ht"],["Hungarian","magyar","hu"],["Armenian","Հայերեն","hy"],["Interlingua","interlingua","ia"],["Indonesian","Bahasa Indonesia","id"],["Interlingue","Interlingue","ie"],["Igbo","Igbo","ig"],["Inupiaq","Iñupiak","ik"],["Iloko","Ilokano","ilo"],["Ido","Ido","io"],["Icelandic","íslenska","is"],["Italian","italiano","it"],["Inuktitut","ᐃᓄᒃᑎᑐᑦ/inuktitut","iu"],["Japanese","日本語","ja"],["Lojban","Lojban","jbo"],["Javanese","Basa Jawa","jv"],["Georgian","ქართული","ka"],["Kara-Kalpak","Qaraqalpaqsha","kaa"],["Kabyle","Taqbaylit","kab"],["Kabardian","Адыгэбзэ","kbd"],["Kongo","Kongo","kg"],["Kikuyu","Gĩkũyũ","ki"],["Kazakh","қазақша","kk"],["Kalaallisut","kalaallisut","kl"],["Khmer","ភាសាខ្មែរ","km"],["Kannada","ಕನ್ನಡ","kn"],["Korean","한국어","ko"],["Komi-Permyak","Перем Коми","koi"],["Karachay-Balkar","къарачай-малкъар","krc"],["Kashmiri","कॉशुर / کٲشُر","ks"],["Colognian","Ripoarisch","ksh"],["Kurdish","Kurdî","ku"],["Komi","коми","kv"],["Cornish","kernowek","kw"],["Kyrgyz","Кыргызча","ky"],["Latin","Latina","la"],["Ladino","Ladino","lad"],["Luxembourgish","Lëtzebuergesch","lb"],["лакку","лакку","lbe"],["Lezghian","лезги","lez"],["Ganda","Luganda","lg"],["Limburgish","Limburgs","li"],["Ligurian","Ligure","lij"],["Lombard","lumbaart","lmo"],["Lingala","lingála","ln"],["Lao","ລາວ","lo"],["Northern Luri","لۊری شومالی","lrc"],["Lithuanian","lietuvių","lt"],["Latgalian","latgaļu","ltg"],["Latvian","latviešu","lv"],["Maithili","मैथिली","mai"],["Basa Banyumasan","Basa Banyumasan","map-bms"],["Moksha","мокшень","mdf"],["Malagasy","Malagasy","mg"],["Eastern Mari","олык марий","mhr"],["Maori","Māori","mi"],["Minangkabau","Baso Minangkabau","min"],["Macedonian","македонски","mk"],["Malayalam","മലയാളം","ml"],["Mongolian","монгол","mn"],["Marathi","मराठी","mr"],["Western Mari","кырык мары","mrj"],["Malay","Bahasa Melayu","ms"],["Maltese","Malti","mt"],["Mirandese","Mirandés","mwl"],["Burmese","မြန်မာဘာသာ","my"],["Erzya","эрзянь","myv"],["Mazanderani","مازِرونی","mzn"],["Nauru","Dorerin Naoero","na"],["Nāhuatl","Nāhuatl","nah"],["Neapolitan","Napulitano","nap"],["Low German","Plattdüütsch","nds"],["Low Saxon (Netherlands)","Nedersaksies","nds-nl"],["Nepali","नेपाली","ne"],["Newari","नेपाल भाषा","new"],["Dutch","Nederlands","nl"],["Norwegian Nynorsk","norsk nynorsk","nn"],["Norwegian","norsk bokmål","no"],["Novial","Novial","nov"],["Nouormand","Nouormand","nrm"],["Northern Sotho","Sesotho sa Leboa","nso"],["Navajo","Diné bizaad","nv"],["Nyanja","Chi-Chewa","ny"],["Occitan","occitan","oc"],["Oromo","Oromoo","om"],["Oriya","ଓଡ଼ିଆ","or"],["Ossetic","Ирон","os"],["Punjabi","ਪੰਜਾਬੀ","pa"],["Pangasinan","Pangasinan","pag"],["Pampanga","Kapampangan","pam"],["Papiamento","Papiamentu","pap"],["Picard","Picard","pcd"],["Pennsylvania German","Deitsch","pdc"],["Palatine German","Pälzisch","pfl"],["Pali","पालि","pi"],["Norfuk / Pitkern","Norfuk / Pitkern","pih"],["Polish","polski","pl"],["Piedmontese","Piemontèis","pms"],["Western Punjabi","پنجابی","pnb"],["Pontic","Ποντιακά","pnt"],["Pashto","پښتو","ps"],["Portuguese","português","pt"],["Quechua","Runa Simi","qu"],["Romansh","rumantsch","rm"],["Romani","Romani","rmy"],["Rundi","Kirundi","rn"],["Romanian","română","ro"],["Aromanian","armãneashti","roa-rup"],["tarandíne","tarandíne","roa-tara"],["Russian","русский","ru"],["Rusyn","русиньскый","rue"],["Kinyarwanda","Kinyarwanda","rw"],["Sanskrit","संस्कृतम्","sa"],["Sakha","саха тыла","sah"],["Sardinian","sardu","sc"],["Sicilian","sicilianu","scn"],["Scots","Scots","sco"],["Sindhi","سنڌي","sd"],["Northern Sami","sámegiella","se"],["Sango","Sängö","sg"],["Serbo-Croatian","srpskohrvatski / српскохрватски","sh"],["Sinhala","සිංහල","si"],["Simple English","Simple English","simple"],["Slovak","slovenčina","sk"],["Slovenian","slovenščina","sl"],["Samoan","Gagana Samoa","sm"],["Shona","chiShona","sn"],["Somali","Soomaaliga","so"],["Albanian","shqip","sq"],["Serbian","српски / srpski","sr"],["Sranan Tongo","Sranantongo","srn"],["Swati","SiSwati","ss"],["Southern Sotho","Sesotho","st"],["Saterland Frisian","Seeltersk","stq"],["Sundanese","Basa Sunda","su"],["Swedish","svenska","sv"],["Swahili","Kiswahili","sw"],["Silesian","ślůnski","szl"],["Tamil","தமிழ்","ta"],["Telugu","తెలుగు","te"],["Tetum","tetun","tet"],["Tajik","тоҷикӣ","tg"],["Thai","ไทย","th"],["Tigrinya","ትግርኛ","ti"],["Turkmen","Türkmençe","tk"],["Tagalog","Tagalog","tl"],["Tswana","Setswana","tn"],["Tongan","lea faka-Tonga","to"],["Tok Pisin","Tok Pisin","tpi"],["Turkish","Türkçe","tr"],["Tsonga","Xitsonga","ts"],["Tatar","татарча/tatarça","tt"],["Tumbuka","chiTumbuka","tum"],["Twi","Twi","tw"],["Tahitian","reo tahiti","ty"],["Tuvinian","тыва дыл","tyv"],["Udmurt","удмурт","udm"],["Uyghur","ئۇيغۇرچە / Uyghurche","ug"],["Ukrainian","українська","uk"],["Urdu","اردو","ur"],["Uzbek","oʻzbekcha/ўзбекча","uz"],["Venda","Tshivenda","ve"],["Venetian","vèneto","vec"],["Veps","vepsän kel’","vep"],["Vietnamese","Tiếng Việt","vi"],["West Flemish","West-Vlams","vls"],["Volapük","Volapük","vo"],["Walloon","walon","wa"],["Waray","Winaray","war"],["Wolof","Wolof","wo"],["Wu Chinese","吴语","wuu"],["Kalmyk","хальмг","xal"],["Xhosa","isiXhosa","xh"],["Mingrelian","მარგალური","xmf"],["Yiddish","ייִדיש","yi"],["Yoruba","Yorùbá","yo"],["Zhuang","Vahcuengh","za"],["Zeelandic","Zeêuws","zea"],["Chinese","中文","zh"],["Classical Chinese","文言","zh-classical"],["Chinese (Min Nan)","Bân-lâm-gú","zh-min-nan"],["Cantonese","粵語","zh-yue"],["Zulu","isiZulu","zu"]],"imperial":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"id":0},"geometry":{"type":"MultiPolygon","coordinates":[[[[-1.426496,50.639342],[-1.445953,50.648139],[-1.452789,50.654283],[-1.485951,50.669338],[-1.497426,50.672309],[-1.535146,50.669379],[-1.551503,50.665107],[-1.569488,50.658026],[-1.545318,50.686103],[-1.50593,50.707709],[-1.418691,50.733791],[-1.420888,50.730455],[-1.423451,50.7237],[-1.425364,50.72012],[-1.400868,50.721991],[-1.377553,50.734198],[-1.343495,50.761054],[-1.318512,50.772162],[-1.295766,50.773179],[-1.144276,50.733791],[-1.119537,50.734198],[-1.10912,50.732856],[-1.097035,50.726955],[-1.096425,50.724433],[-1.097646,50.71601],[-1.097035,50.713324],[-1.094228,50.712633],[-1.085561,50.714016],[-1.082753,50.713324],[-1.062327,50.692816],[-1.062327,50.685289],[-1.066965,50.685248],[-1.069651,50.683498],[-1.071889,50.680976],[-1.075307,50.678534],[-1.112701,50.671454],[-1.128651,50.666449],[-1.156361,50.650784],[-1.162221,50.645982],[-1.164703,50.640937],[-1.164666,50.639543],[-1.426496,50.639342]]],[[[-7.240314,55.050389],[-7.013736,55.1615],[-6.958913,55.20349],[-6.571562,55.268366],[-6.509633,55.31398],[-6.226158,55.344406],[-6.07105,55.25001],[-5.712696,55.017635],[-5.242021,54.415204],[-5.695554,54.14284],[-5.72473,54.07455],[-6.041633,54.006238],[-6.153953,54.054931],[-6.220539,54.098803],[-6.242502,54.099758],[-6.263661,54.104682],[-6.269887,54.097927],[-6.28465,54.105226],[-6.299585,54.104037],[-6.313796,54.099696],[-6.327128,54.097888],[-6.338962,54.102952],[-6.346662,54.109877],[-6.354827,54.110652],[-6.368108,54.097319],[-6.369348,54.091118],[-6.367643,54.083418],[-6.366919,54.075098],[-6.371157,54.066778],[-6.377513,54.063264],[-6.401026,54.060887],[-6.426761,54.05541],[-6.433892,54.055306],[-6.4403,54.057993],[-6.446243,54.062438],[-6.450222,54.066675],[-6.450894,54.068432],[-6.47854,54.067709],[-6.564013,54.04895],[-6.571868,54.049519],[-6.587164,54.053343],[-6.595071,54.052412],[-6.60029,54.04895],[-6.605217,54.044475],[-6.610987,54.039235],[-6.616465,54.037271],[-6.630624,54.041819],[-6.657289,54.061146],[-6.672534,54.068432],[-6.657082,54.091945],[-6.655791,54.103314],[-6.666436,54.114786],[-6.643957,54.131839],[-6.634552,54.150133],[-6.640339,54.168013],[-6.648448,54.173665],[-6.663025,54.183826],[-6.683954,54.194368],[-6.694651,54.197985],[-6.706537,54.198915],[-6.717234,54.195143],[-6.724779,54.188631],[-6.73284,54.183567],[-6.744777,54.184187],[-6.766481,54.192352],[-6.787824,54.202998],[-6.807358,54.21633],[-6.823946,54.23235],[-6.829733,54.242375],[-6.833196,54.25209],[-6.837743,54.260513],[-6.846683,54.266456],[-6.882185,54.277257],[-6.864667,54.282734],[-6.856657,54.292811],[-6.858414,54.307332],[-6.870015,54.326001],[-6.879705,54.341594],[-6.885957,54.345624],[-6.897895,54.346193],[-6.905956,54.349035],[-6.915051,54.365933],[-6.922028,54.372703],[-6.984091,54.403089],[-7.017836,54.413166],[-7.049255,54.411512],[-7.078504,54.394717],[-7.127028,54.349759],[-7.159894,54.335186],[-7.168059,54.335031],[-7.185629,54.336943],[-7.18947,54.335692],[-7.19245,54.334721],[-7.193949,54.329967],[-7.191468,54.323869],[-7.187644,54.318804],[-7.185009,54.317254],[-7.184647,54.316634],[-7.192399,54.307384],[-7.193691,54.307539],[-7.199168,54.303457],[-7.206661,54.304903],[-7.211467,54.30418],[-7.209038,54.293431],[-7.1755,54.283664],[-7.181495,54.269763],[-7.14589,54.25209],[-7.159739,54.24067],[-7.153331,54.224237],[-7.174725,54.216072],[-7.229502,54.207545],[-7.240871,54.202326],[-7.249088,54.197416],[-7.255496,54.190854],[-7.261128,54.18088],[-7.256322,54.176901],[-7.247021,54.17225],[-7.24578,54.166979],[-7.265366,54.16114],[-7.26087,54.151166],[-7.263505,54.140986],[-7.27074,54.132253],[-7.280042,54.126155],[-7.293788,54.122021],[-7.297353,54.125896],[-7.29632,54.134991],[-7.296423,54.146515],[-7.295028,54.155404],[-7.292134,54.162638],[-7.295545,54.165119],[-7.325982,54.154577],[-7.333165,54.149409],[-7.333165,54.142743],[-7.310324,54.114683],[-7.316489,54.11428],[-7.326964,54.113597],[-7.375488,54.123312],[-7.390216,54.121194],[-7.39466,54.121917],[-7.396624,54.126258],[-7.403962,54.135043],[-7.41223,54.136438],[-7.422255,54.135456],[-7.425769,54.136955],[-7.414659,54.145688],[-7.439619,54.146929],[-7.480753,54.127653],[-7.502302,54.125121],[-7.609014,54.139901],[-7.620796,54.144965],[-7.624052,54.153336],[-7.625706,54.162173],[-7.632682,54.168529],[-7.70477,54.200362],[-7.722599,54.202326],[-7.782078,54.2],[-7.836959,54.204341],[-7.856441,54.211421],[-7.86967,54.226872],[-7.873649,54.271055],[-7.880264,54.287023],[-7.894966,54.293586],[-7.93411,54.297049],[-7.942075,54.298873],[-7.950802,54.300873],[-7.96801,54.31219],[-7.981033,54.326556],[-8.002194,54.357923],[-8.03134,54.358027],[-8.05648,54.365882],[-8.079941,54.380196],[-8.122419,54.415233],[-8.146346,54.430736],[-8.156035,54.439055],[-8.158128,54.447117],[-8.161177,54.454817],[-8.173837,54.461741],[-8.168467,54.463477],[-8.15017,54.46939],[-8.097046,54.478588],[-8.072448,54.487063],[-8.060976,54.493316],[-8.05586,54.497553],[-8.043561,54.512229],[-8.023278,54.529696],[-8.002194,54.543442],[-7.926411,54.533055],[-7.887137,54.532125],[-7.848844,54.54091],[-7.749264,54.596152],[-7.707871,54.604162],[-7.707944,54.604708],[-7.707951,54.604763],[-7.710558,54.624264],[-7.721204,54.625866],[-7.736758,54.619251],[-7.753553,54.614497],[-7.769159,54.618011],[-7.801199,54.634806],[-7.814996,54.639457],[-7.822541,54.638113],[-7.838044,54.63124],[-7.846416,54.631447],[-7.85427,54.636408],[-7.864347,54.649069],[-7.872771,54.652221],[-7.890082,54.655063],[-7.906619,54.661316],[-7.914835,54.671651],[-7.907135,54.686689],[-7.913233,54.688653],[-7.929666,54.696714],[-7.880109,54.711029],[-7.845899,54.731027],[-7.832153,54.730614],[-7.803576,54.716145],[-7.770503,54.706016],[-7.736603,54.707463],[-7.70229,54.718883],[-7.667512,54.738779],[-7.649683,54.744877],[-7.61537,54.739347],[-7.585398,54.744722],[-7.566639,54.738675],[-7.556149,54.738365],[-7.543075,54.741673],[-7.543023,54.743791],[-7.548398,54.747202],[-7.551705,54.754695],[-7.549741,54.779603],[-7.543385,54.793091],[-7.470831,54.845284],[-7.45507,54.863009],[-7.444735,54.884455],[-7.444735,54.894893],[-7.448972,54.920318],[-7.445251,54.932152],[-7.436983,54.938301],[-7.417139,54.943056],[-7.415755,54.944372],[-7.408665,54.951117],[-7.407424,54.959437],[-7.413109,54.984965],[-7.409078,54.992045],[-7.403755,54.99313],[-7.40112,54.994836],[-7.405254,55.003569],[-7.376987,55.02889],[-7.366962,55.035557],[-7.355024,55.040931],[-7.291152,55.046615],[-7.282987,55.051835],[-7.275288,55.058863],[-7.266503,55.065167],[-7.247097,55.069328],[-7.2471,55.069322],[-7.256744,55.050686],[-7.240956,55.050279],[-7.240314,55.050389]]],[[[-13.688588,57.596259],[-13.690419,57.596259],[-13.691314,57.596503],[-13.691314,57.597154],[-13.690419,57.597805],[-13.688588,57.597805],[-13.687652,57.597154],[-13.687652,57.596869],[-13.688588,57.596259]]],[[[-4.839121,54.469789],[-4.979941,54.457977],[-5.343644,54.878637],[-5.308469,55.176452],[-6.272566,55.418443],[-8.690528,57.833706],[-6.344705,59.061083],[-4.204785,58.63305],[-2.31566,60.699068],[-1.695335,60.76432],[-1.58092,60.866001],[-0.17022,60.897204],[-0.800508,59.770037],[-1.292368,57.732574],[-1.850077,55.766368],[-1.73054,55.782219],[1.892395,52.815229],[1.742775,51.364209],[1.080173,50.847526],[0.000774,50.664982],[-0.162997,50.752401],[-0.725152,50.731879],[-0.768853,50.741516],[-0.770985,50.736884],[-0.789947,50.730048],[-0.812815,50.734768],[-0.877742,50.761156],[-0.942879,50.758338],[-0.992581,50.737379],[-1.18513,50.766989],[-1.282741,50.792353],[-1.375004,50.772063],[-1.523427,50.719605],[-1.630649,50.695128],[-1.663617,50.670508],[-1.498021,50.40831],[-4.097427,49.735486],[-6.825199,49.700905],[-5.541541,51.446591],[-6.03361,51.732369],[-4.791746,52.635365],[-4.969244,52.637413],[-5.049473,53.131209],[-4.787393,53.409491],[-4.734148,53.424866],[-4.917096,53.508212],[-4.839121,54.469789]]]]}},{"type":"Feature","properties":{"id":0},"geometry":{"type":"MultiPolygon","coordinates":[[[[-157.018938,19.300864],[-179.437336,27.295312],[-179.480084,28.991459],[-168.707465,26.30325],[-163.107414,24.60499],[-153.841679,20.079306],[-154.233846,19.433391],[-153.61725,18.900587],[-154.429471,18.171036],[-156.780638,18.718492],[-157.018938,19.300864]]],[[[-78.91269,43.037032],[-78.964351,42.976393],[-78.981718,42.979043],[-78.998055,42.991111],[-79.01189,43.004358],[-79.022046,43.010539],[-79.023076,43.017015],[-79.00983,43.050867],[-79.011449,43.065291],[-78.993051,43.066174],[-78.975536,43.069707],[-78.958905,43.070884],[-78.943304,43.065291],[-78.917399,43.058521],[-78.908569,43.049396],[-78.91269,43.037032]]],[[[-123.03529,48.992515],[-123.035308,48.992499],[-123.045277,48.984361],[-123.08849,48.972235],[-123.089345,48.987982],[-123.090484,48.992499],[-123.090488,48.992515],[-123.035306,48.992515],[-123.03529,48.992515]]],[[[-103.837038,29.279906],[-103.864121,29.281366],[-103.928122,29.293019],[-104.01915,29.32033],[-104.057313,29.339037],[-104.105424,29.385675],[-104.139789,29.400584],[-104.161648,29.416759],[-104.194514,29.448927],[-104.212291,29.484661],[-104.218698,29.489829],[-104.227148,29.493033],[-104.251022,29.508588],[-104.267171,29.526571],[-104.292751,29.532824],[-104.320604,29.532255],[-104.338484,29.524013],[-104.349026,29.537578],[-104.430443,29.582795],[-104.437832,29.58543],[-104.444008,29.589203],[-104.448555,29.597678],[-104.452069,29.607109],[-104.455222,29.613387],[-104.469381,29.625402],[-104.516639,29.654315],[-104.530824,29.667906],[-104.535036,29.677802],[-104.535191,29.687853],[-104.537103,29.702116],[-104.543666,29.71643],[-104.561391,29.745421],[-104.570279,29.787511],[-104.583586,29.802575],[-104.601207,29.81477],[-104.619682,29.833064],[-104.623764,29.841487],[-104.637588,29.887996],[-104.656346,29.908201],[-104.660635,29.918433],[-104.663478,29.923084],[-104.676526,29.93683],[-104.680479,29.942308],[-104.682469,29.952126],[-104.680117,29.967784],[-104.680479,29.976466],[-104.699108,30.03145],[-104.701589,30.055324],[-104.698592,30.075271],[-104.684639,30.111135],[-104.680479,30.134131],[-104.67867,30.170356],[-104.681564,30.192939],[-104.695853,30.208441],[-104.715231,30.243995],[-104.724585,30.252211],[-104.742155,30.25986],[-104.74939,30.264459],[-104.761689,30.284199],[-104.774143,30.311588],[-104.788767,30.335927],[-104.807732,30.346418],[-104.8129,30.350707],[-104.814967,30.360577],[-104.816001,30.371997],[-104.818274,30.380524],[-104.824269,30.38719],[-104.83755,30.394063],[-104.844939,30.40104],[-104.853259,30.41215],[-104.855016,30.417473],[-104.853621,30.423984],[-104.852432,30.438867],[-104.854655,30.448737],[-104.864473,30.462018],[-104.866695,30.473025],[-104.865248,30.479898],[-104.859615,30.491112],[-104.859254,30.497261],[-104.863026,30.502377],[-104.879718,30.510852],[-104.882146,30.520929],[-104.884007,30.541858],[-104.886591,30.551883],[-104.898166,30.569401],[-104.928242,30.599529],[-104.93434,30.610536],[-104.941057,30.61405],[-104.972735,30.618029],[-104.98276,30.620716],[-104.989117,30.629553],[-104.991649,30.640301],[-104.992941,30.651464],[-104.995783,30.661747],[-105.008495,30.676992],[-105.027977,30.690117],[-105.049475,30.699264],[-105.06813,30.702675],[-105.087043,30.709806],[-105.133604,30.757917],[-105.140425,30.750476],[-105.153241,30.763188],[-105.157788,30.76572],[-105.160889,30.764118],[-105.162698,30.774919],[-105.167297,30.781171],[-105.17479,30.783962],[-105.185125,30.784634],[-105.195306,30.787941],[-105.204917,30.80241],[-105.2121,30.805718],[-105.21825,30.806803],[-105.229257,30.810214],[-105.232874,30.809128],[-105.239851,30.801532],[-105.243985,30.799103],[-105.249049,30.798845],[-105.259488,30.802979],[-105.265844,30.808405],[-105.270753,30.814348],[-105.277006,30.819412],[-105.334315,30.843803],[-105.363771,30.850366],[-105.376173,30.859565],[-105.41555,30.902456],[-105.496682,30.95651],[-105.530789,30.991701],[-105.555955,31.002605],[-105.565722,31.016661],[-105.578641,31.052163],[-105.59094,31.071438],[-105.605875,31.081928],[-105.623496,31.090351],[-105.643805,31.103684],[-105.668042,31.127869],[-105.675225,31.131951],[-105.692278,31.137635],[-105.76819,31.18001],[-105.777854,31.192722],[-105.78483,31.211016],[-105.861983,31.288376],[-105.880147,31.300881],[-105.896994,31.305997],[-105.897149,31.309511],[-105.908802,31.317004],[-105.928052,31.326461],[-105.934563,31.335504],[-105.941772,31.352351],[-105.948515,31.361239],[-105.961202,31.371006],[-106.004739,31.396948],[-106.021147,31.402167],[-106.046261,31.404648],[-106.065304,31.410952],[-106.099385,31.428884],[-106.141113,31.439167],[-106.164316,31.447797],[-106.174471,31.460251],[-106.209249,31.477305],[-106.215424,31.483919],[-106.21744,31.488725],[-106.218731,31.494616],[-106.222891,31.50459],[-106.232658,31.519938],[-106.274749,31.562622],[-106.286298,31.580141],[-106.312292,31.648612],[-106.331309,31.68215],[-106.35849,31.717548],[-106.39177,31.745919],[-106.428951,31.758476],[-106.473135,31.755065],[-106.492797,31.759044],[-106.501425,31.766344],[-106.506052,31.770258],[-106.517189,31.773824],[-106.558969,31.773876],[-106.584859,31.773927],[-106.610697,31.773979],[-106.636587,31.774082],[-106.662477,31.774134],[-106.688315,31.774237],[-106.714205,31.774237],[-106.740095,31.774289],[-106.765933,31.774392],[-106.791823,31.774444],[-106.817713,31.774496],[-106.843603,31.774547],[-106.869441,31.774599],[-106.895331,31.774702],[-106.921221,31.774702],[-106.947111,31.774754],[-106.973001,31.774857],[-106.998891,31.774909],[-107.02478,31.774961],[-107.05067,31.775013],[-107.076509,31.775064],[-107.102398,31.775168],[-107.128288,31.775168],[-107.154127,31.775219],[-107.180016,31.775374],[-107.205906,31.775374],[-107.231796,31.775426],[-107.257634,31.775478],[-107.283524,31.775529],[-107.309414,31.775633],[-107.335252,31.775684],[-107.361142,31.775788],[-107.387032,31.775788],[-107.412896,31.775839],[-107.438786,31.775943],[-107.464676,31.775994],[-107.490566,31.776098],[-107.516404,31.776149],[-107.542294,31.776201],[-107.568184,31.776253],[-107.594074,31.776304],[-107.619964,31.776408],[-107.645854,31.776459],[-107.671744,31.776459],[-107.697633,31.776563],[-107.723472,31.776614],[-107.749362,31.776666],[-107.775251,31.776718],[-107.801141,31.77677],[-107.82698,31.776873],[-107.852869,31.776925],[-107.878759,31.776925],[-107.904598,31.777028],[-107.930487,31.77708],[-107.956377,31.777131],[-107.982216,31.777183],[-108.008105,31.777235],[-108.033995,31.777338],[-108.059885,31.77739],[-108.085723,31.77739],[-108.111613,31.777545],[-108.137503,31.777545],[-108.163341,31.777648],[-108.189283,31.7777],[-108.215121,31.777751],[-108.215121,31.770723],[-108.215121,31.763695],[-108.215121,31.756667],[-108.215121,31.749639],[-108.215121,31.74256],[-108.215121,31.735583],[-108.215121,31.728555],[-108.215121,31.721476],[-108.215121,31.714396],[-108.215121,31.70742],[-108.215121,31.700392],[-108.215121,31.693312],[-108.215121,31.686284],[-108.215121,31.679256],[-108.215121,31.672176],[-108.21507,31.665148],[-108.215018,31.658172],[-108.215018,31.651092],[-108.215018,31.644064],[-108.215018,31.637036],[-108.215018,31.630008],[-108.215018,31.62298],[-108.215018,31.615952],[-108.215018,31.608873],[-108.215018,31.601845],[-108.215018,31.594817],[-108.215018,31.587789],[-108.215018,31.580761],[-108.215018,31.573733],[-108.215018,31.566653],[-108.215018,31.559625],[-108.214966,31.552597],[-108.214966,31.545569],[-108.214966,31.538489],[-108.214966,31.531461],[-108.214966,31.524485],[-108.214966,31.517405],[-108.214966,31.510378],[-108.214966,31.503401],[-108.214966,31.496322],[-108.214966,31.489242],[-108.214966,31.482214],[-108.214966,31.475238],[-108.214966,31.468158],[-108.214966,31.46113],[-108.214966,31.454102],[-108.214966,31.447074],[-108.214915,31.440046],[-108.214863,31.432966],[-108.214863,31.425938],[-108.214863,31.41891],[-108.214863,31.411882],[-108.214863,31.404803],[-108.214863,31.397826],[-108.214863,31.390798],[-108.214863,31.383719],[-108.214863,31.376639],[-108.214863,31.369663],[-108.214863,31.362635],[-108.214863,31.355555],[-108.214863,31.348527],[-108.214863,31.341551],[-108.214863,31.334471],[-108.214811,31.327443],[-108.257573,31.327391],[-108.300336,31.327391],[-108.34302,31.327391],[-108.385731,31.327391],[-108.428442,31.327391],[-108.471152,31.327391],[-108.513837,31.327391],[-108.556547,31.327391],[-108.59931,31.327391],[-108.64202,31.327391],[-108.684757,31.327391],[-108.727467,31.327391],[-108.770178,31.327391],[-108.812914,31.327391],[-108.855625,31.327391],[-108.898335,31.327391],[-108.941046,31.327391],[-108.968282,31.327391],[-108.983731,31.327391],[-109.026493,31.327391],[-109.04743,31.327391],[-109.069203,31.327391],[-109.111914,31.327391],[-109.154599,31.327391],[-109.197361,31.327391],[-109.240072,31.32734],[-109.282782,31.32734],[-109.325519,31.32734],[-109.368229,31.32734],[-109.410914,31.32734],[-109.45365,31.32734],[-109.496387,31.32734],[-109.539071,31.32734],[-109.581808,31.32734],[-109.624493,31.32734],[-109.667177,31.32734],[-109.709965,31.32734],[-109.75265,31.32734],[-109.795335,31.32734],[-109.838123,31.32734],[-109.880808,31.32734],[-109.923596,31.327288],[-109.96628,31.327236],[-110.008965,31.327236],[-110.051702,31.327236],[-110.094386,31.327236],[-110.137071,31.327236],[-110.179807,31.327236],[-110.222544,31.327236],[-110.265229,31.327236],[-110.308017,31.327236],[-110.350753,31.327236],[-110.39349,31.327236],[-110.436174,31.327236],[-110.478859,31.327236],[-110.521595,31.327236],[-110.56428,31.327236],[-110.606965,31.327236],[-110.649727,31.327236],[-110.692438,31.327236],[-110.7352,31.327236],[-110.777885,31.327236],[-110.820595,31.327236],[-110.863358,31.327236],[-110.906068,31.327236],[-110.948753,31.327185],[-111.006269,31.327185],[-111.067118,31.333644],[-111.094455,31.342532],[-111.145924,31.359069],[-111.197446,31.375554],[-111.248864,31.392142],[-111.300333,31.40873],[-111.351803,31.425318],[-111.403299,31.441855],[-111.454768,31.458339],[-111.506238,31.474979],[-111.915464,31.601431],[-112.324715,31.727987],[-112.733967,31.854543],[-113.143218,31.981046],[-113.552444,32.107602],[-113.961696,32.234132],[-114.370921,32.360687],[-114.780147,32.487243],[-114.816785,32.498534],[-114.819373,32.499363],[-114.822108,32.50024],[-114.809447,32.511324],[-114.795546,32.552226],[-114.794203,32.574111],[-114.802678,32.594497],[-114.786813,32.621033],[-114.781542,32.628061],[-114.758804,32.64483],[-114.751156,32.65222],[-114.739477,32.669066],[-114.731209,32.686636],[-114.723871,32.711519],[-114.724284,32.712835],[-114.724285,32.712836],[-114.764541,32.709839],[-114.838076,32.704206],[-114.911612,32.698703],[-114.985199,32.693122],[-115.058734,32.687567],[-115.13227,32.681986],[-115.205806,32.676456],[-115.27929,32.670823],[-115.352851,32.665346],[-115.426386,32.659765],[-115.499922,32.654209],[-115.573535,32.648654],[-115.647019,32.643073],[-115.720529,32.637518],[-115.794064,32.631963],[-115.8676,32.626408],[-115.941213,32.620827],[-116.014748,32.615271],[-116.088232,32.609664],[-116.161742,32.604161],[-116.235329,32.598554],[-116.308891,32.593025],[-116.382426,32.587469],[-116.455962,32.581888],[-116.529472,32.576333],[-116.603007,32.570804],[-116.676543,32.565223],[-116.750104,32.559667],[-116.82364,32.554086],[-116.897201,32.548531],[-116.970737,32.542976],[-117.044221,32.537421],[-117.125121,32.531669],[-117.125969,32.538258],[-117.239623,32.531308],[-120.274098,32.884264],[-121.652736,34.467248],[-124.367265,37.662798],[-126.739806,41.37928],[-126.996297,45.773888],[-124.770704,48.44258],[-123.734053,48.241906],[-123.1663,48.27837],[-123.193018,48.501035],[-123.176987,48.65482],[-122.912481,48.753561],[-122.899122,48.897797],[-122.837671,48.97502],[-122.743986,48.980582],[-122.753,48.992499],[-122.753012,48.992515],[-122.653258,48.992515],[-122.433375,48.992515],[-122.213517,48.992515],[-121.993763,48.992515],[-121.773958,48.992515],[-121.554152,48.992515],[-121.33432,48.992515],[-121.114515,48.992515],[-95.396937,48.99267],[-95.177106,48.99267],[-95.168527,48.995047],[-95.161887,49.001145],[-95.159329,49.01179],[-95.159665,49.10951],[-95.160027,49.223353],[-95.160337,49.313012],[-95.160569,49.369494],[-95.102821,49.35394],[-94.982518,49.356162],[-94.926087,49.345568],[-94.856195,49.318283],[-94.839142,49.308878],[-94.827256,49.292858],[-94.819892,49.252034],[-94.810358,49.229606],[-94.806121,49.210899],[-94.811185,49.166561],[-94.803743,49.146407],[-94.792039,49.12646],[-94.753772,49.026156],[-94.711217,48.914586],[-94.711734,48.862755],[-94.712147,48.842446],[-94.713284,48.823843],[-94.710907,48.807513],[-94.701786,48.790098],[-94.688893,48.778832],[-94.592852,48.726433],[-94.519161,48.70447],[-94.4795,48.700698],[-94.311577,48.713927],[-94.292586,48.711912],[-94.284034,48.709069],[-94.274499,48.704108],[-94.265482,48.697752],[-94.258454,48.690828],[-94.255767,48.683541],[-94.252459,48.662405],[-94.251038,48.65729],[-94.23215,48.652019],[-94.03485,48.643311],[-93.874885,48.636206],[-93.835741,48.617137],[-93.809386,48.543576],[-93.778664,48.519468],[-93.756779,48.516549],[-93.616297,48.531302],[-93.599889,48.526341],[-93.566584,48.538279],[-93.491756,48.542309],[-93.459924,48.557399],[-93.45225,48.572721],[-93.453774,48.586958],[-93.451475,48.597422],[-93.417316,48.604114],[-93.385716,48.614863],[-93.25774,48.630314],[-93.131701,48.62463],[-92.97972,48.61768],[-92.955588,48.612228],[-92.884197,48.579878],[-92.72555,48.548692],[-92.648604,48.536263],[-92.630181,48.519468],[-92.627468,48.502777],[-92.646743,48.497428],[-92.691366,48.489858],[-92.710641,48.482882],[-92.718909,48.459782],[-92.704052,48.445158],[-92.677129,48.441747],[-92.657053,48.438233],[-92.570521,48.446656],[-92.526932,48.445623],[-92.490629,48.433117],[-92.474532,48.410483],[-92.467581,48.394282],[-92.467064,48.353225],[-92.462465,48.329299],[-92.451381,48.312685],[-92.41823,48.282041],[-92.38464,48.232406],[-92.371851,48.222587],[-92.353815,48.222897],[-92.327874,48.229435],[-92.303663,48.239279],[-92.291029,48.249562],[-92.292062,48.270336],[-92.301416,48.290645],[-92.303095,48.310928],[-92.281598,48.33178],[-92.259118,48.339635],[-92.154732,48.350125],[-92.070499,48.346714],[-92.043421,48.334596],[-92.030114,48.313176],[-92.021355,48.287441],[-92.007997,48.262482],[-91.992158,48.247909],[-91.975492,48.236566],[-91.957302,48.228323],[-91.852244,48.195974],[-91.764988,48.187344],[-91.744137,48.179593],[-91.727575,48.168327],[-91.695509,48.13758],[-91.716438,48.112051],[-91.692512,48.097866],[-91.618615,48.089572],[-91.597479,48.090399],[-91.589676,48.088332],[-91.581098,48.080942],[-91.579806,48.070969],[-91.585129,48.06084],[-91.586989,48.052572],[-91.574845,48.048205],[-91.487098,48.053476],[-91.464722,48.048955],[-91.446274,48.040738],[-91.427929,48.036449],[-91.3654,48.057843],[-91.276362,48.064768],[-91.23807,48.082648],[-91.203963,48.107659],[-91.071103,48.170859],[-91.02816,48.184838],[-91.008109,48.194372],[-90.923153,48.227109],[-90.873802,48.234344],[-90.840678,48.220107],[-90.837939,48.210547],[-90.848843,48.198713],[-90.849721,48.189566],[-90.843003,48.176983],[-90.83427,48.171789],[-90.823883,48.168327],[-90.812307,48.160989],[-90.803057,48.147166],[-90.796701,48.117064],[-90.786469,48.10045],[-90.750347,48.083991],[-90.701307,48.08456],[-90.611079,48.103499],[-90.586843,48.104817],[-90.573872,48.097892],[-90.562194,48.088849],[-90.542014,48.083733],[-90.531601,48.08456],[-90.501887,48.094275],[-90.490493,48.096239],[-90.483465,48.094482],[-90.477858,48.091536],[-90.470623,48.089882],[-90.178625,48.116444],[-90.120386,48.115359],[-90.073257,48.101199],[-90.061036,48.091019],[-90.008222,48.029731],[-89.995329,48.018595],[-89.980317,48.010094],[-89.92045,47.98746],[-89.902441,47.985909],[-89.803454,48.013763],[-89.780975,48.017199],[-89.763302,48.017303],[-89.745964,48.013763],[-89.724596,48.005908],[-89.712788,48.003376],[-89.678656,48.008699],[-89.65659,48.007975],[-89.593105,47.996503],[-89.581753,47.996333],[-89.586724,47.992938],[-89.310872,47.981097],[-89.072861,48.046842],[-88.49789,48.212841],[-88.286621,48.156675],[-85.939935,47.280501],[-84.784644,46.770068],[-84.516909,46.435083],[-84.489712,46.446652],[-84.491052,46.457658],[-84.478301,46.466467],[-84.465408,46.478172],[-84.448096,46.489722],[-84.42324,46.511581],[-84.389702,46.520262],[-84.352469,46.522743],[-84.30534,46.501607],[-84.242011,46.526464],[-84.197285,46.546359],[-84.147676,46.541346],[-84.110443,46.526464],[-84.158812,46.433343],[-84.147676,46.399882],[-84.129046,46.375026],[-84.10543,46.347741],[-84.105944,46.346374],[-84.117195,46.347157],[-84.117489,46.338326],[-84.122361,46.331922],[-84.112061,46.287102],[-84.092672,46.227469],[-84.111983,46.20337],[-84.015118,46.149712],[-83.957038,46.045736],[-83.676821,46.15388],[-83.429449,46.086221],[-83.523049,45.892052],[-83.574563,45.890259],[-82.551615,44.857931],[-82.655591,43.968545],[-82.440632,43.096285],[-82.460131,43.084392],[-82.458894,43.083247],[-82.431813,43.039387],[-82.424748,43.02408],[-82.417242,43.01731],[-82.416369,43.01742],[-82.416412,43.017143],[-82.414603,42.983243],[-82.430442,42.951307],[-82.453179,42.918983],[-82.464781,42.883637],[-82.468036,42.863974],[-82.482325,42.835113],[-82.485271,42.818524],[-82.473618,42.798164],[-82.470982,42.790568],[-82.471344,42.779845],[-82.476951,42.761474],[-82.48341,42.719254],[-82.511264,42.646675],[-82.526224,42.619906],[-82.549246,42.590941],[-82.575833,42.571795],[-82.608467,42.561098],[-82.644331,42.557817],[-82.644698,42.557533],[-82.644932,42.561634],[-82.637132,42.568405],[-82.60902,42.579296],[-82.616673,42.582828],[-82.636985,42.599607],[-82.625357,42.616092],[-82.629331,42.626394],[-82.638751,42.633459],[-82.644344,42.640524],[-82.644166,42.641056],[-82.716083,42.617461],[-82.777592,42.408506],[-82.888693,42.406093],[-82.889991,42.403266],[-82.905739,42.387665],[-82.923842,42.374419],[-82.937972,42.366176],[-82.947686,42.363527],[-82.979624,42.359406],[-83.042618,42.340861],[-83.061899,42.32732],[-83.081622,42.30907],[-83.11342,42.279619],[-83.145306,42.066968],[-83.177398,41.960666],[-83.21512,41.794493],[-82.219051,41.516445],[-80.345329,42.13344],[-80.316455,42.123137],[-79.270266,42.591872],[-79.221058,42.582892],[-78.871842,42.860012],[-78.875011,42.867184],[-78.896205,42.897209],[-78.901651,42.908101],[-78.90901,42.952255],[-78.913426,42.957848],[-78.932118,42.9708],[-78.936386,42.979631],[-78.927997,43.002003],[-78.893114,43.029379],[-78.887963,43.051456],[-78.914897,43.076477],[-79.026167,43.086485],[-79.065231,43.10573],[-79.065273,43.105897],[-79.065738,43.120237],[-79.061423,43.130288],[-79.055583,43.138427],[-79.051604,43.146851],[-79.04933,43.159847],[-79.048607,43.170622],[-79.053775,43.260358],[-79.058425,43.277799],[-79.058631,43.2782],[-78.990696,43.286947],[-78.862059,43.324332],[-78.767813,43.336418],[-78.516117,43.50645],[-76.363317,43.943219],[-76.396746,44.106667],[-76.364697,44.111631],[-76.366146,44.117349],[-76.357462,44.131478],[-76.183493,44.223025],[-76.162644,44.229888],[-76.176117,44.30795],[-76.046414,44.354817],[-75.928746,44.391137],[-75.852508,44.381639],[-75.849095,44.386103],[-75.847623,44.392579],[-75.84674,44.398172],[-75.845415,44.40141],[-75.780803,44.432318],[-75.770205,44.446153],[-75.772266,44.463815],[-75.779184,44.48236],[-75.791496,44.496513],[-75.791183,44.496768],[-75.754622,44.527567],[-75.69969,44.581673],[-75.578199,44.661513],[-75.455958,44.741766],[-75.341831,44.816749],[-75.270233,44.863774],[-75.129647,44.925166],[-75.075594,44.935501],[-75.058721,44.941031],[-75.0149,44.96599],[-74.998647,44.972398],[-74.940201,44.987746],[-74.903744,45.005213],[-74.88651,45.009398],[-74.868474,45.010122],[-74.741557,44.998857],[-74.712961,44.999254],[-74.695875,44.99803],[-74.596114,44.998495],[-74.496352,44.999012],[-74.197146,45.000458],[-71.703551,45.012757],[-71.603816,45.013274],[-71.505848,45.013731],[-71.50408,45.013739],[-71.506613,45.037045],[-71.504752,45.052962],[-71.497259,45.066553],[-71.45659,45.110994],[-71.451215,45.121691],[-71.445996,45.140295],[-71.441604,45.150682],[-71.413026,45.186184],[-71.406567,45.204942],[-71.42269,45.217189],[-71.449045,45.226905],[-71.438813,45.233468],[-71.394888,45.241529],[-71.381245,45.250779],[-71.3521,45.278323],[-71.334323,45.28871],[-71.311534,45.294136],[-71.293396,45.292327],[-71.20937,45.254758],[-71.185133,45.248557],[-71.160329,45.245767],[-71.141725,45.252329],[-71.111029,45.287108],[-71.095242,45.300905],[-71.085553,45.304213],[-71.084952,45.304293],[-71.064211,45.307055],[-71.054418,45.310362],[-71.036667,45.323385],[-71.027598,45.33465],[-71.016539,45.343125],[-70.993155,45.347827],[-70.968118,45.34452],[-70.951608,45.332014],[-70.906908,45.246232],[-70.892412,45.234604],[-70.874351,45.245663],[-70.870605,45.255275],[-70.872491,45.274189],[-70.870243,45.283129],[-70.862621,45.290363],[-70.842389,45.301215],[-70.835258,45.309794],[-70.83208,45.328552],[-70.835465,45.373097],[-70.833837,45.393096],[-70.825982,45.410459],[-70.812986,45.42343],[-70.794873,45.430406],[-70.771877,45.430045],[-70.75255,45.422345],[-70.718004,45.397282],[-70.696739,45.388652],[-70.675785,45.388704],[-70.65359,45.395473],[-70.641316,45.408496],[-70.650257,45.427461],[-70.668162,45.439036],[-70.707385,45.4564],[-70.722836,45.470921],[-70.732009,45.491591],[-70.730329,45.507973],[-70.686792,45.572723],[-70.589614,45.651788],[-70.572406,45.662279],[-70.514735,45.681709],[-70.484763,45.699641],[-70.4728,45.703568],[-70.450424,45.703723],[-70.439132,45.705893],[-70.419315,45.716901],[-70.407351,45.731525],[-70.402442,45.749663],[-70.403941,45.771161],[-70.408282,45.781651],[-70.413682,45.787697],[-70.41717,45.793795],[-70.415232,45.804389],[-70.409935,45.810745],[-70.389807,45.825059],[-70.312654,45.867641],[-70.283173,45.890482],[-70.262528,45.923038],[-70.255939,45.948876],[-70.263148,45.956834],[-70.280434,45.959315],[-70.303947,45.968616],[-70.316298,45.982982],[-70.316892,45.999002],[-70.306143,46.035331],[-70.303637,46.038483],[-70.294309,46.044943],[-70.29201,46.048663],[-70.293017,46.054038],[-70.296092,46.057862],[-70.300795,46.061737],[-70.304774,46.065975],[-70.311362,46.071866],[-70.312629,46.079566],[-70.30033,46.089281],[-70.26444,46.106593],[-70.24948,46.120597],[-70.244002,46.141009],[-70.249247,46.162765],[-70.263329,46.183229],[-70.284801,46.191859],[-70.280899,46.211857],[-70.253407,46.251493],[-70.236173,46.288339],[-70.223693,46.300793],[-70.201886,46.305495],[-70.199509,46.315262],[-70.197028,46.336863],[-70.188398,46.358412],[-70.167418,46.368179],[-70.153052,46.372829],[-70.074323,46.419545],[-70.061817,46.445409],[-70.050086,46.511271],[-70.032723,46.609766],[-70.023628,46.661287],[-70.007763,46.704075],[-69.989961,46.721697],[-69.899708,46.811562],[-69.809403,46.901299],[-69.719099,46.991086],[-69.628794,47.080797],[-69.538464,47.17061],[-69.448159,47.260346],[-69.357906,47.350134],[-69.267628,47.439844],[-69.25091,47.452919],[-69.237268,47.45881],[-69.221972,47.459688],[-69.069655,47.431886],[-69.054023,47.418399],[-69.054333,47.389253],[-69.066193,47.32967],[-69.065134,47.296339],[-69.06356,47.290809],[-69.057486,47.269467],[-69.0402,47.249055],[-68.906229,47.190221],[-68.889718,47.190609],[-68.761819,47.23704],[-68.71779,47.245231],[-68.668801,47.243422],[-68.644203,47.245283],[-68.6256,47.255205],[-68.607926,47.269829],[-68.58524,47.28249],[-68.539662,47.299853],[-68.518009,47.304762],[-68.492016,47.307553],[-68.466746,47.305692],[-68.435327,47.291275],[-68.422563,47.293109],[-68.410212,47.297424],[-68.385614,47.301713],[-68.383392,47.307139],[-68.384839,47.315873],[-68.382049,47.32781],[-68.347839,47.358506],[-68.299728,47.367833],[-68.24645,47.360573],[-68.197047,47.341401],[-68.184335,47.333133],[-68.156068,47.306674],[-68.145061,47.301455],[-68.115398,47.292282],[-68.101446,47.286185],[-68.039382,47.245231],[-67.993184,47.223217],[-67.962436,47.197689],[-67.953703,47.18663],[-67.949982,47.172936],[-67.943419,47.164538],[-67.899132,47.138778],[-67.870607,47.107358],[-67.854742,47.09785],[-67.813556,47.081908],[-67.808699,47.075138],[-67.805185,47.035631],[-67.802549,46.901247],[-67.800017,46.766785],[-67.797433,46.632297],[-67.794849,46.497861],[-67.792317,46.363476],[-67.789733,46.229014],[-67.78715,46.094552],[-67.784566,45.960142],[-67.782757,45.95053],[-67.776556,45.942933],[-67.767461,45.935957],[-67.759658,45.928567],[-67.757849,45.919472],[-67.769425,45.903969],[-67.787356,45.890017],[-67.799242,45.875651],[-67.792627,45.858907],[-67.776091,45.840821],[-67.772835,45.828057],[-67.779863,45.815706],[-67.794126,45.799169],[-67.80627,45.781754],[-67.811127,45.76651],[-67.810816,45.762414],[-67.817811,45.754896],[-67.821785,45.740767],[-67.827673,45.739001],[-67.868884,45.744593],[-67.856815,45.723694],[-67.835768,45.703971],[-67.793821,45.676301],[-67.733034,45.651869],[-67.723173,45.645393],[-67.711546,45.642155],[-67.697564,45.64922],[-67.66695,45.620077],[-67.649435,45.611247],[-67.603073,45.605948],[-67.561862,45.596234],[-67.54052,45.593879],[-67.442056,45.603593],[-67.440939,45.604586],[-67.431306,45.597941],[-67.422107,45.568796],[-67.42619,45.533449],[-67.443036,45.522184],[-67.467531,45.508283],[-67.493214,45.493142],[-67.48231,45.455521],[-67.428825,45.38705],[-67.434561,45.350308],[-67.459056,45.318424],[-67.468668,45.301835],[-67.475024,45.282353],[-67.471303,45.266282],[-67.427585,45.236568],[-67.390533,45.193108],[-67.356272,45.165926],[-67.31922,45.153886],[-67.284648,45.169699],[-67.279584,45.179052],[-67.279222,45.187372],[-67.277207,45.195072],[-67.267336,45.202513],[-67.254986,45.205045],[-67.242428,45.202565],[-67.219071,45.192126],[-67.206166,45.189401],[-67.176015,45.178656],[-67.191274,45.180365],[-67.204376,45.178209],[-67.204724,45.177791],[-67.152423,45.148932],[-67.048033,45.043407],[-66.962727,45.047088],[-66.857192,44.968696],[-66.897268,44.817275],[-67.2159,44.593511],[-67.122366,44.423624],[-67.68447,44.192544],[-67.459678,40.781645],[-76.607854,32.495823],[-76.798479,32.713735],[-78.561892,29.037718],[-78.892446,29.039659],[-79.762295,26.719312],[-80.026352,24.932961],[-82.368794,23.994833],[-83.806281,29.068506],[-87.460772,29.089961],[-87.922646,28.666131],[-90.461001,28.246758],[-91.787336,29.11536],[-93.311871,29.12431],[-96.423449,26.057857],[-97.129057,25.991017],[-97.129509,25.966833],[-97.139358,25.965876],[-97.202171,25.960893],[-97.202176,25.960857],[-97.204941,25.960639],[-97.253051,25.963481],[-97.266358,25.960639],[-97.2692,25.944361],[-97.287649,25.928651],[-97.310981,25.922088],[-97.328447,25.933302],[-97.351107,25.918419],[-97.355112,25.912786],[-97.35227,25.894493],[-97.345165,25.871704],[-97.345733,25.852222],[-97.36599,25.843902],[-97.376015,25.846744],[-97.380124,25.853203],[-97.383121,25.860541],[-97.389891,25.865657],[-97.397823,25.865812],[-97.399476,25.861162],[-97.39989,25.855115],[-97.404179,25.851395],[-97.425418,25.854857],[-97.435727,25.869275],[-97.441309,25.884933],[-97.448259,25.892322],[-97.469421,25.892943],[-97.486319,25.895733],[-97.502209,25.901883],[-97.52027,25.912786],[-97.565177,25.954748],[-97.594322,25.966375],[-97.604787,25.979966],[-97.613055,25.995985],[-97.622641,26.00906],[-97.641451,26.022495],[-97.659874,26.03066],[-97.679614,26.034639],[-97.766948,26.039652],[-97.780306,26.043218],[-97.782321,26.058617],[-97.80201,26.063733],[-97.878181,26.063733],[-97.941666,26.056809],[-97.999233,26.064302],[-98.013057,26.063682],[-98.044166,26.048799],[-98.065457,26.042184],[-98.075146,26.046628],[-98.083311,26.070916],[-98.103103,26.074947],[-98.150232,26.063682],[-98.185062,26.065232],[-98.222656,26.075412],[-98.300429,26.111431],[-98.309809,26.121094],[-98.333037,26.15303],[-98.339264,26.159851],[-98.365774,26.160161],[-98.377272,26.163572],[-98.377272,26.173649],[-98.36934,26.19401],[-98.397193,26.201141],[-98.428845,26.217729],[-98.456544,26.225946],[-98.472383,26.207652],[-98.49295,26.230596],[-98.521527,26.240932],[-98.552791,26.248321],[-98.581627,26.262274],[-98.640564,26.24181],[-98.653663,26.244291],[-98.664696,26.250647],[-98.685289,26.268475],[-98.693325,26.270542],[-98.702239,26.271628],[-98.704255,26.27664],[-98.691465,26.290231],[-98.701413,26.299119],[-98.713169,26.303357],[-98.726217,26.30439],[-98.739911,26.303253],[-98.735932,26.320048],[-98.746397,26.332141],[-98.780839,26.351674],[-98.795851,26.368314],[-98.801329,26.372138],[-98.810295,26.372448],[-98.817323,26.368521],[-98.825023,26.366454],[-98.836081,26.372138],[-98.842334,26.365834],[-98.850835,26.364077],[-98.860524,26.366299],[-98.870214,26.372138],[-98.893029,26.367849],[-98.9299,26.39224],[-98.945377,26.378288],[-98.954136,26.393946],[-98.962844,26.399527],[-98.986951,26.400095],[-99.004056,26.393842],[-99.010515,26.392602],[-99.016432,26.394462],[-99.022995,26.403351],[-99.027878,26.406245],[-99.047645,26.406968],[-99.066351,26.404746],[-99.085498,26.40764],[-99.106427,26.423039],[-99.108907,26.434253],[-99.102525,26.446966],[-99.09374,26.459781],[-99.089373,26.47115],[-99.091492,26.484018],[-99.10299,26.512078],[-99.115108,26.525617],[-99.140946,26.531405],[-99.164873,26.540448],[-99.17128,26.563961],[-99.171548,26.56583],[-99.213953,26.568537],[-99.242801,26.579723],[-99.254575,26.6018],[-99.258844,26.614752],[-99.277683,26.638007],[-99.281951,26.649781],[-99.277389,26.657729],[-99.26635,26.653314],[-99.252662,26.644483],[-99.240299,26.639184],[-99.244861,26.652431],[-99.240299,26.697763],[-99.242507,26.713658],[-99.252368,26.743683],[-99.254575,26.75899],[-99.252368,26.799024],[-99.254575,26.810504],[-99.257666,26.813153],[-99.262229,26.814036],[-99.266497,26.817863],[-99.268263,26.827872],[-99.271649,26.832876],[-99.289458,26.84465],[-99.308444,26.830521],[-99.316539,26.822279],[-99.323457,26.810504],[-99.328166,26.797258],[-99.329197,26.789016],[-99.331699,26.78254],[-99.340383,26.77312],[-99.366728,26.761345],[-99.380269,26.777241],[-99.391896,26.796963],[-99.412207,26.796963],[-99.410883,26.808149],[-99.405437,26.818452],[-99.396606,26.824928],[-99.384979,26.824928],[-99.377178,26.816686],[-99.374823,26.804028],[-99.374234,26.791076],[-99.371291,26.783128],[-99.360694,26.780479],[-99.359369,26.790487],[-99.36452,26.810504],[-99.357897,26.822279],[-99.351274,26.83111],[-99.346123,26.840824],[-99.344062,26.855247],[-99.348772,26.899696],[-99.355101,26.920302],[-99.36452,26.934726],[-99.403377,26.952093],[-99.413974,26.964162],[-99.401758,26.985651],[-99.399991,26.999192],[-99.418831,27.007728],[-99.441938,27.013615],[-99.453271,27.019797],[-99.455332,27.025979],[-99.464751,27.039225],[-99.466959,27.047467],[-99.462544,27.057181],[-99.461635,27.056839],[-99.461728,27.056954],[-99.442039,27.089614],[-99.439404,27.098347],[-99.441419,27.107494],[-99.445734,27.114728],[-99.450178,27.120465],[-99.452452,27.125012],[-99.450333,27.145166],[-99.435786,27.188419],[-99.431988,27.207591],[-99.434029,27.22697],[-99.440902,27.244798],[-99.451832,27.26118],[-99.46612,27.276527],[-99.468963,27.278233],[-99.480409,27.283297],[-99.482941,27.286708],[-99.484879,27.294821],[-99.486584,27.297611],[-99.493199,27.30128],[-99.521362,27.311254],[-99.5148,27.321796],[-99.497591,27.338798],[-99.494026,27.348203],[-99.492889,27.358848],[-99.487721,27.37187],[-99.484621,27.391766],[-99.475706,27.414762],[-99.472916,27.426647],[-99.473639,27.463803],[-99.472916,27.468299],[-99.47643,27.48251],[-99.480409,27.490778],[-99.48829,27.494654],[-99.503689,27.495584],[-99.509503,27.500028],[-99.510071,27.510518],[-99.507074,27.533437],[-99.507203,27.57377],[-99.515006,27.588601],[-99.535031,27.604828],[-99.55503,27.613509],[-99.572264,27.61847],[-99.578232,27.622811],[-99.590247,27.642061],[-99.600169,27.646427],[-99.612442,27.643637],[-99.633526,27.633069],[-99.644869,27.632733],[-99.648642,27.636919],[-99.658693,27.654024],[-99.664739,27.659398],[-99.70037,27.659191],[-99.705692,27.66317],[-99.710674,27.670116],[-99.723056,27.687381],[-99.730652,27.691825],[-99.734037,27.702031],[-99.736311,27.713607],[-99.740445,27.722159],[-99.747344,27.726009],[-99.765198,27.731177],[-99.774577,27.735828],[-99.78685,27.748488],[-99.795428,27.761924],[-99.806963,27.771423],[-99.808167,27.772414],[-99.83292,27.776755],[-99.832971,27.782181],[-99.844779,27.793576],[-99.858241,27.803524],[-99.863357,27.804661],[-99.864727,27.814324],[-99.861858,27.83608],[-99.863357,27.845666],[-99.870928,27.854477],[-99.880204,27.859231],[-99.888007,27.864812],[-99.891288,27.876026],[-99.882684,27.89158],[-99.878808,27.901838],[-99.88134,27.906463],[-99.896766,27.912923],[-99.914336,27.928245],[-99.929916,27.946331],[-99.939683,27.961085],[-99.928289,27.975761],[-99.940717,27.983254],[-99.961852,27.987492],[-99.976606,27.992453],[-99.991127,28.007801],[-100.000584,28.02041],[-100.007457,28.033561],[-100.014123,28.050459],[-100.013503,28.056971],[-100.010506,28.063611],[-100.010196,28.068882],[-100.017585,28.070949],[-100.031538,28.081801],[-100.045077,28.095289],[-100.048023,28.102523],[-100.048901,28.115959],[-100.056498,28.137922],[-100.074895,28.154407],[-100.172873,28.198538],[-100.189203,28.201329],[-100.197626,28.207168],[-100.201192,28.220346],[-100.202949,28.234428],[-100.205946,28.242877],[-100.212819,28.245073],[-100.240724,28.249698],[-100.257932,28.260524],[-100.275089,28.277242],[-100.284339,28.296517],[-100.277931,28.314888],[-100.278551,28.331088],[-100.293899,28.353413],[-100.322631,28.386899],[-100.331675,28.422013],[-100.336326,28.458574],[-100.340201,28.464259],[-100.348315,28.470253],[-100.355549,28.478185],[-100.35679,28.489322],[-100.351622,28.496711],[-100.322631,28.510406],[-100.364024,28.524797],[-100.38423,28.537174],[-100.397769,28.557586],[-100.398751,28.568645],[-100.397097,28.592726],[-100.401438,28.60226],[-100.411463,28.609314],[-100.434821,28.619133],[-100.44619,28.626497],[-100.444898,28.643782],[-100.481381,28.686054],[-100.493939,28.708378],[-100.519054,28.804961],[-100.524996,28.814831],[-100.529285,28.819947],[-100.534453,28.830231],[-100.538639,28.835631],[-100.54515,28.83899],[-100.559671,28.839378],[-100.566234,28.842504],[-100.569696,28.84961],[-100.56334,28.86209],[-100.566234,28.869789],[-100.571763,28.8732],[-100.586543,28.879789],[-100.58954,28.883458],[-100.594966,28.899322],[-100.606955,28.910123],[-100.618841,28.917926],[-100.624318,28.924721],[-100.624783,28.93777],[-100.626696,28.948338],[-100.630778,28.956683],[-100.637909,28.962884],[-100.628918,28.98433],[-100.632793,29.005156],[-100.652224,29.044817],[-100.660854,29.102669],[-100.668967,29.116208],[-100.678165,29.119412],[-100.690826,29.121014],[-100.70204,29.12365],[-100.706846,29.130187],[-100.70974,29.135561],[-100.762501,29.173776],[-100.770098,29.187289],[-100.762088,29.208658],[-100.783172,29.243074],[-100.796143,29.257673],[-100.81609,29.270773],[-100.86389,29.290616],[-100.871797,29.296456],[-100.891227,29.318547],[-100.91474,29.337048],[-100.987397,29.366322],[-100.998301,29.372472],[-101.008068,29.380585],[-101.016232,29.390068],[-101.022175,29.40048],[-101.025948,29.414356],[-101.029617,29.442984],[-101.037782,29.460063],[-101.039026,29.460452],[-101.040188,29.457132],[-101.045487,29.451245],[-101.060205,29.449184],[-101.067711,29.45095],[-101.076101,29.453894],[-101.085962,29.454483],[-101.098031,29.449184],[-101.113043,29.466552],[-101.142774,29.475383],[-101.174124,29.475971],[-101.193699,29.469495],[-101.198703,29.473911],[-101.198851,29.476854],[-101.184132,29.497754],[-101.184868,29.512767],[-101.195171,29.521892],[-101.214157,29.518065],[-101.245213,29.493044],[-101.265818,29.487157],[-101.290545,29.49746],[-101.297315,29.503936],[-101.300995,29.512767],[-101.294372,29.520715],[-101.273177,29.524247],[-101.259195,29.533372],[-101.243888,29.554861],[-101.231966,29.580176],[-101.227845,29.599899],[-101.239178,29.616677],[-101.26052,29.613439],[-101.281272,29.597249],[-101.290545,29.575761],[-101.295255,29.570168],[-101.306146,29.574583],[-101.317626,29.584003],[-101.323955,29.592539],[-101.323661,29.603137],[-101.318804,29.616383],[-101.311445,29.628158],[-101.303497,29.634045],[-101.303669,29.631411],[-101.302727,29.633851],[-101.301073,29.649509],[-101.30978,29.654548],[-101.336239,29.654315],[-101.349029,29.660103],[-101.357684,29.667441],[-101.364351,29.676665],[-101.376624,29.700643],[-101.383368,29.718497],[-101.39962,29.740718],[-101.406545,29.752888],[-101.409309,29.765781],[-101.405098,29.778442],[-101.414012,29.774411],[-101.424218,29.771414],[-101.435096,29.770122],[-101.446103,29.771052],[-101.455689,29.77591],[-101.462433,29.788932],[-101.470908,29.791516],[-101.490286,29.785547],[-101.505763,29.773894],[-101.521809,29.765936],[-101.542893,29.771052],[-101.539689,29.779191],[-101.530516,29.796477],[-101.528604,29.801438],[-101.531912,29.811101],[-101.539172,29.817974],[-101.546458,29.820145],[-101.549766,29.815701],[-101.553977,29.796684],[-101.564907,29.786478],[-101.580281,29.781568],[-101.632216,29.775651],[-101.794531,29.795857],[-101.80298,29.801438],[-101.805978,29.811928],[-101.812695,29.812032],[-101.82409,29.805184],[-101.857602,29.805184],[-101.877524,29.810843],[-101.88742,29.81229],[-101.895455,29.808621],[-101.90238,29.803247],[-101.910881,29.799888],[-101.920157,29.798182],[-101.929613,29.797717],[-101.942662,29.803608],[-101.957054,29.814047],[-101.972246,29.818181],[-101.98793,29.805184],[-102.014595,29.810998],[-102.109344,29.80211],[-102.145647,29.815701],[-102.157248,29.824537],[-102.203679,29.846138],[-102.239775,29.849135],[-102.253444,29.855285],[-102.258276,29.873475],[-102.276181,29.869547],[-102.289023,29.878126],[-102.302175,29.889391],[-102.321011,29.893939],[-102.330235,29.888926],[-102.339769,29.870633],[-102.351061,29.866602],[-102.36323,29.864276],[-102.370723,29.857765],[-102.374547,29.848102],[-102.376589,29.821488],[-102.380051,29.811386],[-102.404132,29.780793],[-102.406096,29.777279],[-102.515288,29.784721],[-102.523066,29.782318],[-102.531127,29.769915],[-102.54154,29.762474],[-102.543349,29.760123],[-102.546578,29.757875],[-102.553141,29.756738],[-102.558309,29.759089],[-102.562882,29.769347],[-102.566758,29.771052],[-102.58531,29.764696],[-102.621225,29.747281],[-102.638743,29.743715],[-102.676054,29.74449],[-102.683469,29.743715],[-102.69104,29.736817],[-102.693624,29.729401],[-102.694709,29.720616],[-102.697758,29.709557],[-102.726748,29.664495],[-102.73127,29.650594],[-102.735507,29.649509],[-102.751656,29.622457],[-102.75176,29.620157],[-102.761346,29.603414],[-102.767598,29.59729],[-102.779665,29.592303],[-102.774084,29.579617],[-102.776461,29.575948],[-102.785892,29.571814],[-102.78075,29.558249],[-102.786512,29.550497],[-102.795478,29.54427],[-102.827311,29.470502],[-102.833951,29.461355],[-102.839067,29.45195],[-102.841134,29.438308],[-102.838705,29.426939],[-102.834984,29.415699],[-102.835191,29.403839],[-102.844545,29.390533],[-102.845578,29.384719],[-102.838033,29.370534],[-102.837672,29.366322],[-102.84656,29.361749],[-102.853872,29.361],[-102.859867,29.361155],[-102.864957,29.359527],[-102.876972,29.350871],[-102.883069,29.343766],[-102.885188,29.333379],[-102.885498,29.314801],[-102.899399,29.276095],[-102.899709,29.2639],[-102.892139,29.254391],[-102.867954,29.240387],[-102.858781,29.229147],[-102.869866,29.224781],[-102.896893,29.220285],[-102.942265,29.190209],[-102.947536,29.182018],[-102.969757,29.192845],[-102.988386,29.177135],[-103.015826,29.126776],[-103.024275,29.116157],[-103.032621,29.110214],[-103.072541,29.091404],[-103.080758,29.085203],[-103.085589,29.07572],[-103.091532,29.057866],[-103.095356,29.060294],[-103.104684,29.057866],[-103.109205,29.023372],[-103.122771,28.996474],[-103.147989,28.985105],[-103.187108,28.990221],[-103.241756,29.003502],[-103.301545,29.002365],[-103.316247,29.010065],[-103.311514,29.026043],[-103.309994,29.031175],[-103.3248,29.026808],[-103.330484,29.023733],[-103.342602,29.041226],[-103.351671,29.039417],[-103.360534,29.029831],[-103.372083,29.023733],[-103.38663,29.028798],[-103.414639,29.052414],[-103.423605,29.057866],[-103.435697,29.061121],[-103.478537,29.08205],[-103.529748,29.126776],[-103.535588,29.135122],[-103.538223,29.142408],[-103.541711,29.148816],[-103.550238,29.154656],[-103.558015,29.156206],[-103.58499,29.154656],[-103.673125,29.173569],[-103.702477,29.187858],[-103.749476,29.222972],[-103.759062,29.226848],[-103.770767,29.229845],[-103.777718,29.235297],[-103.769424,29.257543],[-103.774229,29.267517],[-103.78366,29.274803],[-103.794177,29.277594],[-103.837038,29.279906]]],[[[178.301106,52.056551],[179.595462,52.142083],[179.825447,51.992849],[179.661729,51.485763],[179.723231,51.459963],[179.408066,51.209841],[178.411463,51.523605],[177.698335,51.877899],[177.16784,51.581866],[176.487008,52.175325],[174.484678,52.08716],[172.866263,52.207379],[172.825506,52.716846],[172.747012,52.654022],[172.08261,52.952695],[172.942925,53.183013],[173.029416,52.993628],[173.127208,52.99494],[173.143321,52.990383],[173.175059,52.971747],[173.182932,52.968373],[176.45233,52.628178],[176.468135,52.488358],[177.900385,52.488358],[178.007601,52.179677],[178.301106,52.056551]]],[[[-168.899607,65.747626],[-168.909861,65.739569],[-168.926218,65.739895],[-168.942128,65.74372],[-168.951731,65.75316],[-168.942983,65.764716],[-168.920115,65.768866],[-168.907908,65.768297],[-168.902781,65.761542],[-168.899607,65.747626]]],[[[-131.160718,54.787192],[-132.853508,54.482536],[-134.77719,54.717786],[-142.6966,55.845503],[-142.861997,49.948308],[-155.675916,51.109976],[-164.492732,50.603976],[-164.691217,50.997975],[-171.246993,49.948308],[-171.215436,50.576636],[-173.341669,50.968826],[-173.362022,51.082198],[-177.799603,51.272899],[-179.155463,50.982285],[-179.476076,52.072632],[-177.11459,52.248701],[-177.146284,52.789384],[-174.777218,52.443779],[-174.773743,52.685853],[-173.653194,52.704099],[-173.790528,53.469081],[-171.063371,53.604473],[-170.777733,59.291898],[-174.324884,60.332184],[-171.736408,62.68026],[-172.315705,62.725352],[-171.995091,63.999658],[-168.501424,65.565173],[-168.714145,65.546708],[-168.853077,68.370871],[-161.115601,72.416214],[-146.132257,70.607941],[-140.692512,69.955349],[-141.145395,69.671641],[-141.015207,69.654202],[-141.006459,69.651272],[-141.005564,69.650946],[-141.005549,69.650941],[-141.005471,69.505164],[-141.001208,60.466879],[-141.001156,60.321074],[-140.994929,60.304382],[-140.979555,60.295804],[-140.909146,60.28366],[-140.768457,60.259269],[-140.660505,60.24051],[-140.533743,60.218548],[-140.518705,60.22387],[-140.506664,60.236324],[-140.475323,60.276477],[-140.462791,60.289138],[-140.447805,60.29446],[-140.424111,60.293168],[-140.32497,60.267537],[-140.169243,60.227229],[-140.01579,60.187387],[-139.967757,60.188369],[-139.916933,60.207851],[-139.826318,60.256478],[-139.728417,60.309033],[-139.679816,60.32681],[-139.628346,60.334096],[-139.517965,60.336732],[-139.413992,60.339212],[-139.262193,60.342778],[-139.101608,60.346602],[-139.079465,60.341021],[-139.06869,60.322056],[-139.073186,60.299835],[-139.113468,60.226816],[-139.149615,60.161187],[-139.183231,60.100157],[-139.182146,60.073389],[-139.112305,60.031376],[-139.060207,60.000059],[-139.051611,59.994892],[-139.003759,59.977219],[-138.842425,59.937686],[-138.742586,59.913192],[-138.704888,59.898464],[-138.697188,59.89371],[-138.692098,59.886888],[-138.654349,59.805498],[-138.63745,59.784052],[-138.59921,59.753822],[-138.488881,59.696357],[-138.363617,59.631142],[-138.219543,59.556004],[-138.067614,59.476991],[-137.91057,59.395187],[-137.758305,59.315915],[-137.611363,59.239331],[-137.594181,59.225275],[-137.582088,59.206568],[-137.5493,59.134531],[-137.521007,59.072364],[-137.484394,58.991904],[-137.507752,58.939969],[-137.50876,58.914906],[-137.486875,58.900075],[-137.453466,58.899145],[-137.423106,58.907723],[-137.338098,58.955472],[-137.2819,58.98715],[-137.172346,59.027148],[-137.062367,59.067572],[-137.047109,59.07331],[-136.942282,59.11107],[-136.840816,59.148174],[-136.785496,59.157217],[-136.671911,59.150809],[-136.613491,59.15422],[-136.569489,59.172152],[-136.484791,59.2538],[-136.483551,59.257469],[-136.466549,59.287803],[-136.467092,59.38449],[-136.467557,59.461643],[-136.415958,59.452238],[-136.36684,59.449551],[-136.319995,59.459059],[-136.275036,59.486448],[-136.244728,59.528202],[-136.258474,59.556107],[-136.29935,59.575745],[-136.350329,59.592384],[-136.2585,59.621582],[-136.145406,59.636826],[-136.02686,59.652846],[-135.923818,59.666747],[-135.830955,59.693257],[-135.641251,59.747362],[-135.482759,59.792475],[-135.465137,59.789685],[-135.404392,59.753305],[-135.345791,59.731032],[-135.259879,59.698218],[-135.221897,59.675273],[-135.192028,59.64711],[-135.157792,59.623287],[-135.106684,59.613158],[-135.087874,59.606544],[-135.032942,59.573109],[-135.018524,59.559363],[-135.016198,59.543447],[-135.01948,59.493166],[-135.023252,59.477146],[-135.037489,59.461591],[-135.078598,59.438337],[-135.095754,59.418855],[-134.993254,59.381906],[-135.00483,59.367127],[-135.014441,59.35152],[-135.016198,59.336173],[-134.979973,59.297415],[-134.95783,59.280982],[-134.932431,59.270647],[-134.839465,59.258141],[-134.74345,59.245119],[-134.70552,59.240106],[-134.692084,59.235249],[-134.68286,59.223001],[-134.671439,59.193752],[-134.66038,59.181298],[-134.610771,59.144556],[-134.582788,59.128847],[-134.556717,59.123059],[-134.509072,59.122801],[-134.477575,59.114946],[-134.451013,59.097893],[-134.398019,59.051952],[-134.387167,59.036863],[-134.385591,59.018828],[-134.399389,58.974954],[-134.343423,58.968857],[-134.329651,58.963017],[-134.320039,58.952682],[-134.32314,58.949168],[-134.330323,58.945344],[-134.333036,58.93413],[-134.327403,58.916457],[-134.316939,58.903796],[-134.22219,58.842714],[-134.108838,58.808246],[-133.983109,58.769902],[-133.87123,58.735899],[-133.831129,58.718019],[-133.796402,58.693421],[-133.700077,58.59937],[-133.626283,58.546402],[-133.547063,58.505577],[-133.463089,58.462221],[-133.392241,58.403878],[-133.43012,58.372097],[-133.41503,58.330549],[-133.374567,58.290965],[-133.257262,58.210298],[-133.165588,58.147305],[-133.142127,58.120588],[-133.094843,58.0331],[-133.075154,58.007882],[-132.99335,57.941917],[-132.917153,57.880499],[-132.83212,57.791564],[-132.70944,57.663303],[-132.629057,57.579277],[-132.552447,57.499075],[-132.455735,57.420992],[-132.362304,57.3457],[-132.304684,57.280355],[-132.230994,57.19682],[-132.276366,57.14889],[-132.34122,57.080393],[-132.16229,57.050317],[-132.031859,57.028406],[-132.107384,56.858753],[-131.871558,56.79346],[-131.865874,56.785708],[-131.872411,56.77297],[-131.882617,56.759146],[-131.887966,56.747958],[-131.886028,56.737055],[-131.880705,56.728838],[-131.864789,56.71349],[-131.838976,56.682278],[-131.830424,56.664759],[-131.826574,56.644606],[-131.832103,56.603368],[-131.825592,56.593343],[-131.799108,56.587658],[-131.692293,56.585074],[-131.585891,56.595048],[-131.560363,56.594066],[-131.536437,56.585229],[-131.491659,56.560166],[-131.345699,56.503271],[-131.215604,56.45255],[-131.100546,56.407669],[-131.016934,56.38705],[-130.839089,56.372452],[-130.760334,56.345192],[-130.645768,56.261942],[-130.602256,56.247059],[-130.495518,56.232434],[-130.47229,56.22489],[-130.458053,56.210653],[-130.427926,56.143964],[-130.418159,56.129702],[-130.403974,56.121898],[-130.290311,56.10097],[-130.243156,56.092391],[-130.211246,56.089962],[-130.116756,56.105646],[-130.094328,56.101486],[-130.071539,56.084123],[-130.039319,56.045521],[-130.026632,56.024101],[-130.01901,56.002216],[-130.014695,55.963252],[-130.016788,55.918913],[-130.019612,55.907978],[-130.019618,55.907952],[-130.022817,55.901353],[-130.049387,55.871405],[-130.104726,55.825263],[-130.136627,55.806464],[-130.148834,55.795356],[-130.163482,55.771145],[-130.167307,55.766262],[-130.170806,55.759833],[-130.173655,55.749498],[-130.170806,55.740953],[-130.163808,55.734565],[-130.160064,55.727118],[-130.167388,55.715399],[-130.155914,55.700141],[-130.142893,55.689521],[-130.131825,55.676581],[-130.126454,55.653998],[-130.12857,55.63642],[-130.135121,55.619127],[-130.153147,55.58511],[-130.148671,55.578192],[-130.146881,55.569322],[-130.146962,55.547187],[-130.112172,55.509345],[-130.101674,55.481147],[-130.095082,55.472113],[-130.065419,55.446112],[-130.057525,55.434882],[-130.052561,55.414008],[-130.054311,55.366645],[-130.05012,55.345445],[-130.039296,55.330756],[-129.989247,55.284003],[-130.031239,55.26435],[-130.050038,55.252875],[-130.067494,55.239],[-130.078236,55.233791],[-130.100494,55.230292],[-130.104726,55.225653],[-130.105702,55.211127],[-130.10912,55.200751],[-130.115793,55.191596],[-130.126454,55.180976],[-130.151967,55.163275],[-130.159983,55.153713],[-130.167592,55.129584],[-130.173695,55.117743],[-130.200266,55.104153],[-130.211781,55.084133],[-130.228871,55.04385],[-130.238678,55.03441],[-130.261342,55.022895],[-130.269846,55.016547],[-130.275706,55.006985],[-130.286366,54.983222],[-130.294342,54.971869],[-130.326568,54.952094],[-130.335561,54.938707],[-130.365387,54.907294],[-130.385243,54.896552],[-130.430816,54.881252],[-130.488759,54.844184],[-130.580312,54.806383],[-130.597485,54.803391],[-130.71074,54.733215],[-131.160718,54.787192]]]]}}]},"featureIcons":{"circle-stroked-24":{"x":0,"y":0,"width":24,"height":24},"circle-stroked-18":{"x":24,"y":0,"width":18,"height":18},"circle-stroked-12":{"x":42,"y":0,"width":12,"height":12},"circle-24":{"x":54,"y":0,"width":24,"height":24},"circle-18":{"x":78,"y":0,"width":18,"height":18},"circle-12":{"x":96,"y":0,"width":12,"height":12},"square-stroked-24":{"x":108,"y":0,"width":24,"height":24},"square-stroked-18":{"x":132,"y":0,"width":18,"height":18},"square-stroked-12":{"x":150,"y":0,"width":12,"height":12},"square-24":{"x":162,"y":0,"width":24,"height":24},"square-18":{"x":186,"y":0,"width":18,"height":18},"square-12":{"x":204,"y":0,"width":12,"height":12},"triangle-stroked-24":{"x":216,"y":0,"width":24,"height":24},"triangle-stroked-18":{"x":240,"y":0,"width":18,"height":18},"triangle-stroked-12":{"x":258,"y":0,"width":12,"height":12},"triangle-24":{"x":0,"y":24,"width":24,"height":24},"triangle-18":{"x":24,"y":24,"width":18,"height":18},"triangle-12":{"x":42,"y":24,"width":12,"height":12},"star-stroked-24":{"x":54,"y":24,"width":24,"height":24},"star-stroked-18":{"x":78,"y":24,"width":18,"height":18},"star-stroked-12":{"x":96,"y":24,"width":12,"height":12},"star-24":{"x":108,"y":24,"width":24,"height":24},"star-18":{"x":132,"y":24,"width":18,"height":18},"star-12":{"x":150,"y":24,"width":12,"height":12},"cross-24":{"x":162,"y":24,"width":24,"height":24},"cross-18":{"x":186,"y":24,"width":18,"height":18},"cross-12":{"x":204,"y":24,"width":12,"height":12},"marker-stroked-24":{"x":216,"y":24,"width":24,"height":24},"marker-stroked-18":{"x":240,"y":24,"width":18,"height":18},"marker-stroked-12":{"x":258,"y":24,"width":12,"height":12},"marker-24":{"x":0,"y":48,"width":24,"height":24},"marker-18":{"x":24,"y":48,"width":18,"height":18},"marker-12":{"x":42,"y":48,"width":12,"height":12},"religious-jewish-24":{"x":54,"y":48,"width":24,"height":24},"religious-jewish-18":{"x":78,"y":48,"width":18,"height":18},"religious-jewish-12":{"x":96,"y":48,"width":12,"height":12},"religious-christian-24":{"x":108,"y":48,"width":24,"height":24},"religious-christian-18":{"x":132,"y":48,"width":18,"height":18},"religious-christian-12":{"x":150,"y":48,"width":12,"height":12},"religious-muslim-24":{"x":162,"y":48,"width":24,"height":24},"religious-muslim-18":{"x":186,"y":48,"width":18,"height":18},"religious-muslim-12":{"x":204,"y":48,"width":12,"height":12},"cemetery-24":{"x":216,"y":48,"width":24,"height":24},"cemetery-18":{"x":240,"y":48,"width":18,"height":18},"cemetery-12":{"x":258,"y":48,"width":12,"height":12},"rocket-24":{"x":0,"y":72,"width":24,"height":24},"rocket-18":{"x":24,"y":72,"width":18,"height":18},"rocket-12":{"x":42,"y":72,"width":12,"height":12},"airport-24":{"x":54,"y":72,"width":24,"height":24},"airport-18":{"x":78,"y":72,"width":18,"height":18},"airport-12":{"x":96,"y":72,"width":12,"height":12},"heliport-24":{"x":108,"y":72,"width":24,"height":24},"heliport-18":{"x":132,"y":72,"width":18,"height":18},"heliport-12":{"x":150,"y":72,"width":12,"height":12},"rail-24":{"x":162,"y":72,"width":24,"height":24},"rail-18":{"x":186,"y":72,"width":18,"height":18},"rail-12":{"x":204,"y":72,"width":12,"height":12},"rail-metro-24":{"x":216,"y":72,"width":24,"height":24},"rail-metro-18":{"x":240,"y":72,"width":18,"height":18},"rail-metro-12":{"x":258,"y":72,"width":12,"height":12},"rail-light-24":{"x":0,"y":96,"width":24,"height":24},"rail-light-18":{"x":24,"y":96,"width":18,"height":18},"rail-light-12":{"x":42,"y":96,"width":12,"height":12},"bus-24":{"x":54,"y":96,"width":24,"height":24},"bus-18":{"x":78,"y":96,"width":18,"height":18},"bus-12":{"x":96,"y":96,"width":12,"height":12},"fuel-24":{"x":108,"y":96,"width":24,"height":24},"fuel-18":{"x":132,"y":96,"width":18,"height":18},"fuel-12":{"x":150,"y":96,"width":12,"height":12},"parking-24":{"x":162,"y":96,"width":24,"height":24},"parking-18":{"x":186,"y":96,"width":18,"height":18},"parking-12":{"x":204,"y":96,"width":12,"height":12},"parking-garage-24":{"x":216,"y":96,"width":24,"height":24},"parking-garage-18":{"x":240,"y":96,"width":18,"height":18},"parking-garage-12":{"x":258,"y":96,"width":12,"height":12},"airfield-24":{"x":0,"y":120,"width":24,"height":24},"airfield-18":{"x":24,"y":120,"width":18,"height":18},"airfield-12":{"x":42,"y":120,"width":12,"height":12},"roadblock-24":{"x":54,"y":120,"width":24,"height":24},"roadblock-18":{"x":78,"y":120,"width":18,"height":18},"roadblock-12":{"x":96,"y":120,"width":12,"height":12},"ferry-24":{"x":108,"y":120,"width":24,"height":24},"ferry-18":{"x":132,"y":120,"width":18,"height":18},"ferry-12":{"x":150,"y":120,"width":12,"height":12},"harbor-24":{"x":162,"y":120,"width":24,"height":24},"harbor-18":{"x":186,"y":120,"width":18,"height":18},"harbor-12":{"x":204,"y":120,"width":12,"height":12},"bicycle-24":{"x":216,"y":120,"width":24,"height":24},"bicycle-18":{"x":240,"y":120,"width":18,"height":18},"bicycle-12":{"x":258,"y":120,"width":12,"height":12},"park-24":{"x":0,"y":144,"width":24,"height":24},"park-18":{"x":24,"y":144,"width":18,"height":18},"park-12":{"x":42,"y":144,"width":12,"height":12},"park2-24":{"x":54,"y":144,"width":24,"height":24},"park2-18":{"x":78,"y":144,"width":18,"height":18},"park2-12":{"x":96,"y":144,"width":12,"height":12},"museum-24":{"x":108,"y":144,"width":24,"height":24},"museum-18":{"x":132,"y":144,"width":18,"height":18},"museum-12":{"x":150,"y":144,"width":12,"height":12},"lodging-24":{"x":162,"y":144,"width":24,"height":24},"lodging-18":{"x":186,"y":144,"width":18,"height":18},"lodging-12":{"x":204,"y":144,"width":12,"height":12},"monument-24":{"x":216,"y":144,"width":24,"height":24},"monument-18":{"x":240,"y":144,"width":18,"height":18},"monument-12":{"x":258,"y":144,"width":12,"height":12},"zoo-24":{"x":0,"y":168,"width":24,"height":24},"zoo-18":{"x":24,"y":168,"width":18,"height":18},"zoo-12":{"x":42,"y":168,"width":12,"height":12},"garden-24":{"x":54,"y":168,"width":24,"height":24},"garden-18":{"x":78,"y":168,"width":18,"height":18},"garden-12":{"x":96,"y":168,"width":12,"height":12},"campsite-24":{"x":108,"y":168,"width":24,"height":24},"campsite-18":{"x":132,"y":168,"width":18,"height":18},"campsite-12":{"x":150,"y":168,"width":12,"height":12},"theatre-24":{"x":162,"y":168,"width":24,"height":24},"theatre-18":{"x":186,"y":168,"width":18,"height":18},"theatre-12":{"x":204,"y":168,"width":12,"height":12},"art-gallery-24":{"x":216,"y":168,"width":24,"height":24},"art-gallery-18":{"x":240,"y":168,"width":18,"height":18},"art-gallery-12":{"x":258,"y":168,"width":12,"height":12},"pitch-24":{"x":0,"y":192,"width":24,"height":24},"pitch-18":{"x":24,"y":192,"width":18,"height":18},"pitch-12":{"x":42,"y":192,"width":12,"height":12},"soccer-24":{"x":54,"y":192,"width":24,"height":24},"soccer-18":{"x":78,"y":192,"width":18,"height":18},"soccer-12":{"x":96,"y":192,"width":12,"height":12},"america-football-24":{"x":108,"y":192,"width":24,"height":24},"america-football-18":{"x":132,"y":192,"width":18,"height":18},"america-football-12":{"x":150,"y":192,"width":12,"height":12},"tennis-24":{"x":162,"y":192,"width":24,"height":24},"tennis-18":{"x":186,"y":192,"width":18,"height":18},"tennis-12":{"x":204,"y":192,"width":12,"height":12},"basketball-24":{"x":216,"y":192,"width":24,"height":24},"basketball-18":{"x":240,"y":192,"width":18,"height":18},"basketball-12":{"x":258,"y":192,"width":12,"height":12},"baseball-24":{"x":0,"y":216,"width":24,"height":24},"baseball-18":{"x":24,"y":216,"width":18,"height":18},"baseball-12":{"x":42,"y":216,"width":12,"height":12},"golf-24":{"x":54,"y":216,"width":24,"height":24},"golf-18":{"x":78,"y":216,"width":18,"height":18},"golf-12":{"x":96,"y":216,"width":12,"height":12},"swimming-24":{"x":108,"y":216,"width":24,"height":24},"swimming-18":{"x":132,"y":216,"width":18,"height":18},"swimming-12":{"x":150,"y":216,"width":12,"height":12},"cricket-24":{"x":162,"y":216,"width":24,"height":24},"cricket-18":{"x":186,"y":216,"width":18,"height":18},"cricket-12":{"x":204,"y":216,"width":12,"height":12},"skiing-24":{"x":216,"y":216,"width":24,"height":24},"skiing-18":{"x":240,"y":216,"width":18,"height":18},"skiing-12":{"x":258,"y":216,"width":12,"height":12},"school-24":{"x":0,"y":240,"width":24,"height":24},"school-18":{"x":24,"y":240,"width":18,"height":18},"school-12":{"x":42,"y":240,"width":12,"height":12},"college-24":{"x":54,"y":240,"width":24,"height":24},"college-18":{"x":78,"y":240,"width":18,"height":18},"college-12":{"x":96,"y":240,"width":12,"height":12},"library-24":{"x":108,"y":240,"width":24,"height":24},"library-18":{"x":132,"y":240,"width":18,"height":18},"library-12":{"x":150,"y":240,"width":12,"height":12},"post-24":{"x":162,"y":240,"width":24,"height":24},"post-18":{"x":186,"y":240,"width":18,"height":18},"post-12":{"x":204,"y":240,"width":12,"height":12},"fire-station-24":{"x":216,"y":240,"width":24,"height":24},"fire-station-18":{"x":240,"y":240,"width":18,"height":18},"fire-station-12":{"x":258,"y":240,"width":12,"height":12},"town-hall-24":{"x":0,"y":264,"width":24,"height":24},"town-hall-18":{"x":24,"y":264,"width":18,"height":18},"town-hall-12":{"x":42,"y":264,"width":12,"height":12},"police-24":{"x":54,"y":264,"width":24,"height":24},"police-18":{"x":78,"y":264,"width":18,"height":18},"police-12":{"x":96,"y":264,"width":12,"height":12},"prison-24":{"x":108,"y":264,"width":24,"height":24},"prison-18":{"x":132,"y":264,"width":18,"height":18},"prison-12":{"x":150,"y":264,"width":12,"height":12},"embassy-24":{"x":162,"y":264,"width":24,"height":24},"embassy-18":{"x":186,"y":264,"width":18,"height":18},"embassy-12":{"x":204,"y":264,"width":12,"height":12},"beer-24":{"x":216,"y":264,"width":24,"height":24},"beer-18":{"x":240,"y":264,"width":18,"height":18},"beer-12":{"x":258,"y":264,"width":12,"height":12},"restaurant-24":{"x":0,"y":288,"width":24,"height":24},"restaurant-18":{"x":24,"y":288,"width":18,"height":18},"restaurant-12":{"x":42,"y":288,"width":12,"height":12},"cafe-24":{"x":54,"y":288,"width":24,"height":24},"cafe-18":{"x":78,"y":288,"width":18,"height":18},"cafe-12":{"x":96,"y":288,"width":12,"height":12},"shop-24":{"x":108,"y":288,"width":24,"height":24},"shop-18":{"x":132,"y":288,"width":18,"height":18},"shop-12":{"x":150,"y":288,"width":12,"height":12},"fast-food-24":{"x":162,"y":288,"width":24,"height":24},"fast-food-18":{"x":186,"y":288,"width":18,"height":18},"fast-food-12":{"x":204,"y":288,"width":12,"height":12},"bar-24":{"x":216,"y":288,"width":24,"height":24},"bar-18":{"x":240,"y":288,"width":18,"height":18},"bar-12":{"x":258,"y":288,"width":12,"height":12},"bank-24":{"x":0,"y":312,"width":24,"height":24},"bank-18":{"x":24,"y":312,"width":18,"height":18},"bank-12":{"x":42,"y":312,"width":12,"height":12},"grocery-24":{"x":54,"y":312,"width":24,"height":24},"grocery-18":{"x":78,"y":312,"width":18,"height":18},"grocery-12":{"x":96,"y":312,"width":12,"height":12},"cinema-24":{"x":108,"y":312,"width":24,"height":24},"cinema-18":{"x":132,"y":312,"width":18,"height":18},"cinema-12":{"x":150,"y":312,"width":12,"height":12},"pharmacy-24":{"x":162,"y":312,"width":24,"height":24},"pharmacy-18":{"x":186,"y":312,"width":18,"height":18},"pharmacy-12":{"x":204,"y":312,"width":12,"height":12},"hospital-24":{"x":216,"y":312,"width":24,"height":24},"hospital-18":{"x":240,"y":312,"width":18,"height":18},"hospital-12":{"x":258,"y":312,"width":12,"height":12},"danger-24":{"x":0,"y":336,"width":24,"height":24},"danger-18":{"x":24,"y":336,"width":18,"height":18},"danger-12":{"x":42,"y":336,"width":12,"height":12},"industrial-24":{"x":54,"y":336,"width":24,"height":24},"industrial-18":{"x":78,"y":336,"width":18,"height":18},"industrial-12":{"x":96,"y":336,"width":12,"height":12},"warehouse-24":{"x":108,"y":336,"width":24,"height":24},"warehouse-18":{"x":132,"y":336,"width":18,"height":18},"warehouse-12":{"x":150,"y":336,"width":12,"height":12},"commercial-24":{"x":162,"y":336,"width":24,"height":24},"commercial-18":{"x":186,"y":336,"width":18,"height":18},"commercial-12":{"x":204,"y":336,"width":12,"height":12},"building-24":{"x":216,"y":336,"width":24,"height":24},"building-18":{"x":240,"y":336,"width":18,"height":18},"building-12":{"x":258,"y":336,"width":12,"height":12},"place-of-worship-24":{"x":0,"y":360,"width":24,"height":24},"place-of-worship-18":{"x":24,"y":360,"width":18,"height":18},"place-of-worship-12":{"x":42,"y":360,"width":12,"height":12},"alcohol-shop-24":{"x":54,"y":360,"width":24,"height":24},"alcohol-shop-18":{"x":78,"y":360,"width":18,"height":18},"alcohol-shop-12":{"x":96,"y":360,"width":12,"height":12},"logging-24":{"x":108,"y":360,"width":24,"height":24},"logging-18":{"x":132,"y":360,"width":18,"height":18},"logging-12":{"x":150,"y":360,"width":12,"height":12},"oil-well-24":{"x":162,"y":360,"width":24,"height":24},"oil-well-18":{"x":186,"y":360,"width":18,"height":18},"oil-well-12":{"x":204,"y":360,"width":12,"height":12},"slaughterhouse-24":{"x":216,"y":360,"width":24,"height":24},"slaughterhouse-18":{"x":240,"y":360,"width":18,"height":18},"slaughterhouse-12":{"x":258,"y":360,"width":12,"height":12},"dam-24":{"x":0,"y":384,"width":24,"height":24},"dam-18":{"x":24,"y":384,"width":18,"height":18},"dam-12":{"x":42,"y":384,"width":12,"height":12},"water-24":{"x":54,"y":384,"width":24,"height":24},"water-18":{"x":78,"y":384,"width":18,"height":18},"water-12":{"x":96,"y":384,"width":12,"height":12},"wetland-24":{"x":108,"y":384,"width":24,"height":24},"wetland-18":{"x":132,"y":384,"width":18,"height":18},"wetland-12":{"x":150,"y":384,"width":12,"height":12},"disability-24":{"x":162,"y":384,"width":24,"height":24},"disability-18":{"x":186,"y":384,"width":18,"height":18},"disability-12":{"x":204,"y":384,"width":12,"height":12},"telephone-24":{"x":216,"y":384,"width":24,"height":24},"telephone-18":{"x":240,"y":384,"width":18,"height":18},"telephone-12":{"x":258,"y":384,"width":12,"height":12},"emergency-telephone-24":{"x":0,"y":408,"width":24,"height":24},"emergency-telephone-18":{"x":24,"y":408,"width":18,"height":18},"emergency-telephone-12":{"x":42,"y":408,"width":12,"height":12},"toilets-24":{"x":54,"y":408,"width":24,"height":24},"toilets-18":{"x":78,"y":408,"width":18,"height":18},"toilets-12":{"x":96,"y":408,"width":12,"height":12},"waste-basket-24":{"x":108,"y":408,"width":24,"height":24},"waste-basket-18":{"x":132,"y":408,"width":18,"height":18},"waste-basket-12":{"x":150,"y":408,"width":12,"height":12},"music-24":{"x":162,"y":408,"width":24,"height":24},"music-18":{"x":186,"y":408,"width":18,"height":18},"music-12":{"x":204,"y":408,"width":12,"height":12},"land-use-24":{"x":216,"y":408,"width":24,"height":24},"land-use-18":{"x":240,"y":408,"width":18,"height":18},"land-use-12":{"x":258,"y":408,"width":12,"height":12},"city-24":{"x":0,"y":432,"width":24,"height":24},"city-18":{"x":24,"y":432,"width":18,"height":18},"city-12":{"x":42,"y":432,"width":12,"height":12},"town-24":{"x":54,"y":432,"width":24,"height":24},"town-18":{"x":78,"y":432,"width":18,"height":18},"town-12":{"x":96,"y":432,"width":12,"height":12},"village-24":{"x":108,"y":432,"width":24,"height":24},"village-18":{"x":132,"y":432,"width":18,"height":18},"village-12":{"x":150,"y":432,"width":12,"height":12},"farm-24":{"x":162,"y":432,"width":24,"height":24},"farm-18":{"x":186,"y":432,"width":18,"height":18},"farm-12":{"x":204,"y":432,"width":12,"height":12},"bakery-24":{"x":216,"y":432,"width":24,"height":24},"bakery-18":{"x":240,"y":432,"width":18,"height":18},"bakery-12":{"x":258,"y":432,"width":12,"height":12},"dog-park-24":{"x":0,"y":456,"width":24,"height":24},"dog-park-18":{"x":24,"y":456,"width":18,"height":18},"dog-park-12":{"x":42,"y":456,"width":12,"height":12},"lighthouse-24":{"x":54,"y":456,"width":24,"height":24},"lighthouse-18":{"x":78,"y":456,"width":18,"height":18},"lighthouse-12":{"x":96,"y":456,"width":12,"height":12},"clothing-store-24":{"x":108,"y":456,"width":24,"height":24},"clothing-store-18":{"x":132,"y":456,"width":18,"height":18},"clothing-store-12":{"x":150,"y":456,"width":12,"height":12},"polling-place-24":{"x":162,"y":456,"width":24,"height":24},"polling-place-18":{"x":186,"y":456,"width":18,"height":18},"polling-place-12":{"x":204,"y":456,"width":12,"height":12},"playground-24":{"x":216,"y":456,"width":24,"height":24},"playground-18":{"x":240,"y":456,"width":18,"height":18},"playground-12":{"x":258,"y":456,"width":12,"height":12},"entrance-24":{"x":0,"y":480,"width":24,"height":24},"entrance-18":{"x":24,"y":480,"width":18,"height":18},"entrance-12":{"x":42,"y":480,"width":12,"height":12},"heart-24":{"x":54,"y":480,"width":24,"height":24},"heart-18":{"x":78,"y":480,"width":18,"height":18},"heart-12":{"x":96,"y":480,"width":12,"height":12},"london-underground-24":{"x":108,"y":480,"width":24,"height":24},"london-underground-18":{"x":132,"y":480,"width":18,"height":18},"london-underground-12":{"x":150,"y":480,"width":12,"height":12},"minefield-24":{"x":162,"y":480,"width":24,"height":24},"minefield-18":{"x":186,"y":480,"width":18,"height":18},"minefield-12":{"x":204,"y":480,"width":12,"height":12},"rail-underground-24":{"x":216,"y":480,"width":24,"height":24},"rail-underground-18":{"x":240,"y":480,"width":18,"height":18},"rail-underground-12":{"x":258,"y":480,"width":12,"height":12},"rail-above-24":{"x":0,"y":504,"width":24,"height":24},"rail-above-18":{"x":24,"y":504,"width":18,"height":18},"rail-above-12":{"x":42,"y":504,"width":12,"height":12},"camera-24":{"x":54,"y":504,"width":24,"height":24},"camera-18":{"x":78,"y":504,"width":18,"height":18},"camera-12":{"x":96,"y":504,"width":12,"height":12},"laundry-24":{"x":108,"y":504,"width":24,"height":24},"laundry-18":{"x":132,"y":504,"width":18,"height":18},"laundry-12":{"x":150,"y":504,"width":12,"height":12},"car-24":{"x":162,"y":504,"width":24,"height":24},"car-18":{"x":186,"y":504,"width":18,"height":18},"car-12":{"x":204,"y":504,"width":12,"height":12},"suitcase-24":{"x":216,"y":504,"width":24,"height":24},"suitcase-18":{"x":240,"y":504,"width":18,"height":18},"suitcase-12":{"x":258,"y":504,"width":12,"height":12},"hairdresser-24":{"x":0,"y":528,"width":24,"height":24},"hairdresser-18":{"x":24,"y":528,"width":18,"height":18},"hairdresser-12":{"x":42,"y":528,"width":12,"height":12},"chemist-24":{"x":54,"y":528,"width":24,"height":24},"chemist-18":{"x":78,"y":528,"width":18,"height":18},"chemist-12":{"x":96,"y":528,"width":12,"height":12},"mobilephone-24":{"x":108,"y":528,"width":24,"height":24},"mobilephone-18":{"x":132,"y":528,"width":18,"height":18},"mobilephone-12":{"x":150,"y":528,"width":12,"height":12},"scooter-24":{"x":162,"y":528,"width":24,"height":24},"scooter-18":{"x":186,"y":528,"width":18,"height":18},"scooter-12":{"x":204,"y":528,"width":12,"height":12},"gift-24":{"x":216,"y":528,"width":24,"height":24},"gift-18":{"x":240,"y":528,"width":18,"height":18},"gift-12":{"x":258,"y":528,"width":12,"height":12},"ice-cream-24":{"x":0,"y":552,"width":24,"height":24},"ice-cream-18":{"x":24,"y":552,"width":18,"height":18},"ice-cream-12":{"x":42,"y":552,"width":12,"height":12}},"locales":["af","sq","ar","ar-AA","hy","ast","bn","bs","bg-BG","ca","zh","zh-CN","zh-HK","zh-TW","yue","hr","cs","da","nl","en-GB","eo","et","fi","fr","gl","de","el","hi","hu","is","id","it","ja","kn","ko","lv","lij","lt","no","fa","pl","pt","pt-BR","ro","ru","sc","sr","si","sk","sl","es","sv","tl","ta","te","th","tr","uk","vi"],"en":{"modes":{"add_area":{"title":"Area","description":"Add parks, buildings, lakes or other areas to the map.","tail":"Click on the map to start drawing an area, like a park, lake, or building."},"add_line":{"title":"Line","description":"Add highways, streets, pedestrian paths, canals or other lines to the map.","tail":"Click on the map to start drawing a road, path, or route."},"add_point":{"title":"Point","description":"Add restaurants, monuments, postal boxes or other points to the map.","tail":"Click on the map to add a point."},"browse":{"title":"Browse","description":"Pan and zoom the map."},"draw_area":{"tail":"Click to add nodes to your area. Click the first node to finish the area."},"draw_line":{"tail":"Click to add more nodes to the line. Click on other lines to connect to them, and double-click to end the line."}},"operations":{"add":{"annotation":{"point":"Added a point.","vertex":"Added a node to a way.","relation":"Added a relation."}},"start":{"annotation":{"line":"Started a line.","area":"Started an area."}},"continue":{"key":"A","title":"Continue","description":"Continue this line.","not_eligible":"No line can be continued here.","multiple":"Several lines can be continued here. To choose a line, press the Shift key and click on it to select it.","annotation":{"line":"Continued a line.","area":"Continued an area."}},"cancel_draw":{"annotation":"Canceled drawing."},"change_role":{"annotation":"Changed the role of a relation member."},"change_tags":{"annotation":"Changed tags."},"circularize":{"title":"Circularize","description":{"line":"Make this line circular.","area":"Make this area circular."},"key":"O","annotation":{"line":"Made a line circular.","area":"Made an area circular."},"not_closed":"This can't be made circular because it's not a loop.","too_large":"This can't be made circular because not enough of it is currently visible.","connected_to_hidden":"This can't be made circular because it is connected to a hidden feature."},"orthogonalize":{"title":"Square","description":{"line":"Square the corners of this line.","area":"Square the corners of this area."},"key":"S","annotation":{"line":"Squared the corners of a line.","area":"Squared the corners of an area."},"not_squarish":"This can't be made square because it is not squarish.","too_large":"This can't be made square because not enough of it is currently visible.","connected_to_hidden":"This can't be made square because it is connected to a hidden feature."},"straighten":{"title":"Straighten","description":"Straighten this line.","key":"S","annotation":"Straightened a line.","too_bendy":"This can't be straightened because it bends too much.","connected_to_hidden":"This line can't be straightened because it is connected to a hidden feature."},"delete":{"title":"Delete","description":"Delete object permanently.","annotation":{"point":"Deleted a point.","vertex":"Deleted a node from a way.","line":"Deleted a line.","area":"Deleted an area.","relation":"Deleted a relation.","multiple":"Deleted {n} objects."},"incomplete_relation":"This feature can't be deleted because it hasn't been fully downloaded.","part_of_relation":"This feature can't be deleted because it's part of a larger relation. You must remove it from the relation first.","connected_to_hidden":"This can't be deleted because it is connected to a hidden feature."},"add_member":{"annotation":"Added a member to a relation."},"delete_member":{"annotation":"Removed a member from a relation."},"connect":{"annotation":{"point":"Connected a way to a point.","vertex":"Connected a way to another.","line":"Connected a way to a line.","area":"Connected a way to an area."}},"disconnect":{"title":"Disconnect","description":"Disconnect these lines/areas from each other.","key":"D","annotation":"Disconnected lines/areas.","not_connected":"There aren't enough lines/areas here to disconnect.","connected_to_hidden":"This can't be disconnected because it is connected to a hidden feature.","relation":"This can't be disconnected because it connects members of a relation."},"merge":{"title":"Merge","description":"Merge these features.","key":"C","annotation":"Merged {n} features.","not_eligible":"These features can't be merged.","not_adjacent":"These features can't be merged because they aren't connected.","restriction":"These features can't be merged because at least one is a member of a \"{relation}\" relation.","incomplete_relation":"These features can't be merged because at least one hasn't been fully downloaded.","conflicting_tags":"These features can't be merged because some of their tags have conflicting values."},"move":{"title":"Move","description":"Move this to a different location.","key":"M","annotation":{"point":"Moved a point.","vertex":"Moved a node in a way.","line":"Moved a line.","area":"Moved an area.","multiple":"Moved multiple objects."},"incomplete_relation":"This feature can't be moved because it hasn't been fully downloaded.","too_large":"This can't be moved because not enough of it is currently visible.","connected_to_hidden":"This can't be moved because it is connected to a hidden feature."},"rotate":{"title":"Rotate","description":"Rotate this object around its center point.","key":"R","annotation":{"line":"Rotated a line.","area":"Rotated an area."},"too_large":"This can't be rotated because not enough of it is currently visible.","connected_to_hidden":"This can't be rotated because it is connected to a hidden feature."},"reverse":{"title":"Reverse","description":"Make this line go in the opposite direction.","key":"V","annotation":"Reversed a line."},"split":{"title":"Split","description":{"line":"Split this line into two at this node.","area":"Split the boundary of this area into two.","multiple":"Split the lines/area boundaries at this node into two."},"key":"X","annotation":{"line":"Split a line.","area":"Split an area boundary.","multiple":"Split {n} lines/area boundaries."},"not_eligible":"Lines can't be split at their beginning or end.","multiple_ways":"There are too many lines here to split.","connected_to_hidden":"This can't be split because it is connected to a hidden feature."},"restriction":{"help":{"select":"Click to select a road segment.","toggle":"Click to toggle turn restrictions.","toggle_on":"Click to add a \"{restriction}\" restriction.","toggle_off":"Click to remove the \"{restriction}\" restriction."},"annotation":{"create":"Added a turn restriction","delete":"Deleted a turn restriction"}}},"undo":{"tooltip":"Undo: {action}","nothing":"Nothing to undo."},"redo":{"tooltip":"Redo: {action}","nothing":"Nothing to redo."},"tooltip_keyhint":"Shortcut:","browser_notice":"This editor is supported in Firefox, Chrome, Safari, Opera, and Internet Explorer 11 and above. Please upgrade your browser or use Potlatch 2 to edit the map.","translate":{"translate":"Translate","localized_translation_label":"Multilingual name","localized_translation_language":"Choose language","localized_translation_name":"Name"},"zoom_in_edit":"Zoom in to Edit","logout":"logout","loading_auth":"Connecting to OpenStreetMap...","report_a_bug":"Report a bug","help_translate":"Help translate","feature_info":{"hidden_warning":"{count} hidden features","hidden_details":"These features are currently hidden: {details}"},"status":{"error":"Unable to connect to API.","offline":"The API is offline. Please try editing later.","readonly":"The API is read-only. You will need to wait to save your changes."},"commit":{"title":"Save Changes","description_placeholder":"Brief description of your contributions","message_label":"Changeset comment","upload_explanation":"The changes you upload will be visible on all maps that use OpenStreetMap data.","upload_explanation_with_user":"The changes you upload as {user} will be visible on all maps that use OpenStreetMap data.","save":"Save","cancel":"Cancel","changes":"{count} Changes","warnings":"Warnings","modified":"Modified","deleted":"Deleted","created":"Created","about_changeset_comments":"About changeset comments","about_changeset_comments_link":"//wiki.openstreetmap.org/wiki/Good_changeset_comments"},"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"},"inspector":{"no_documentation_combination":"There is no documentation available for this tag combination","no_documentation_key":"There is no documentation available for this key","show_more":"Show More","view_on_osm":"View on openstreetmap.org","all_fields":"All fields","all_tags":"All tags","all_members":"All members","all_relations":"All relations","new_relation":"New relation...","role":"Role","choose":"Select feature type","results":"{n} results for {search}","reference":"View on OpenStreetMap Wiki","back_tooltip":"Change feature","remove":"Remove","search":"Search","multiselect":"Selected items","unknown":"Unknown","incomplete":"<not downloaded>","feature_list":"Search features","edit":"Edit feature","check":{"yes":"Yes","no":"No"},"none":"None","node":"Node","way":"Way","relation":"Relation","location":"Location","add_fields":"Add field:"},"background":{"title":"Background","description":"Background settings","percent_brightness":"{opacity}% brightness","none":"None","best_imagery":"Best known imagery source for this location","custom":"Custom","custom_button":"Edit custom background","custom_prompt":"Enter a tile URL template. Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.","fix_misalignment":"Fix alignment","imagery_source_faq":"Where does this imagery come from?","reset":"reset","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"},"major_roads":{"description":"Major Roads","tooltip":"Highways, Streets, etc."},"minor_roads":{"description":"Minor Roads","tooltip":"Service Roads, Parking Aisles, Tracks, etc."},"paths":{"description":"Paths","tooltip":"Sidewalks, Foot Paths, Cycle Paths, etc."},"buildings":{"description":"Buildings","tooltip":"Buildings, Shelters, Garages, etc."},"landuse":{"description":"Landuse Features","tooltip":"Forests, Farmland, Parks, Residential, Commercial, etc."},"boundaries":{"description":"Boundaries","tooltip":"Administrative Boundaries"},"water":{"description":"Water Features","tooltip":"Rivers, Lakes, Ponds, Basins, etc."},"rail":{"description":"Rail Features","tooltip":"Railways"},"power":{"description":"Power Features","tooltip":"Power Lines, Power Plants, Substations, etc."},"past_future":{"description":"Past/Future","tooltip":"Proposed, Construction, Abandoned, Demolished, etc."},"others":{"description":"Others","tooltip":"Everything Else"}},"area_fill":{"wireframe":{"description":"No Fill (Wireframe)","tooltip":"Enabling wireframe mode makes it easy to see the background imagery."},"partial":{"description":"Partial Fill","tooltip":"Areas are drawn with fill only around their inner edges. (Recommended for beginner mappers)"},"full":{"description":"Full Fill","tooltip":"Areas are drawn fully filled."}},"restore":{"heading":"You have unsaved changes","description":"Do you wish to restore unsaved changes from a previous editing session?","restore":"Restore","reset":"Reset"},"save":{"title":"Save","help":"Save changes to OpenStreetMap, making them visible to other users.","no_changes":"No changes to save.","error":"Errors occurred while trying to save","status_code":"Server returned status code {code}","unknown_error_details":"Please ensure you are connected to the internet.","uploading":"Uploading changes to OpenStreetMap.","unsaved_changes":"You have unsaved changes","conflict":{"header":"Resolve conflicting edits","count":"Conflict {num} of {total}","previous":"< Previous","next":"Next >","keep_local":"Keep mine","keep_remote":"Use theirs","restore":"Restore","delete":"Leave Deleted","download_changes":"Or download your changes.","done":"All conflicts resolved!","help":"Another user changed some of the same map features you changed.\nClick on each item below for more details about the conflict, and choose whether to keep\nyour changes or the other user's changes.\n"}},"merge_remote_changes":{"conflict":{"deleted":"This object has been deleted by {user}.","location":"This object was moved by both you and {user}.","nodelist":"Nodes were changed by both you and {user}.","memberlist":"Relation members were changed by both you and {user}.","tags":"You changed the <b>{tag}</b> tag to \"{local}\" and {user} changed it to \"{remote}\"."}},"success":{"edited_osm":"Edited OSM!","just_edited":"You just edited OpenStreetMap!","view_on_osm":"View on OSM","facebook":"Share on Facebook","twitter":"Share on Twitter","google":"Share on Google+","help_html":"Your changes should appear in the \"Standard\" layer in a few minutes. Other layers, and certain features, may take longer.","help_link_text":"Details","help_link_url":"https://wiki.openstreetmap.org/wiki/FAQ#I_have_just_made_some_changes_to_the_map._How_do_I_get_to_see_my_changes.3F"},"confirm":{"okay":"Okay","cancel":"Cancel"},"splash":{"welcome":"Welcome to the iD OpenStreetMap editor","text":"iD is a friendly but powerful tool for contributing to the world's best free world map. This is version {version}. For more information see {website} and report bugs at {github}.","walkthrough":"Start the Walkthrough","start":"Edit Now"},"source_switch":{"live":"live","lose_changes":"You have unsaved changes. Switching the map server will discard them. Are you sure you want to switch servers?","dev":"dev"},"tag_reference":{"description":"Description","on_wiki":"{tag} on wiki.osm.org","used_with":"used with {type}"},"validations":{"untagged_point":"Untagged point","untagged_line":"Untagged line","untagged_area":"Untagged area","many_deletions":"You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.","tag_suggests_area":"The tag {tag} suggests line should be area, but it is not an area","untagged_point_tooltip":"Select a feature type that describes what this point is.","untagged_line_tooltip":"Select a feature type that describes what this line is.","untagged_area_tooltip":"Select a feature type that describes what this area is.","deprecated_tags":"Deprecated tags: {tags}"},"zoom":{"in":"Zoom In","out":"Zoom Out"},"cannot_zoom":"Cannot zoom out further in current mode.","full_screen":"Toggle Full Screen","gpx":{"local_layer":"Local GPX file","drag_drop":"Drag and drop a .gpx file on the page, or click the button to the right to browse","zoom":"Zoom to GPX track","browse":"Browse for a .gpx file"},"mapillary_images":{"tooltip":"Street-level photos from Mapillary","title":"Photo Overlay (Mapillary)"},"mapillary_signs":{"tooltip":"Traffic signs from Mapillary","title":"Traffic Sign Overlay (Mapillary)"},"mapillary":{"view_on_mapillary":"View this image on Mapillary"},"help":{"title":"Help","help":"# Help\n\nThis is an editor for [OpenStreetMap](http://www.openstreetmap.org/), the\nfree and editable map of the world. You can use it to add and update\ndata in your area, making an open-source and open-data map of the world\nbetter for everyone.\n\nEdits that you make on this map will be visible to everyone who uses\nOpenStreetMap. In order to make an edit, you'll need to\n[log in](https://www.openstreetmap.org/login).\n\nThe [iD editor](http://ideditor.com/) is a collaborative project with [source\ncode available on GitHub](https://github.com/openstreetmap/iD).\n","editing_saving":"# Editing & Saving\n\nThis editor is designed to work primarily online, and you're accessing\nit through a website right now.\n\n### Selecting Features\n\nTo select a map feature, like a road or point of interest, click\non it on the map. This will highlight the selected feature, open a panel with\ndetails about it, and show a menu of things you can do with the feature.\n\nTo select multiple features, hold down the 'Shift' key. Then either click\non the features you want to select, or drag on the map to draw a rectangle.\nThis will draw a box and select all the points within it.\n\n### Saving Edits\n\nWhen you make changes like editing roads, buildings, and places, these are\nstored locally until you save them to the server. Don't worry if you make\na mistake - you can undo changes by clicking the undo button, and redo\nchanges by clicking the redo button.\n\nClick 'Save' to finish a group of edits - for instance, if you've completed\nan area of town and would like to start on a new area. You'll have a chance\nto review what you've done, and the editor supplies helpful suggestions\nand warnings if something doesn't seem right about the changes.\n\nIf everything looks good, you can enter a short comment explaining the change\nyou made, and click 'Save' again to post the changes\nto [OpenStreetMap.org](http://www.openstreetmap.org/), where they are visible\nto all other users and available for others to build and improve upon.\n\nIf you can't finish your edits in one sitting, you can leave the editor\nwindow and come back (on the same browser and computer), and the\neditor application will offer to restore your work.\n\n### Using the editor\n\nA list of available keyboard shortcuts can be found [here](http://wiki.openstreetmap.org/wiki/ID/Shortcuts).\n","roads":"# Roads\n\nYou can create, fix, and delete roads with this editor. Roads can be all\nkinds: paths, highways, trails, cycleways, and more - any often-crossed\nsegment should be mappable.\n\n### Selecting\n\nClick on a road to select it. An outline should become visible, along\nwith a small tools menu on the map and a sidebar showing more information\nabout the road.\n\n### Modifying\n\nOften you'll see roads that aren't aligned to the imagery behind them\nor to a GPS track. You can adjust these roads so they are in the correct\nplace.\n\nFirst click on the road you want to change. This will highlight it and show\ncontrol points along it that you can drag to better locations. If\nyou want to add new control points for more detail, double-click a part\nof the road without a node, and one will be added.\n\nIf the road connects to another road, but doesn't properly connect on\nthe map, you can drag one of its control points onto the other road in\norder to join them. Having roads connect is important for the map\nand essential for providing driving directions.\n\nYou can also click the 'Move' tool or press the `M` shortcut key to move the entire road at\none time, and then click again to save that movement.\n\n### Deleting\n\nIf a road is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the road could simply be newly built.\n\nYou can delete a road by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n\n### Creating\n\nFound somewhere there should be a road but there isn't? Click the 'Line'\nicon in the top-left of the editor or press the shortcut key `2` to start drawing\na line.\n\nClick on the start of the road on the map to start drawing. If the road\nbranches off from an existing road, start by clicking on the place where they connect.\n\nThen click on points along the road so that it follows the right path, according\nto satellite imagery or GPS. If the road you are drawing crosses another road, connect\nit by clicking on the intersection point. When you're done drawing, double-click\nor press 'Return' or 'Enter' on your keyboard.\n","gps":"# GPS\n\nCollected GPS traces are one valuable source of data for OpenStreetMap. This editor\nsupports local traces - `.gpx` files on your local computer. You can collect\nthis kind of GPS trace with a number of smartphone applications as well as\npersonal GPS hardware.\n\nFor information on how to perform a GPS survey, read\n[Mapping with a smartphone, GPS, or paper](http://learnosm.org/en/mobile-mapping/).\n\nTo use a GPX track for mapping, drag and drop the GPX file onto the map\neditor. If it's recognized, it will be added to the map as a bright purple\nline. Click on the 'Map Data' menu on the right side to enable,\ndisable, or zoom to this new GPX-powered layer.\n\nThe GPX track isn't directly uploaded to OpenStreetMap - the best way to\nuse it is to draw on the map, using it as a guide for the new features that\nyou add, and also to [upload it to OpenStreetMap](http://www.openstreetmap.org/trace/create)\nfor other users to use.\n","imagery":"# Imagery\n\nAerial imagery is an important resource for mapping. A combination of\nairplane flyovers, satellite views, and freely-compiled sources are available\nin the editor under the 'Background Settings' menu on the right.\n\nBy default a [Bing Maps](http://www.bing.com/maps/) satellite layer is\npresented in the editor, but as you pan and zoom the map to new geographical\nareas, new sources will become available. Some countries, like the United\nStates, France, and Denmark have very high-quality imagery available for some areas.\n\nImagery is sometimes offset from the map data because of a mistake on the\nimagery provider's side. If you see a lot of roads shifted from the background,\ndon't immediately move them all to match the background. Instead you can adjust\nthe imagery so that it matches the existing data by clicking 'Fix alignment' at\nthe bottom of the Background Settings UI.\n","addresses":"# Addresses\n\nAddresses are some of the most useful information for the map.\n\nAlthough addresses are often represented as parts of streets, in OpenStreetMap\nthey're recorded as attributes of buildings and places along streets.\n\nYou can add address information to places mapped as building outlines\nas well as those mapped as single points. The optimal source of address\ndata is from an on-the-ground survey or personal knowledge - as with any\nother feature, copying from commercial sources like Google Maps is strictly\nforbidden.\n","inspector":"# Using the Inspector\n\nThe inspector is the section on the left side of the page that allows you to\nedit the details of the selected feature.\n\n### Selecting a Feature Type\n\nAfter you add a point, line, or area, you can choose what type of feature it\nis, like whether it's a highway or residential road, supermarket or cafe.\nThe inspector will display buttons for common feature types, and you can\nfind others by typing what you're looking for in the search box.\n\nClick the 'i' in the bottom-right-hand corner of a feature type button to\nlearn more about it. Click a button to choose that type.\n\n### Using Forms and Editing Tags\n\nAfter you choose a feature type, or when you select a feature that already\nhas a type assigned, the inspector will display fields with details about\nthe feature like its name and address.\n\nBelow the fields you see, you can click the 'Add field' dropdown to add\nother details, like a Wikipedia link, wheelchair access, and more.\n\nAt the bottom of the inspector, click 'Additional tags' to add arbitrary\nother tags to the element. [Taginfo](http://taginfo.openstreetmap.org/) is a\ngreat resource for learn more about popular tag combinations.\n\nChanges you make in the inspector are automatically applied to the map.\nYou can undo them at any time by clicking the 'Undo' button.\n","buildings":"# Buildings\n\nOpenStreetMap is the world's largest database of buildings. You can create\nand improve this database.\n\n### Selecting\n\nYou can select a building by clicking on its border. This will highlight the\nbuilding and open a small tools menu and a sidebar showing more information\nabout the building.\n\n### Modifying\n\nSometimes buildings are incorrectly placed or have incorrect tags.\n\nTo move an entire building, select it, then click the 'Move' tool. Move your\nmouse to shift the building, and click when it's correctly placed.\n\nTo fix the specific shape of a building, click and drag the nodes that form\nits border into better places.\n\n### Creating\n\nOne of the main questions around adding buildings to the map is that\nOpenStreetMap records buildings both as shapes and points. The rule of thumb\nis to _map a building as a shape whenever possible_, and map companies, homes,\namenities, and other things that operate out of buildings as points placed\nwithin the building shape.\n\nStart drawing a building as a shape by clicking the 'Area' button in the top\nleft of the interface, and end it either by pressing 'Return' on your keyboard\nor clicking on the first node drawn to close the shape.\n\n### Deleting\n\nIf a building is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the building could simply be newly built.\n\nYou can delete a building by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n","relations":"# Relations\n\nA relation is a special type of feature in OpenStreetMap that groups together\nother features. For example, two common types of relations are *route relations*,\nwhich group together sections of road that belong to a specific freeway or\nhighway, and *multipolygons*, which group together several lines that define\na complex area (one with several pieces or holes in it like a donut).\n\nThe group of features in a relation are called *members*. In the sidebar, you can\nsee which relations a feature is a member of, and click on a relation there\nto select the it. When the relation is selected, you can see all of its\nmembers listed in the sidebar and highlighted on the map.\n\nFor the most part, iD will take care of maintaining relations automatically\nwhile you edit. The main thing you should be aware of is that if you delete a\nsection of road to redraw it more accurately, you should make sure that the\nnew section is a member of the same relations as the original.\n\n## Editing Relations\n\nIf you want to edit relations, here are the basics.\n\nTo add a feature to a relation, select the feature, click the \"+\" button in the\n\"All relations\" section of the sidebar, and select or type the name of the relation.\n\nTo create a new relation, select the first feature that should be a member,\nclick the \"+\" button in the \"All relations\" section, and select \"New relation...\".\n\nTo remove a feature from a relation, select the feature and click the trash\nbutton next to the relation you want to remove it from.\n\nYou can create multipolygons with holes using the \"Merge\" tool. Draw two areas (inner\nand outer), hold the Shift key and click on each of them to select them both, and then\nclick the \"Merge\" (+) button.\n"},"intro":{"graph":{"city_hall":"Three Rivers City Hall","fire_department":"Three Rivers Fire Department","memory_isle_park":"Memory Isle Park","riverwalk_trail":"Riverwalk Trail","w_michigan_ave":"West Michigan Avenue","e_michigan_ave":"East Michigan Avenue","spring_st":"Spring Street","scidmore_park":"Scidmore Park","petting_zoo":"Scidmore Park Petting Zoo","n_andrews_st":"North Andrews Street","s_andrews_st":"South Andrews Street","n_constantine_st":"North Constantine Street","s_constantine_st":"South Constantine Street","rocky_river":"Rocky River","railroad_dr":"Railroad Drive","conrail_rr":"Conrail Railroad","st_joseph_river":"Saint Joseph River","n_main_st":"North Main Street","s_main_st":"South Main Street","water_st":"Water Street","foster_st":"Foster Street","portage_river":"Portage River","flower_st":"Flower Street","elm_st":"Elm Street","walnut_st":"Walnut Street","morris_ave":"Morris Avenue","east_st":"East Street","portage_ave":"Portage Avenue"},"navigation":{"title":"Navigation","drag":"The main map area shows OpenStreetMap data on top of a background. You can navigate by dragging and scrolling, just like any web map. **Drag the map!**","select":"Map features are represented three ways: using points, lines or areas. All features can be selected by clicking on them. **Click on the point to select it.**","pane":"When a feature is selected, the feature editor is displayed. The header shows us the feature type and the main pane shows the feature's attributes, such as its name and address. **Close the feature editor by pressing the {button} button in the top right.**","search":"You can also search for features in the current view, or worldwide. **Search for '{name}'**","choose":"**Choose {name} from the list to select it.**","chosen":"Great! {name} is now selected. **Close the feature editor by pressing the {button} button.**"},"points":{"title":"Points","add":"Points can be used to represent features such as shops, restaurants, and monuments. They mark a specific location, and describe what's there. **Click the {button} Point button to add a new point.**","place":"The point can be placed by clicking on the map. **Click the map to place the new point on top of the building.**","search":"There are many different features that can be represented by points. The point you just added is a Cafe. **Search for '{name}'**","choose":"**Choose Cafe from the list.**","describe":"The point is now marked as a cafe. Using the feature editor, we can add more information about the feature. **Add a name**","close":"The feature editor will remember all of your changes automatically. When you change a feature, the close button will change to a checkmark. **Click the {button} button to close the feature editor**","reselect":"Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Click to select the point you just created.**","fixname":"**Change the name, then click the {button} button to close the feature editor.**","reselect_delete":"All features on the map can be deleted. **Click to select the point you created.**","delete":"The menu around the point contains operations that can be performed on it, including delete. **Click on the {button} button to delete the point.**"},"areas":{"title":"Areas","add":"Areas are used to show the boundaries of features like lakes, buildings, and residential areas. They can be also be used for more detailed mapping of many features you might normally map as points. **Click the {button} Area button to add a new area.**","corner":"Areas are drawn by placing nodes that mark the boundary of the area. **Click to place a starting node on one of the corners of the playground.**","place":"Draw the area by placing more nodes. Finish the area by clicking on the starting node. **Draw an area for the playground.**","search":"**Search for '{name}'.**","choose":"**Choose Playground from the list.**","describe":"**Add a name, then click the {button} button to close the feature editor**"},"lines":{"title":"Lines","add":"Lines are used to represent features such as roads, railroads, and rivers. **Click the {button} Line button to add a new line.**","start":"**Start the line by clicking on the end of the road.**","intersect":"Click to add more nodes to the line. You can drag the map while drawing if necessary. Roads, and many other types of lines, are part of a larger network. It is important for these lines to be connected properly in order for routing applications to work. **Click on {name} to create an intersection connecting the two lines.**","finish":"Lines can be finished by clicking on the last node again. **Finish drawing the road.**","road":"**Select Road from the list**","residential":"There are different types of roads, the most common of which is Residential. **Choose the Residential road type**","describe":"**Name the road, then click the {button} button to close the feature editor.**","restart":"The road needs to intersect {name}.","wrong_preset":"You didn't select the Residential road type. **Click here to choose again**"},"startediting":{"title":"Start Editing","help":"You can replay this walkthrough or view more documentation by clicking the {button} Help button.","save":"Don't forget to regularly save your changes!","start":"Start mapping!"}},"presets":{"categories":{"category-building":{"name":"Building Features"},"category-golf":{"name":"Golf Features"},"category-landuse":{"name":"Land Use Features"},"category-path":{"name":"Path Features"},"category-rail":{"name":"Rail Features"},"category-restriction":{"name":"Restriction Features"},"category-road":{"name":"Road Features"},"category-route":{"name":"Route Features"},"category-water-area":{"name":"Water Features"},"category-water-line":{"name":"Water Features"}},"fields":{"access":{"label":"Allowed Access","placeholder":"Not Specified","types":{"access":"All","foot":"Foot","motor_vehicle":"Motor Vehicles","bicycle":"Bicycles","horse":"Horses"},"options":{"yes":{"title":"Allowed","description":"Access permitted by law; a right of way"},"no":{"title":"Prohibited","description":"Access not permitted to the general public"},"permissive":{"title":"Permissive","description":"Access permitted until such time as the owner revokes the permission"},"private":{"title":"Private","description":"Access permitted only with permission of the owner on an individual basis"},"designated":{"title":"Designated","description":"Access permitted according to signs or specific local laws"},"destination":{"title":"Destination","description":"Access permitted only to reach a destination"},"dismount":{"title":"Dismount","description":"Access permitted but rider must dismount"}}},"access_simple":{"label":"Allowed Access","placeholder":"yes"},"access_toilets":{"label":"Access"},"address":{"label":"Address","placeholders":{"housename":"Housename","housenumber":"123","conscriptionnumber":"123","street":"Street","city":"City","postcode":"Postcode","place":"Place","hamlet":"Hamlet","suburb":"Suburb","subdistrict":"Subdistrict","district":"District","province":"Province","state":"State","country":"Country"}},"admin_level":{"label":"Admin Level"},"aerialway":{"label":"Type"},"aerialway/access":{"label":"Access","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aerialway/bubble":{"label":"Bubble"},"aerialway/capacity":{"label":"Capacity (per hour)","placeholder":"500, 2500, 5000..."},"aerialway/duration":{"label":"Duration (minutes)","placeholder":"1, 2, 3..."},"aerialway/heating":{"label":"Heated"},"aerialway/occupancy":{"label":"Occupancy","placeholder":"2, 4, 8..."},"aerialway/summer/access":{"label":"Access (summer)","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aeroway":{"label":"Type"},"amenity":{"label":"Type"},"area/highway":{"label":"Type"},"artist":{"label":"Artist"},"artwork_type":{"label":"Type"},"atm":{"label":"ATM"},"backrest":{"label":"Backrest"},"barrier":{"label":"Type"},"bench":{"label":"Bench"},"bicycle_parking":{"label":"Type"},"boundary":{"label":"Type"},"brand":{"label":"Brand"},"building":{"label":"Building"},"building_area":{"label":"Building"},"capacity":{"label":"Capacity","placeholder":"50, 100, 200..."},"cardinal_direction":{"label":"Direction","options":{"N":"North","E":"East","S":"South","W":"West","NE":"Northeast","SE":"Southeast","SW":"Southwest","NW":"Northwest","NNE":"North-northeast","ENE":"East-northeast","ESE":"East-southeast","SSE":"South-southeast","SSW":"South-southwest","WSW":"West-southwest","WNW":"West-northwest","NNW":"North-northwest"}},"clock_direction":{"label":"Direction","options":{"clockwise":"Clockwise","anticlockwise":"Counterclockwise"}},"collection_times":{"label":"Collection Times"},"construction":{"label":"Type"},"content":{"label":"Contents"},"country":{"label":"Country"},"covered":{"label":"Covered"},"craft":{"label":"Type"},"crop":{"label":"Crop"},"crossing":{"label":"Type"},"cuisine":{"label":"Cuisine"},"cycleway":{"label":"Bike Lanes","placeholder":"none","types":{"cycleway:left":"Left side","cycleway:right":"Right side"},"options":{"none":{"title":"None","description":"No bike lane"},"lane":{"title":"Standard bike lane","description":"A bike lane separated from auto traffic by a painted line"},"shared_lane":{"title":"Shared bike lane","description":"A bike lane with no separation from auto traffic"},"track":{"title":"Bike track","description":"A bike lane separated from traffic by a physical barrier"},"share_busway":{"title":"Bike lane shared with bus","description":"A bike lane shared with a bus lane"},"opposite_lane":{"title":"Opposite bike lane","description":"A bike lane that travels in the opposite direction of traffic"},"opposite":{"title":"Contraflow bike lane","description":"A bike lane that travels in both directions on a one-way street"}}},"delivery":{"label":"Delivery"},"denomination":{"label":"Denomination"},"denotation":{"label":"Denotation"},"description":{"label":"Description"},"diaper":{"label":"Diaper Changing Available"},"dock":{"label":"Type"},"drive_through":{"label":"Drive-Through"},"electrified":{"label":"Electrification","placeholder":"Contact Line, Electrified Rail...","options":{"contact_line":"Contact Line","rail":"Electrified Rail","yes":"Yes (unspecified)","no":"No"}},"elevation":{"label":"Elevation"},"emergency":{"label":"Emergency"},"entrance":{"label":"Type"},"except":{"label":"Exceptions"},"fax":{"label":"Fax","placeholder":"+31 42 123 4567"},"fee":{"label":"Fee"},"fire_hydrant/type":{"label":"Type","options":{"pillar":"Pillar/Aboveground","underground":"Underground","wall":"Wall","pond":"Pond"}},"fixme":{"label":"Fix Me"},"fuel":{"label":"Fuel"},"fuel/biodiesel":{"label":"Sells Biodiesel"},"fuel/diesel":{"label":"Sells Diesel"},"fuel/e10":{"label":"Sells E10"},"fuel/e85":{"label":"Sells E85"},"fuel/lpg":{"label":"Sells Propane"},"fuel/octane_100":{"label":"Sells Racing Gasoline"},"fuel/octane_91":{"label":"Sells Regular Gasoline"},"fuel/octane_95":{"label":"Sells Midgrade Gasoline"},"fuel/octane_98":{"label":"Sells Premium Gasoline"},"gauge":{"label":"Gauge"},"gender":{"label":"Gender","placeholder":"Unknown","options":{"male":"Male","female":"Female","unisex":"Unisex"}},"generator/method":{"label":"Method"},"generator/source":{"label":"Source"},"generator/type":{"label":"Type"},"golf_hole":{"label":"Reference","placeholder":"Hole number (1-18)"},"handicap":{"label":"Handicap","placeholder":"1-18"},"handrail":{"label":"Handrail"},"highway":{"label":"Type"},"historic":{"label":"Type"},"hoops":{"label":"Hoops","placeholder":"1, 2, 4..."},"iata":{"label":"IATA"},"icao":{"label":"ICAO"},"incline":{"label":"Incline"},"incline_steps":{"label":"Incline","options":{"up":"Up","down":"Down"}},"information":{"label":"Type"},"internet_access":{"label":"Internet Access","options":{"yes":"Yes","no":"No","wlan":"Wifi","wired":"Wired","terminal":"Terminal"}},"lamp_type":{"label":"Type"},"landuse":{"label":"Type"},"lanes":{"label":"Lanes","placeholder":"1, 2, 3..."},"layer":{"label":"Layer"},"leaf_cycle":{"label":"Leaf Cycle","options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous","mixed":"Mixed"}},"leaf_cycle_singular":{"label":"Leaf Cycle","options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous"}},"leaf_type":{"label":"Leaf Type","options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","mixed":"Mixed","leafless":"Leafless"}},"leaf_type_singular":{"label":"Leaf Type","options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","leafless":"Leafless"}},"leisure":{"label":"Type"},"length":{"label":"Length (Meters)"},"level":{"label":"Level"},"levels":{"label":"Levels","placeholder":"2, 4, 6..."},"lit":{"label":"Lit"},"location":{"label":"Location"},"man_made":{"label":"Type"},"maxspeed":{"label":"Speed Limit","placeholder":"40, 50, 60..."},"maxstay":{"label":"Max Stay"},"mtb/scale":{"label":"Mountain Biking Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Solid gravel/packed earth, no obstacles, wide curves","1":"1: Some loose surface, small obstacles, wide curves","2":"2: Much loose surface, large obstacles, easy hairpins","3":"3: Slippery surface, large obstacles, tight hairpins","4":"4: Loose surface or boulders, dangerous hairpins","5":"5: Maximum difficulty, boulder fields, landslides","6":"6: Not rideable except by the very best mountain bikers"}},"mtb/scale/imba":{"label":"IMBA Trail Difficulty","placeholder":"Easy, Medium, Difficult...","options":{"0":"Easiest (white circle)","1":"Easy (green circle)","2":"Medium (blue square)","3":"Difficult (black diamond)","4":"Extremely Difficult (double black diamond)"}},"mtb/scale/uphill":{"label":"Mountain Biking Uphill Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Avg. incline <10%, gravel/packed earth, no obstacles","1":"1: Avg. incline <15%, gravel/packed earth, few small objects","2":"2: Avg. incline <20%, stable surface, fistsize rocks/roots","3":"3: Avg. incline <25%, variable surface, fistsize rocks/branches","4":"4: Avg. incline <30%, poor condition, big rocks/branches","5":"5: Very steep, bike generally needs to be pushed or carried"}},"name":{"label":"Name","placeholder":"Common name (if any)"},"natural":{"label":"Natural"},"network":{"label":"Network"},"note":{"label":"Note"},"office":{"label":"Type"},"oneway":{"label":"One Way","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"oneway_yes":{"label":"One Way","options":{"undefined":"Assumed to be Yes","yes":"Yes","no":"No"}},"opening_hours":{"label":"Hours"},"operator":{"label":"Operator"},"par":{"label":"Par","placeholder":"3, 4, 5..."},"park_ride":{"label":"Park and Ride"},"parking":{"label":"Type","options":{"surface":"Surface","multi-storey":"Multilevel","underground":"Underground","sheds":"Sheds","carports":"Carports","garage_boxes":"Garage Boxes","lane":"Roadside Lane"}},"phone":{"label":"Phone","placeholder":"+31 42 123 4567"},"piste/difficulty":{"label":"Difficulty","placeholder":"Easy, Intermediate, Advanced...","options":{"novice":"Novice (instructional)","easy":"Easy (green circle)","intermediate":"Intermediate (blue square)","advanced":"Advanced (black diamond)","expert":"Expert (double black diamond)","freeride":"Freeride (off-piste)","extreme":"Extreme (climbing equipment required)"}},"piste/grooming":{"label":"Grooming","options":{"classic":"Classic","mogul":"Mogul","backcountry":"Backcountry","classic+skating":"Classic and Skating","scooter":"Scooter/Snowmobile","skating":"Skating"}},"piste/type":{"label":"Type","options":{"downhill":"Downhill","nordic":"Nordic","skitour":"Skitour","sled":"Sled","hike":"Hike","sleigh":"Sleigh","ice_skate":"Ice Skate","snow_park":"Snow Park","playground":"Playground"}},"place":{"label":"Type"},"population":{"label":"Population"},"power":{"label":"Type"},"power_supply":{"label":"Power Supply"},"railway":{"label":"Type"},"recycling/cans":{"label":"Accepts Cans"},"recycling/clothes":{"label":"Accepts Clothes"},"recycling/glass":{"label":"Accepts Glass"},"recycling/glass_bottles":{"label":"Accepts Glass Bottles"},"recycling/paper":{"label":"Accepts Paper"},"recycling/plastic":{"label":"Accepts Plastic"},"recycling/type":{"label":"Recycling Type","options":{"container":"Container","centre":"Recycling Center"}},"ref":{"label":"Reference"},"relation":{"label":"Type"},"religion":{"label":"Religion"},"restriction":{"label":"Type"},"restrictions":{"label":"Turn Restrictions"},"route":{"label":"Type"},"route_master":{"label":"Type"},"sac_scale":{"label":"Hiking Difficulty","placeholder":"Mountain Hiking, Alpine Hiking...","options":{"hiking":"T1: Hiking","mountain_hiking":"T2: Mountain Hiking","demanding_mountain_hiking":"T3: Demanding Mountain Hiking","alpine_hiking":"T4: Alpine Hiking","demanding_alpine_hiking":"T5: Demanding Alpine Hiking","difficult_alpine_hiking":"T6: Difficult Alpine Hiking"}},"sanitary_dump_station":{"label":"Toilet Disposal"},"seasonal":{"label":"Seasonal"},"service":{"label":"Type"},"service/bicycle/chain_tool":{"label":"Chain Tool","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"service/bicycle/pump":{"label":"Air Pump","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"service_rail":{"label":"Service Type","options":{"spur":"Spur","yard":"Yard","siding":"Siding","crossover":"Crossover"}},"shelter":{"label":"Shelter"},"shelter_type":{"label":"Type"},"shop":{"label":"Type"},"site":{"label":"Type"},"sloped_curb":{"label":"Sloped Curb"},"smoking":{"label":"Smoking","placeholder":"No, Separated, Yes...","options":{"no":"No smoking anywhere","separated":"In smoking areas, not physically isolated","isolated":"In smoking areas, physically isolated","outside":"Allowed outside","yes":"Allowed everywhere","dedicated":"Dedicated to smokers (e.g. smokers' club)"}},"smoothness":{"label":"Smoothness","placeholder":"Thin Rollers, Wheels, Off-Road...","options":{"excellent":"Thin Rollers: rollerblade, skateboard","good":"Thin Wheels: racing bike","intermediate":"Wheels: city bike, wheelchair, scooter","bad":"Robust Wheels: trekking bike, car, rickshaw","very_bad":"High Clearance: light duty off-road vehicle","horrible":"Off-Road: heavy duty off-road vehicle","very_horrible":"Specialized off-road: tractor, ATV","impassable":"Impassable / No wheeled vehicle"}},"social_facility_for":{"label":"People served","placeholder":"Homeless, Disabled, Child, etc"},"source":{"label":"Source"},"sport":{"label":"Sport"},"sport_ice":{"label":"Sport"},"sport_racing":{"label":"Sport"},"structure":{"label":"Structure","placeholder":"Unknown","options":{"bridge":"Bridge","tunnel":"Tunnel","embankment":"Embankment","cutting":"Cutting","ford":"Ford"}},"studio_type":{"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/pub":{"name":"Pub","terms":"dive,beer,bier,booze"},"amenity/public_bookcase":{"name":"Public Bookcase","terms":"library,bookcrossing"},"amenity/ranger_station":{"name":"Ranger Station","terms":"visitor center,visitor centre,permit center,permit centre,backcountry office,warden office,warden center"},"amenity/recycling":{"name":"Recycling","terms":"can,bottle,garbage,scrap,trash"},"amenity/register_office":{"name":"Register Office","terms":""},"amenity/restaurant":{"name":"Restaurant","terms":"bar,breakfast,cafe,café,canteen,coffee,dine,dining,dinner,drive-in,eat,grill,lunch,table"},"amenity/sanitary_dump_station":{"name":"RV Toilet Disposal","terms":"Motor Home,Camper,Sanitary,Dump Station,Elsan,CDP,CTDP,Chemical Toilet"},"amenity/school":{"name":"School Grounds","terms":"academy,elementary school,middle school,high school"},"amenity/shelter":{"name":"Shelter","terms":"lean-to,gazebo,picnic"},"amenity/social_facility":{"name":"Social Facility","terms":""},"amenity/social_facility/food_bank":{"name":"Food Bank","terms":""},"amenity/social_facility/group_home":{"name":"Elderly Group Home","terms":"old,senior,living"},"amenity/social_facility/homeless_shelter":{"name":"Homeless Shelter","terms":"houseless,unhoused,displaced"},"amenity/studio":{"name":"Studio","terms":"recording,radio,television"},"amenity/swimming_pool":{"name":"Swimming Pool","terms":""},"amenity/taxi":{"name":"Taxi Stand","terms":"cab"},"amenity/telephone":{"name":"Telephone","terms":"phone"},"amenity/theatre":{"name":"Theater","terms":"theatre,performance,play,musical"},"amenity/toilets":{"name":"Toilets","terms":"bathroom,restroom,outhouse,privy,head,lavatory,latrine,water closet,WC,W.C."},"amenity/townhall":{"name":"Town Hall","terms":"village,city,government,courthouse,municipal"},"amenity/university":{"name":"University Grounds","terms":"college"},"amenity/vending_machine/cigarettes":{"name":"Cigarette Vending Machine","terms":"cigarette"},"amenity/vending_machine/condoms":{"name":"Condom Vending Machine","terms":"condom"},"amenity/vending_machine/drinks":{"name":"Drink Vending Machine","terms":"drink,soda,beverage,juice,pop"},"amenity/vending_machine/excrement_bags":{"name":"Excrement Bag Vending Machine","terms":"excrement bags,poop,dog,animal"},"amenity/vending_machine/news_papers":{"name":"Newspaper Vending Machine","terms":"newspaper"},"amenity/vending_machine/parcel_pickup_dropoff":{"name":"Parcel Pickup/Dropoff Vending Machine","terms":"parcel,mail,pickup"},"amenity/vending_machine/parking_tickets":{"name":"Parking Ticket Vending Machine","terms":"parking,ticket"},"amenity/vending_machine/public_transport_tickets":{"name":"Transit Ticket Vending Machine","terms":"bus,train,ferry,rail,ticket,transportation"},"amenity/vending_machine/sweets":{"name":"Snack Vending Machine","terms":"candy,gum,chip,pretzel,cookie,cracker"},"amenity/vending_machine/vending_machine":{"name":"Vending Machine","terms":""},"amenity/veterinary":{"name":"Veterinary","terms":"pet clinic,veterinarian,animal hospital,pet doctor"},"amenity/waste_basket":{"name":"Waste Basket","terms":"bin,rubbish,litter,trash,garbage"},"amenity/waste_disposal":{"name":"Garbage Dumpster","terms":"rubbish,litter,trash"},"amenity/water_point":{"name":"RV Drinking Water","terms":""},"area":{"name":"Area","terms":""},"area/highway":{"name":"Road Surface","terms":""},"barrier":{"name":"Barrier","terms":""},"barrier/block":{"name":"Block","terms":""},"barrier/bollard":{"name":"Bollard","terms":""},"barrier/cattle_grid":{"name":"Cattle Grid","terms":""},"barrier/city_wall":{"name":"City Wall","terms":""},"barrier/cycle_barrier":{"name":"Cycle Barrier","terms":""},"barrier/ditch":{"name":"Ditch","terms":""},"barrier/entrance":{"name":"Entrance","terms":""},"barrier/fence":{"name":"Fence","terms":""},"barrier/gate":{"name":"Gate","terms":""},"barrier/hedge":{"name":"Hedge","terms":""},"barrier/kissing_gate":{"name":"Kissing Gate","terms":""},"barrier/lift_gate":{"name":"Lift Gate","terms":""},"barrier/retaining_wall":{"name":"Retaining Wall","terms":""},"barrier/stile":{"name":"Stile","terms":""},"barrier/toll_booth":{"name":"Toll Booth","terms":""},"barrier/wall":{"name":"Wall","terms":""},"boundary/administrative":{"name":"Administrative Boundary","terms":""},"building":{"name":"Building","terms":""},"building/apartments":{"name":"Apartments","terms":""},"building/barn":{"name":"Barn","terms":""},"building/bunker":{"name":"Bunker","terms":""},"building/cabin":{"name":"Cabin","terms":""},"building/cathedral":{"name":"Cathedral Building","terms":""},"building/chapel":{"name":"Chapel Building","terms":""},"building/church":{"name":"Church Building","terms":""},"building/college":{"name":"College Building","terms":"university"},"building/commercial":{"name":"Commercial Building","terms":""},"building/construction":{"name":"Building Under Construction","terms":""},"building/detached":{"name":"Detached House","terms":"home,single,family,residence,dwelling"},"building/dormitory":{"name":"Dormitory","terms":""},"building/entrance":{"name":"Entrance/Exit","terms":""},"building/garage":{"name":"Garage","terms":""},"building/garages":{"name":"Garages","terms":""},"building/greenhouse":{"name":"Greenhouse","terms":""},"building/hospital":{"name":"Hospital Building","terms":""},"building/hotel":{"name":"Hotel Building","terms":""},"building/house":{"name":"House","terms":"home,family,residence,dwelling"},"building/hut":{"name":"Hut","terms":""},"building/industrial":{"name":"Industrial Building","terms":""},"building/kindergarten":{"name":"Preschool/Kindergarten Building","terms":"kindergarden,pre-school"},"building/public":{"name":"Public Building","terms":""},"building/residential":{"name":"Residential Building","terms":""},"building/retail":{"name":"Retail Building","terms":""},"building/roof":{"name":"Roof","terms":""},"building/school":{"name":"School Building","terms":"academy,elementary school,middle school,high school"},"building/semidetached_house":{"name":"Semi-Detached House","terms":"home,double,duplex,twin,family,residence,dwelling"},"building/shed":{"name":"Shed","terms":""},"building/stable":{"name":"Stable","terms":""},"building/static_caravan":{"name":"Static Mobile Home","terms":""},"building/terrace":{"name":"Row Houses","terms":"home,terrace,brownstone,family,residence,dwelling"},"building/train_station":{"name":"Train Station","terms":""},"building/university":{"name":"University Building","terms":"college"},"building/warehouse":{"name":"Warehouse","terms":""},"craft":{"name":"Craft","terms":""},"craft/basket_maker":{"name":"Basket Maker","terms":""},"craft/beekeeper":{"name":"Beekeeper","terms":""},"craft/blacksmith":{"name":"Blacksmith","terms":""},"craft/boatbuilder":{"name":"Boat Builder","terms":""},"craft/bookbinder":{"name":"Bookbinder","terms":"book repair"},"craft/brewery":{"name":"Brewery","terms":"beer,bier"},"craft/carpenter":{"name":"Carpenter","terms":"woodworker"},"craft/carpet_layer":{"name":"Carpet Layer","terms":""},"craft/caterer":{"name":"Caterer","terms":""},"craft/clockmaker":{"name":"Clockmaker","terms":""},"craft/confectionery":{"name":"Confectionery","terms":"sweets,candy"},"craft/dressmaker":{"name":"Dressmaker","terms":"seamstress"},"craft/electrician":{"name":"Electrician","terms":"power,wire"},"craft/gardener":{"name":"Gardener","terms":"landscaper,grounds keeper"},"craft/glaziery":{"name":"Glaziery","terms":"glass,stained-glass,window"},"craft/handicraft":{"name":"Handicraft","terms":""},"craft/hvac":{"name":"HVAC","terms":"heat*,vent*,air conditioning"},"craft/insulator":{"name":"Insulator","terms":""},"craft/jeweler":{"name":"Jeweler","terms":""},"craft/key_cutter":{"name":"Key Cutter","terms":""},"craft/locksmith":{"name":"Locksmith","terms":""},"craft/metal_construction":{"name":"Metal Construction","terms":""},"craft/optician":{"name":"Optician","terms":""},"craft/painter":{"name":"Painter","terms":""},"craft/photographer":{"name":"Photographer","terms":""},"craft/photographic_laboratory":{"name":"Photographic Laboratory","terms":"film"},"craft/plasterer":{"name":"Plasterer","terms":""},"craft/plumber":{"name":"Plumber","terms":"pipe"},"craft/pottery":{"name":"Pottery","terms":"ceramic"},"craft/rigger":{"name":"Rigger","terms":""},"craft/roofer":{"name":"Roofer","terms":""},"craft/saddler":{"name":"Saddler","terms":""},"craft/sailmaker":{"name":"Sailmaker","terms":""},"craft/sawmill":{"name":"Sawmill","terms":"lumber"},"craft/scaffolder":{"name":"Scaffolder","terms":""},"craft/sculpter":{"name":"Sculpter","terms":""},"craft/shoemaker":{"name":"Shoemaker","terms":"cobbler"},"craft/stonemason":{"name":"Stonemason","terms":"masonry"},"craft/sweep":{"name":"Chimney Sweep","terms":""},"craft/tailor":{"name":"Tailor","terms":"clothes,suit"},"craft/tiler":{"name":"Tiler","terms":""},"craft/tinsmith":{"name":"Tinsmith","terms":""},"craft/upholsterer":{"name":"Upholsterer","terms":""},"craft/watchmaker":{"name":"Watchmaker","terms":""},"craft/window_construction":{"name":"Window Construction","terms":"glass"},"craft/winery":{"name":"Winery","terms":""},"embankment":{"name":"Embankment","terms":""},"emergency/ambulance_station":{"name":"Ambulance Station","terms":"EMS,EMT,rescue"},"emergency/fire_hydrant":{"name":"Fire Hydrant","terms":""},"emergency/phone":{"name":"Emergency Phone","terms":""},"entrance":{"name":"Entrance/Exit","terms":""},"footway/crossing":{"name":"Street Crossing","terms":""},"footway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"footway/sidewalk":{"name":"Sidewalk","terms":""},"ford":{"name":"Ford","terms":""},"golf/bunker":{"name":"Sand Trap","terms":"hazard,bunker"},"golf/fairway":{"name":"Fairway","terms":""},"golf/green":{"name":"Putting Green","terms":""},"golf/hole":{"name":"Golf Hole","terms":""},"golf/lateral_water_hazard":{"name":"Lateral Water Hazard","terms":""},"golf/rough":{"name":"Rough","terms":""},"golf/tee":{"name":"Tee Box","terms":"teeing ground"},"golf/water_hazard":{"name":"Water Hazard","terms":""},"highway":{"name":"Highway","terms":""},"highway/bridleway":{"name":"Bridle Path","terms":"bridleway,equestrian,horse"},"highway/bus_stop":{"name":"Bus Stop","terms":""},"highway/corridor":{"name":"Indoor Corridor","terms":"gallery,hall,hallway,indoor,passage,passageway"},"highway/crossing":{"name":"Street Crossing","terms":""},"highway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"highway/cycleway":{"name":"Cycle Path","terms":"bike"},"highway/footway":{"name":"Foot Path","terms":"hike,hiking,trackway,trail,walk"},"highway/living_street":{"name":"Living Street","terms":""},"highway/mini_roundabout":{"name":"Mini-Roundabout","terms":""},"highway/motorway":{"name":"Motorway","terms":""},"highway/motorway_junction":{"name":"Motorway Junction / Exit","terms":""},"highway/motorway_link":{"name":"Motorway Link","terms":"ramp,on ramp,off ramp"},"highway/path":{"name":"Path","terms":"hike,hiking,trackway,trail,walk"},"highway/pedestrian":{"name":"Pedestrian Street","terms":""},"highway/primary":{"name":"Primary Road","terms":""},"highway/primary_link":{"name":"Primary Link","terms":"ramp,on ramp,off ramp"},"highway/raceway":{"name":"Motor Raceway","terms":"auto*,race*,nascar"},"highway/residential":{"name":"Residential Road","terms":""},"highway/rest_area":{"name":"Rest Area","terms":"rest stop"},"highway/road":{"name":"Unknown Road","terms":""},"highway/secondary":{"name":"Secondary Road","terms":""},"highway/secondary_link":{"name":"Secondary Link","terms":"ramp,on ramp,off ramp"},"highway/service":{"name":"Service Road","terms":""},"highway/service/alley":{"name":"Alley","terms":""},"highway/service/drive-through":{"name":"Drive-Through","terms":""},"highway/service/driveway":{"name":"Driveway","terms":""},"highway/service/emergency_access":{"name":"Emergency Access","terms":""},"highway/service/parking_aisle":{"name":"Parking Aisle","terms":""},"highway/services":{"name":"Service Area","terms":"services,travel plaza,service station"},"highway/steps":{"name":"Steps","terms":"stairs,staircase"},"highway/stop":{"name":"Stop Sign","terms":"stop sign"},"highway/street_lamp":{"name":"Street Lamp","terms":"streetlight,street light,lamp,light,gaslight"},"highway/tertiary":{"name":"Tertiary Road","terms":""},"highway/tertiary_link":{"name":"Tertiary Link","terms":"ramp,on ramp,off ramp"},"highway/track":{"name":"Unmaintained Track Road","terms":"woods road,forest road,logging road,fire road,farm road,agricultural road,ranch road,carriage road,primitive,unmaintained,rut,offroad,4wd,4x4,four wheel drive,atv,quad,jeep,double track,two track"},"highway/traffic_signals":{"name":"Traffic Signals","terms":"light,stoplight,traffic light"},"highway/trunk":{"name":"Trunk Road","terms":""},"highway/trunk_link":{"name":"Trunk Link","terms":"ramp,on ramp,off ramp"},"highway/turning_circle":{"name":"Turning Circle","terms":"cul-de-sac"},"highway/unclassified":{"name":"Minor 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/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":""},"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/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/optician":{"name":"Optician","terms":"eye,glasses"},"shop/organic":{"name":"Organic Goods Store","terms":""},"shop/outdoor":{"name":"Outdoors Store","terms":"camping,climbing,hiking"},"shop/paint":{"name":"Paint Store","terms":""},"shop/pawnbroker":{"name":"Pawn Shop","terms":""},"shop/pet":{"name":"Pet Store","terms":"cat,dog,fish"},"shop/photo":{"name":"Photography Store","terms":"camera,film"},"shop/pyrotechnics":{"name":"Fireworks Store","terms":""},"shop/radiotechnics":{"name":"Radio/Electronic Component Store","terms":""},"shop/religion":{"name":"Religious Store","terms":""},"shop/scuba_diving":{"name":"Scuba Diving Shop","terms":""},"shop/seafood":{"name":"Seafood Shop","terms":"fishmonger"},"shop/second_hand":{"name":"Consignment/Thrift Store","terms":"secondhand,second hand,resale,thrift,used"},"shop/shoes":{"name":"Shoe Store","terms":""},"shop/sports":{"name":"Sporting Goods Store","terms":""},"shop/stationery":{"name":"Stationery Store","terms":"card,paper"},"shop/storage_rental":{"name":"Storage Rental","terms":""},"shop/supermarket":{"name":"Supermarket","terms":"grocery,store,shop"},"shop/tailor":{"name":"Tailor","terms":"clothes,suit"},"shop/tattoo":{"name":"Tattoo Parlor","terms":""},"shop/tea":{"name":"Tea Store","terms":""},"shop/ticket":{"name":"Ticket Seller","terms":""},"shop/tobacco":{"name":"Tobacco Shop","terms":""},"shop/toys":{"name":"Toy Store","terms":""},"shop/travel_agency":{"name":"Travel Agency","terms":""},"shop/tyres":{"name":"Tire Store","terms":""},"shop/vacant":{"name":"Vacant Shop","terms":""},"shop/vacuum_cleaner":{"name":"Vacuum Cleaner Store","terms":""},"shop/variety_store":{"name":"Variety Store","terms":""},"shop/video":{"name":"Video Store","terms":"DVD"},"shop/video_games":{"name":"Video Game Store","terms":""},"shop/water_sports":{"name":"Watersport/Swim Shop","terms":""},"shop/weapons":{"name":"Weapon Shop","terms":"ammo,gun,knife,knives"},"shop/window_blind":{"name":"Window Blind Store","terms":""},"shop/wine":{"name":"Wine Shop","terms":""},"tourism":{"name":"Tourism","terms":""},"tourism/alpine_hut":{"name":"Alpine Hut","terms":""},"tourism/artwork":{"name":"Artwork","terms":"mural,sculpture,statue"},"tourism/attraction":{"name":"Tourist Attraction","terms":""},"tourism/camp_site":{"name":"Camp Site","terms":"Tent"},"tourism/caravan_site":{"name":"RV Park","terms":"Motor Home,Camper"},"tourism/chalet":{"name":"Chalet","terms":""},"tourism/gallery":{"name":"Art Gallery","terms":"art*,exhibit*,paint*,photo*,sculpt*"},"tourism/guest_house":{"name":"Guest House","terms":"B&B,Bed and Breakfast"},"tourism/hostel":{"name":"Hostel","terms":""},"tourism/hotel":{"name":"Hotel","terms":""},"tourism/information":{"name":"Information","terms":""},"tourism/motel":{"name":"Motel","terms":""},"tourism/museum":{"name":"Museum","terms":"art*,exhibit*,gallery,foundation,hall,institution,paint*,photo*,sculpt*"},"tourism/picnic_site":{"name":"Picnic Site","terms":"camp"},"tourism/theme_park":{"name":"Theme Park","terms":""},"tourism/viewpoint":{"name":"Viewpoint","terms":""},"tourism/zoo":{"name":"Zoo","terms":""},"traffic_calming/bump":{"name":"Speed Bump","terms":"speed hump"},"traffic_calming/hump":{"name":"Speed Hump","terms":"speed bump"},"traffic_calming/rumble_strip":{"name":"Rumble Strip","terms":"sleeper lines,audible lines,growlers"},"traffic_calming/table":{"name":"Raised Pedestrian Crossing","terms":"speed table,flat top hump"},"type/boundary":{"name":"Boundary","terms":""},"type/boundary/administrative":{"name":"Administrative Boundary","terms":""},"type/multipolygon":{"name":"Multipolygon","terms":""},"type/restriction":{"name":"Restriction","terms":""},"type/restriction/no_left_turn":{"name":"No Left Turn","terms":""},"type/restriction/no_right_turn":{"name":"No Right Turn","terms":""},"type/restriction/no_straight_on":{"name":"No Straight On","terms":""},"type/restriction/no_u_turn":{"name":"No U-turn","terms":""},"type/restriction/only_left_turn":{"name":"Left Turn Only","terms":""},"type/restriction/only_right_turn":{"name":"Right Turn Only","terms":""},"type/restriction/only_straight_on":{"name":"No Turns","terms":""},"type/route":{"name":"Route","terms":""},"type/route/bicycle":{"name":"Cycle Route","terms":""},"type/route/bus":{"name":"Bus Route","terms":""},"type/route/detour":{"name":"Detour Route","terms":""},"type/route/ferry":{"name":"Ferry Route","terms":""},"type/route/foot":{"name":"Foot Route","terms":""},"type/route/hiking":{"name":"Hiking Route","terms":""},"type/route/pipeline":{"name":"Pipeline Route","terms":""},"type/route/power":{"name":"Power Route","terms":""},"type/route/road":{"name":"Road Route","terms":""},"type/route/train":{"name":"Train Route","terms":""},"type/route/tram":{"name":"Tram Route","terms":""},"type/route_master":{"name":"Route Master","terms":""},"type/site":{"name":"Site","terms":""},"vertex":{"name":"Other","terms":""},"waterway":{"name":"Waterway","terms":""},"waterway/boatyard":{"name":"Boatyard","terms":""},"waterway/canal":{"name":"Canal","terms":""},"waterway/dam":{"name":"Dam","terms":""},"waterway/ditch":{"name":"Ditch","terms":""},"waterway/dock":{"name":"Dock","terms":""},"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"]]}]};