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 */
19038 /* Straight accessors. Avoid using these if you can. */
19039 var ui, connection, history;
19040 context.ui = function() { return ui; };
19041 context.connection = function() { return connection; };
19042 context.history = function() { return history; };
19046 function entitiesLoaded(err, result) {
19047 if (!err) history.merge(result.data, result.extent);
19050 context.preauth = function(options) {
19051 connection.switch(options);
19055 context.loadTiles = function(projection, dimensions, callback) {
19056 function done(err, result) {
19057 entitiesLoaded(err, result);
19058 if (callback) callback(err, result);
19060 connection.loadTiles(projection, dimensions, done);
19063 context.loadEntity = function(id, callback) {
19064 function done(err, result) {
19065 entitiesLoaded(err, result);
19066 if (callback) callback(err, result);
19068 connection.loadEntity(id, done);
19071 context.zoomToEntity = function(id, zoomTo) {
19072 if (zoomTo !== false) {
19073 this.loadEntity(id, function(err, result) {
19075 var entity = _.find(result.data, function(e) { return e.id === id; });
19076 if (entity) { map.zoomTo(entity); }
19080 map.on('drawn.zoomToEntity', function() {
19081 if (!context.hasEntity(id)) return;
19082 map.on('drawn.zoomToEntity', null);
19083 context.on('enter.zoomToEntity', null);
19084 context.enter(iD.modes.Select(context, [id]));
19087 context.on('enter.zoomToEntity', function() {
19088 if (mode.id !== 'browse') {
19089 map.on('drawn.zoomToEntity', null);
19090 context.on('enter.zoomToEntity', null);
19095 var minEditableZoom = 16;
19096 context.minEditableZoom = function(_) {
19097 if (!arguments.length) return minEditableZoom;
19098 minEditableZoom = _;
19099 connection.tileZoom(_);
19105 var inIntro = false;
19106 context.inIntro = function(_) {
19107 if (!arguments.length) return inIntro;
19112 context.save = function() {
19113 if (inIntro || (mode && mode.id === 'save')) return;
19115 if (history.hasChanges()) return t('save.unsaved_changes');
19118 context.flush = function() {
19119 context.debouncedSave.cancel();
19120 connection.flush();
19123 _.each(iD.services, function(service) {
19124 var reset = service().reset;
19125 if (reset) reset(context);
19132 context.hasEntity = function(id) {
19133 return history.graph().hasEntity(id);
19135 context.entity = function(id) {
19136 return history.graph().entity(id);
19138 context.childNodes = function(way) {
19139 return history.graph().childNodes(way);
19141 context.geometry = function(id) {
19142 return context.entity(id).geometry(history.graph());
19148 context.mode = function() {
19151 context.enter = function(newMode) {
19154 dispatch.exit(mode);
19159 dispatch.enter(mode);
19162 context.selectedIDs = function() {
19163 if (mode && mode.selectedIDs) {
19164 return mode.selectedIDs();
19172 context.install = function(behavior) {
19173 context.surface().call(behavior);
19175 context.uninstall = function(behavior) {
19176 context.surface().call(behavior.off);
19181 var copyIDs = [], copyGraph;
19182 context.copyGraph = function() { return copyGraph; };
19183 context.copyIDs = function(_) {
19184 if (!arguments.length) return copyIDs;
19186 copyGraph = history.graph();
19193 context.background = function() { return background; };
19198 context.features = function() { return features; };
19199 context.hasHiddenConnections = function(id) {
19200 var graph = history.graph(),
19201 entity = graph.entity(id);
19202 return features.hasHiddenConnections(entity, graph);
19208 context.map = function() { return map; };
19209 context.layers = function() { return map.layers; };
19210 context.surface = function() { return map.surface; };
19211 context.editable = function() { return map.editable(); };
19213 context.surfaceRect = function() {
19214 // Work around a bug in Firefox.
19215 // http://stackoverflow.com/questions/18153989/
19216 // https://bugzilla.mozilla.org/show_bug.cgi?id=530985
19217 return context.surface().node().parentNode.getBoundingClientRect();
19223 context.presets = function(_) {
19224 if (!arguments.length) return presets;
19226 iD.areaKeys = presets.areaKeys();
19232 context.imagery = function(_) {
19233 background.load(_);
19239 var container, embed;
19240 context.container = function(_) {
19241 if (!arguments.length) return container;
19243 container.classed('id-container', true);
19246 context.embed = function(_) {
19247 if (!arguments.length) return embed;
19255 context.taginfo = function(_) {
19256 if (!arguments.length) return taginfo;
19263 var assetPath = '';
19264 context.assetPath = function(_) {
19265 if (!arguments.length) return assetPath;
19271 context.assetMap = function(_) {
19272 if (!arguments.length) return assetMap;
19277 context.asset = function(_) {
19278 var filename = assetPath + _;
19279 return assetMap[filename] || filename;
19282 context.imagePath = function(_) {
19283 return context.asset('img/' + _);
19286 var locale, localePath;
19287 context.locale = function(loc, path) {
19291 // Also set iD.detect().locale (unless we detected 'en-us' and openstreetmap wants 'en')..
19292 if (!(loc.toLowerCase() === 'en' && iD.detect().locale.toLowerCase() === 'en-us')) {
19293 iD.detect().locale = loc;
19299 context.loadLocale = function(cb) {
19300 if (locale && locale !== 'en' && iD.data.locales.indexOf(locale) !== -1) {
19301 localePath = localePath || context.asset('locales/' + locale + '.json');
19302 d3.json(localePath, function(err, result) {
19303 window.locale[locale] = result;
19304 window.locale.current(locale);
19315 context.projection = iD.geo.RawMercator();
19317 locale = iD.detect().locale;
19318 if (locale && iD.data.locales.indexOf(locale) === -1) {
19319 locale = locale.split('-')[0];
19322 history = iD.History(context);
19323 context.graph = history.graph;
19324 context.changes = history.changes;
19325 context.intersects = history.intersects;
19327 // Debounce save, since it's a synchronous localStorage write,
19328 // and history changes can happen frequently (e.g. when dragging).
19329 context.debouncedSave = _.debounce(context.save, 350);
19330 function withDebouncedSave(fn) {
19331 return function() {
19332 var result = fn.apply(history, arguments);
19333 context.debouncedSave();
19338 context.perform = withDebouncedSave(history.perform);
19339 context.replace = withDebouncedSave(history.replace);
19340 context.pop = withDebouncedSave(history.pop);
19341 context.overwrite = withDebouncedSave(history.overwrite);
19342 context.undo = withDebouncedSave(history.undo);
19343 context.redo = withDebouncedSave(history.redo);
19345 ui = iD.ui(context);
19347 connection = iD.Connection();
19349 background = iD.Background(context);
19351 features = iD.Features(context);
19353 map = iD.Map(context);
19354 context.mouse = map.mouse;
19355 context.extent = map.extent;
19356 context.pan = map.pan;
19357 context.zoomIn = map.zoomIn;
19358 context.zoomOut = map.zoomOut;
19359 context.zoomInFurther = map.zoomInFurther;
19360 context.zoomOutFurther = map.zoomOutFurther;
19361 context.redrawEnable = map.redrawEnable;
19363 presets = iD.presets();
19365 return d3.rebind(context, dispatch, 'on');
19369 iD.version = '1.9.1';
19374 var ua = navigator.userAgent,
19377 m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
19379 detected.browser = m[1];
19380 detected.version = m[2];
19382 if (!detected.browser) {
19383 m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
19385 detected.browser = 'msie';
19386 detected.version = m[1];
19389 if (!detected.browser) {
19390 m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
19392 detected.browser = 'Opera';
19393 detected.version = m[2];
19396 if (!detected.browser) {
19397 m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
19399 detected.browser = m[1];
19400 detected.version = m[2];
19401 m = ua.match(/version\/([\.\d]+)/i);
19402 if (m !== null) detected.version = m[1];
19405 if (!detected.browser) {
19406 detected.browser = navigator.appName;
19407 detected.version = navigator.appVersion;
19410 // keep major.minor version only..
19411 detected.version = detected.version.split(/\W/).slice(0,2).join('.');
19413 if (detected.browser.toLowerCase() === 'msie') {
19414 detected.ie = true;
19415 detected.browser = 'Internet Explorer';
19416 detected.support = parseFloat(detected.version) >= 11;
19418 detected.ie = false;
19419 detected.support = true;
19422 // Added due to incomplete svg style support. See #715
19423 detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 );
19425 detected.locale = (navigator.languages && navigator.languages.length)
19426 ? navigator.languages[0] : (navigator.language || navigator.userLanguage || 'en-US');
19428 detected.filedrop = (window.FileReader && 'ondrop' in window);
19431 return navigator.userAgent.indexOf(x) !== -1;
19435 detected.os = 'win';
19436 detected.platform = 'Windows';
19438 else if (nav('Mac')) {
19439 detected.os = 'mac';
19440 detected.platform = 'Macintosh';
19442 else if (nav('X11') || nav('Linux')) {
19443 detected.os = 'linux';
19444 detected.platform = 'Linux';
19447 detected.os = 'win';
19448 detected.platform = 'Unknown';
19451 iD.detect = function() { return detected; };
19454 iD.services.mapillary = function() {
19455 var mapillary = {},
19456 dispatch = d3.dispatch('loadedImages', 'loadedSigns'),
19457 apibase = 'https://a.mapillary.com/v2/',
19458 urlImage = 'https://www.mapillary.com/map/im/',
19459 urlThumb = 'https://d1cuyjsrcm0gby.cloudfront.net/',
19460 clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi',
19465 function loadSignStyles(context) {
19466 d3.select('head').selectAll('#traffico')
19470 .attr('id', 'traffico')
19471 .attr('rel', 'stylesheet')
19472 .attr('href', context.asset('traffico/stylesheets/traffico.css'));
19475 function loadSignDefs(context) {
19476 if (!iD.services.mapillary.sign_defs) {
19477 iD.services.mapillary.sign_defs = {};
19478 _.each(['au', 'br', 'ca', 'de', 'us'], function(region) {
19479 d3.json(context.asset('traffico/string-maps/' + region + '-map.json'), function(err, data) {
19481 if (region === 'de') region = 'eu';
19482 iD.services.mapillary.sign_defs[region] = data;
19488 function abortRequest(i) {
19492 function getTiles(projection, dimensions) {
19493 var s = projection.scale() * 2 * Math.PI,
19494 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
19495 ts = 256 * Math.pow(2, z - tileZoom),
19497 s / 2 - projection.translate()[0],
19498 s / 2 - projection.translate()[1]];
19500 return d3.geo.tile()
19501 .scaleExtent([tileZoom, tileZoom])
19504 .translate(projection.translate())()
19505 .map(function(tile) {
19506 var x = tile[0] * ts - origin[0],
19507 y = tile[1] * ts - origin[1];
19510 id: tile.toString(),
19511 extent: iD.geo.Extent(
19512 projection.invert([x, y + ts]),
19513 projection.invert([x + ts, y]))
19519 function loadTiles(which, url, projection, dimensions) {
19520 var tiles = getTiles(projection, dimensions);
19522 _.filter(which.inflight, function(v, k) {
19523 var wanted = _.find(tiles, function(tile) { return k === (tile.id + ',0'); });
19524 if (!wanted) delete which.inflight[k];
19526 }).map(abortRequest);
19528 tiles.forEach(function(tile) {
19529 loadTilePage(which, url, tile, 0);
19533 function loadTilePage(which, url, tile, page) {
19534 var cache = iD.services.mapillary.cache[which],
19535 id = tile.id + ',' + String(page),
19536 rect = tile.extent.rectangle();
19538 if (cache.loaded[id] || cache.inflight[id]) return;
19540 cache.inflight[id] = d3.json(url +
19545 client_id: clientId,
19550 }), function(err, data) {
19551 cache.loaded[id] = true;
19552 delete cache.inflight[id];
19553 if (err || !data.features || !data.features.length) return;
19558 for (var i = 0; i < data.features.length; i++) {
19559 feature = data.features[i];
19560 loc = feature.geometry.coordinates;
19561 d = { key: feature.properties.key, loc: loc };
19562 if (which === 'images') d.ca = feature.properties.ca;
19563 if (which === 'signs') d.signs = feature.properties.rects;
19565 features.push([loc[0], loc[1], loc[0], loc[1], d]);
19568 cache.rtree.load(features);
19570 if (which === 'images') dispatch.loadedImages();
19571 if (which === 'signs') dispatch.loadedSigns();
19573 if (data.features.length === maxResults) {
19574 loadTilePage(which, url, tile, ++page);
19580 mapillary.loadImages = function(projection, dimensions) {
19581 var url = apibase + 'search/im/geojson?';
19582 loadTiles('images', url, projection, dimensions);
19585 mapillary.loadSigns = function(context, projection, dimensions) {
19586 var url = apibase + 'search/im/geojson/or?';
19587 loadSignStyles(context);
19588 loadSignDefs(context);
19589 loadTiles('signs', url, projection, dimensions);
19593 // partition viewport into `psize` x `psize` regions
19594 function partitionViewport(psize, projection, dimensions) {
19595 psize = psize || 16;
19596 var cols = d3.range(0, dimensions[0], psize),
19597 rows = d3.range(0, dimensions[1], psize),
19600 rows.forEach(function(y) {
19601 cols.forEach(function(x) {
19602 var min = [x, y + psize],
19603 max = [x + psize, y];
19605 iD.geo.Extent(projection.invert(min), projection.invert(max)));
19612 // no more than `limit` results per partition.
19613 function searchLimited(psize, limit, projection, dimensions, rtree) {
19614 limit = limit || 3;
19616 var partitions = partitionViewport(psize, projection, dimensions);
19617 return _.flatten(_.compact(_.map(partitions, function(extent) {
19618 return rtree.search(extent.rectangle())
19620 .map(function(d) { return d[4]; });
19624 mapillary.images = function(projection, dimensions) {
19625 var psize = 16, limit = 3;
19626 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.images.rtree);
19629 mapillary.signs = function(projection, dimensions) {
19630 var psize = 32, limit = 3;
19631 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.signs.rtree);
19634 mapillary.signsSupported = function() {
19635 var detected = iD.detect();
19636 return (!(detected.ie || detected.browser.toLowerCase() === 'safari'));
19639 mapillary.signHTML = function(d) {
19640 if (!iD.services.mapillary.sign_defs) return;
19642 var detectionPackage = d.signs[0].package,
19643 type = d.signs[0].type,
19644 country = detectionPackage.split('_')[1];
19645 return iD.services.mapillary.sign_defs[country][type];
19648 mapillary.showThumbnail = function(imageKey, position) {
19649 if (!imageKey) return;
19651 var positionClass = {
19652 'ar': (position !== 'left'),
19653 'al': (position === 'left')
19656 var thumbnail = d3.select('#content').selectAll('.mapillary-image')
19660 var enter = thumbnail.enter().append('div')
19661 .attr('class', 'mapillary-image ar');
19663 enter.append('button')
19664 .on('click', function () {
19665 mapillary.hideThumbnail();
19668 .call(iD.svg.Icon('#icon-close'));
19670 enter.append('img');
19673 .attr('class', 'link ar')
19674 .attr('target', '_blank')
19675 .call(iD.svg.Icon('#icon-out-link', 'inline'))
19677 .text(t('mapillary.view_on_mapillary'));
19680 thumbnail.selectAll('img')
19681 .attr('src', urlThumb + imageKey + '/thumb-320.jpg');
19683 var link = thumbnail.selectAll('a')
19684 .attr('href', urlImage + imageKey);
19687 thumbnail.classed(positionClass);
19688 link.classed(positionClass);
19694 .style('opacity', 1);
19697 mapillary.hideThumbnail = function() {
19698 if (iD.services.mapillary) {
19699 iD.services.mapillary.thumb = null;
19701 d3.select('#content').selectAll('.mapillary-image')
19704 .style('opacity', 0)
19708 mapillary.selectedThumbnail = function(d) {
19709 if (!iD.services.mapillary) return null;
19710 if (!arguments.length) return iD.services.mapillary.thumb;
19711 iD.services.mapillary.thumb = d;
19714 mapillary.reset = function() {
19715 var cache = iD.services.mapillary.cache;
19718 _.forEach(cache.images.inflight, abortRequest);
19719 _.forEach(cache.signs.inflight, abortRequest);
19722 iD.services.mapillary.cache = {
19723 images: { inflight: {}, loaded: {}, rtree: rbush() },
19724 signs: { inflight: {}, loaded: {}, rtree: rbush() }
19727 iD.services.mapillary.thumb = null;
19733 if (!iD.services.mapillary.cache) {
19737 return d3.rebind(mapillary, dispatch, 'on');
19739 iD.services.nominatim = function() {
19740 var nominatim = {},
19741 endpoint = 'https://nominatim.openstreetmap.org/reverse?';
19744 nominatim.countryCode = function(location, callback) {
19745 var cache = iD.services.nominatim.cache,
19746 countryCodes = cache.search([location[0], location[1], location[0], location[1]]);
19748 if (countryCodes.length > 0)
19749 return callback(null, countryCodes[0][4]);
19757 }), function(err, result) {
19759 return callback(err);
19760 else if (result && result.error)
19761 return callback(result.error);
19763 var extent = iD.geo.Extent(location).padByMeters(1000);
19765 cache.insert(extent.rectangle().concat(result.address.country_code));
19767 callback(null, result.address.country_code);
19771 nominatim.reset = function() {
19772 iD.services.nominatim.cache = rbush();
19777 if (!iD.services.nominatim.cache) {
19783 iD.services.taginfo = function() {
19785 endpoint = 'https://taginfo.openstreetmap.org/api/4/',
19787 point: 'count_nodes',
19788 vertex: 'count_nodes',
19789 area: 'count_ways',
19800 function sets(parameters, n, o) {
19801 if (parameters.geometry && o[parameters.geometry]) {
19802 parameters[n] = o[parameters.geometry];
19807 function setFilter(parameters) {
19808 return sets(parameters, 'filter', tag_filters);
19811 function setSort(parameters) {
19812 return sets(parameters, 'sortname', tag_sorts);
19815 function clean(parameters) {
19816 return _.omit(parameters, 'geometry', 'debounce');
19819 function popularKeys(parameters) {
19820 var pop_field = 'count_all';
19821 if (parameters.filter) pop_field = 'count_' + parameters.filter;
19822 return function(d) { return parseFloat(d[pop_field]) > 5000 || d.in_wiki; };
19825 function popularValues() {
19826 return function(d) { return parseFloat(d.fraction) > 0.01 || d.in_wiki; };
19829 function valKey(d) { return { value: d.key }; }
19831 function valKeyDescription(d) {
19834 title: d.description
19838 // sort keys with ':' lower than keys without ':'
19839 function sortKeys(a, b) {
19840 return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
19841 : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
19845 var debounced = _.debounce(d3.json, 100, true);
19847 function request(url, debounce, callback) {
19848 var cache = iD.services.taginfo.cache;
19851 callback(null, cache[url]);
19852 } else if (debounce) {
19853 debounced(url, done);
19855 d3.json(url, done);
19858 function done(err, data) {
19859 if (!err) cache[url] = data;
19860 callback(err, data);
19864 taginfo.keys = function(parameters, callback) {
19865 var debounce = parameters.debounce;
19866 parameters = clean(setSort(parameters));
19867 request(endpoint + 'keys/all?' +
19868 iD.util.qsString(_.extend({
19870 sortname: 'count_all',
19873 }, parameters)), debounce, function(err, d) {
19874 if (err) return callback(err);
19875 callback(null, d.data.filter(popularKeys(parameters)).sort(sortKeys).map(valKey));
19879 taginfo.values = function(parameters, callback) {
19880 var debounce = parameters.debounce;
19881 parameters = clean(setSort(setFilter(parameters)));
19882 request(endpoint + 'key/values?' +
19883 iD.util.qsString(_.extend({
19885 sortname: 'count_all',
19888 }, parameters)), debounce, function(err, d) {
19889 if (err) return callback(err);
19890 callback(null, d.data.filter(popularValues()).map(valKeyDescription), parameters);
19894 taginfo.docs = function(parameters, callback) {
19895 var debounce = parameters.debounce;
19896 parameters = clean(setSort(parameters));
19898 var path = 'key/wiki_pages?';
19899 if (parameters.value) path = 'tag/wiki_pages?';
19900 else if (parameters.rtype) path = 'relation/wiki_pages?';
19902 request(endpoint + path + iD.util.qsString(parameters), debounce, function(err, d) {
19903 if (err) return callback(err);
19904 callback(null, d.data);
19908 taginfo.endpoint = function(_) {
19909 if (!arguments.length) return endpoint;
19914 taginfo.reset = function() {
19915 iD.services.taginfo.cache = {};
19920 if (!iD.services.taginfo.cache) {
19926 iD.services.wikipedia = function() {
19928 endpoint = 'https://en.wikipedia.org/w/api.php?';
19930 wiki.search = function(lang, query, callback) {
19931 lang = lang || 'en';
19932 d3.jsonp(endpoint.replace('en', lang) +
19937 srinfo: 'suggestion',
19939 callback: '{callback}',
19941 }), function(data) {
19942 if (!data.query) return;
19943 callback(query, data.query.search.map(function(d) {
19949 wiki.suggestions = function(lang, query, callback) {
19950 lang = lang || 'en';
19951 d3.jsonp(endpoint.replace('en', lang) +
19953 action: 'opensearch',
19957 callback: '{callback}',
19960 callback(d[0], d[1]);
19964 wiki.translations = function(lang, title, callback) {
19965 d3.jsonp(endpoint.replace('en', lang) +
19970 callback: '{callback}',
19974 var list = d.query.pages[Object.keys(d.query.pages)[0]],
19976 if (list && list.langlinks) {
19977 list.langlinks.forEach(function(d) {
19978 translations[d.lang] = d['*'];
19980 callback(translations);
19989 iD.util.tagText = function(entity) {
19990 return d3.entries(entity.tags).map(function(e) {
19991 return e.key + '=' + e.value;
19995 iD.util.entitySelector = function(ids) {
19996 return ids.length ? '.' + ids.join(',.') : 'nothing';
19999 iD.util.entityOrMemberSelector = function(ids, graph) {
20000 var s = iD.util.entitySelector(ids);
20002 ids.forEach(function(id) {
20003 var entity = graph.hasEntity(id);
20004 if (entity && entity.type === 'relation') {
20005 entity.members.forEach(function(member) {
20006 s += ',.' + member.id;
20014 iD.util.displayName = function(entity) {
20015 var localeName = 'name:' + iD.detect().locale.toLowerCase().split('-')[0];
20016 return entity.tags[localeName] || entity.tags.name || entity.tags.ref;
20019 iD.util.displayType = function(id) {
20021 n: t('inspector.node'),
20022 w: t('inspector.way'),
20023 r: t('inspector.relation')
20027 iD.util.stringQs = function(str) {
20028 return str.split('&').reduce(function(obj, pair){
20029 var parts = pair.split('=');
20030 if (parts.length === 2) {
20031 obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
20037 iD.util.qsString = function(obj, noencode) {
20038 function softEncode(s) {
20039 // encode everything except special characters used in certain hash parameters:
20040 // "/" in map states, ":", ",", {" and "}" in background
20041 return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
20043 return Object.keys(obj).sort().map(function(key) {
20044 return encodeURIComponent(key) + '=' + (
20045 noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
20049 iD.util.prefixDOMProperty = function(property) {
20050 var prefixes = ['webkit', 'ms', 'moz', 'o'],
20052 n = prefixes.length,
20058 property = property.substr(0, 1).toUpperCase() + property.substr(1);
20061 if (prefixes[i] + property in s)
20062 return prefixes[i] + property;
20067 iD.util.prefixCSSProperty = function(property) {
20068 var prefixes = ['webkit', 'ms', 'Moz', 'O'],
20070 n = prefixes.length,
20071 s = document.body.style;
20073 if (property.toLowerCase() in s)
20074 return property.toLowerCase();
20077 if (prefixes[i] + property in s)
20078 return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
20084 iD.util.setTransform = function(el, x, y, scale) {
20085 var prop = iD.util.transformProperty = iD.util.transformProperty || iD.util.prefixCSSProperty('Transform'),
20086 translate = iD.detect().opera ?
20087 'translate(' + x + 'px,' + y + 'px)' :
20088 'translate3d(' + x + 'px,' + y + 'px,0)';
20089 return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
20092 iD.util.getStyle = function(selector) {
20093 for (var i = 0; i < document.styleSheets.length; i++) {
20094 var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules || [];
20095 for (var k = 0; k < rules.length; k++) {
20096 var selectorText = rules[k].selectorText && rules[k].selectorText.split(', ');
20097 if (_.contains(selectorText, selector)) {
20104 iD.util.editDistance = function(a, b) {
20105 if (a.length === 0) return b.length;
20106 if (b.length === 0) return a.length;
20108 for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
20109 for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
20110 for (i = 1; i <= b.length; i++) {
20111 for (j = 1; j <= a.length; j++) {
20112 if (b.charAt(i-1) === a.charAt(j-1)) {
20113 matrix[i][j] = matrix[i-1][j-1];
20115 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
20116 Math.min(matrix[i][j-1] + 1, // insertion
20117 matrix[i-1][j] + 1)); // deletion
20121 return matrix[b.length][a.length];
20124 // a d3.mouse-alike which
20125 // 1. Only works on HTML elements, not SVG
20126 // 2. Does not cause style recalculation
20127 iD.util.fastMouse = function(container) {
20128 var rect = container.getBoundingClientRect(),
20129 rectLeft = rect.left,
20130 rectTop = rect.top,
20131 clientLeft = +container.clientLeft,
20132 clientTop = +container.clientTop;
20133 return function(e) {
20135 e.clientX - rectLeft - clientLeft,
20136 e.clientY - rectTop - clientTop];
20140 /* eslint-disable no-proto */
20141 iD.util.getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
20142 /* eslint-enable no-proto */
20144 iD.util.asyncMap = function(inputs, func, callback) {
20145 var remaining = inputs.length,
20149 inputs.forEach(function(d, i) {
20150 func(d, function done(err, data) {
20154 if (!remaining) callback(errors, results);
20159 // wraps an index to an interval [0..length-1]
20160 iD.util.wrap = function(index, length) {
20162 index += Math.ceil(-index/length)*length;
20163 return index % length;
20165 // A per-domain session mutex backed by a cookie and dead man's
20166 // switch. If the session crashes, the mutex will auto-release
20167 // after 5 seconds.
20169 iD.util.SessionMutex = function(name) {
20174 var expires = new Date();
20175 expires.setSeconds(expires.getSeconds() + 5);
20176 document.cookie = name + '=1; expires=' + expires.toUTCString();
20179 mutex.lock = function() {
20180 if (intervalID) return true;
20181 var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
20182 if (cookie) return false;
20184 intervalID = window.setInterval(renew, 4000);
20188 mutex.unlock = function() {
20189 if (!intervalID) return;
20190 document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
20191 clearInterval(intervalID);
20195 mutex.locked = function() {
20196 return !!intervalID;
20201 iD.util.SuggestNames = function(preset, suggestions) {
20202 preset = preset.id.split('/', 2);
20206 return function(value, callback) {
20208 if (value && value.length > 2) {
20209 if (suggestions[k] && suggestions[k][v]) {
20210 for (var sugg in suggestions[k][v]) {
20211 var dist = iD.util.editDistance(value, sugg.substring(0, value.length));
20221 result.sort(function(a, b) {
20222 return a.dist - b.dist;
20225 result = result.slice(0,3);
20231 iD.geo.roundCoords = function(c) {
20232 return [Math.floor(c[0]), Math.floor(c[1])];
20235 iD.geo.interp = function(p1, p2, t) {
20236 return [p1[0] + (p2[0] - p1[0]) * t,
20237 p1[1] + (p2[1] - p1[1]) * t];
20240 // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
20241 // Returns a positive value, if OAB makes a counter-clockwise turn,
20242 // negative for clockwise turn, and zero if the points are collinear.
20243 iD.geo.cross = function(o, a, b) {
20244 return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
20247 // http://jsperf.com/id-dist-optimization
20248 iD.geo.euclideanDistance = function(a, b) {
20249 var x = a[0] - b[0], y = a[1] - b[1];
20250 return Math.sqrt((x * x) + (y * y));
20253 // using WGS84 polar radius (6356752.314245179 m)
20254 // const = 2 * PI * r / 360
20255 iD.geo.latToMeters = function(dLat) {
20256 return dLat * 110946.257617;
20259 // using WGS84 equatorial radius (6378137.0 m)
20260 // const = 2 * PI * r / 360
20261 iD.geo.lonToMeters = function(dLon, atLat) {
20262 return Math.abs(atLat) >= 90 ? 0 :
20263 dLon * 111319.490793 * Math.abs(Math.cos(atLat * (Math.PI/180)));
20266 // using WGS84 polar radius (6356752.314245179 m)
20267 // const = 2 * PI * r / 360
20268 iD.geo.metersToLat = function(m) {
20269 return m / 110946.257617;
20272 // using WGS84 equatorial radius (6378137.0 m)
20273 // const = 2 * PI * r / 360
20274 iD.geo.metersToLon = function(m, atLat) {
20275 return Math.abs(atLat) >= 90 ? 0 :
20276 m / 111319.490793 / Math.abs(Math.cos(atLat * (Math.PI/180)));
20279 // Equirectangular approximation of spherical distances on Earth
20280 iD.geo.sphericalDistance = function(a, b) {
20281 var x = iD.geo.lonToMeters(a[0] - b[0], (a[1] + b[1]) / 2),
20282 y = iD.geo.latToMeters(a[1] - b[1]);
20283 return Math.sqrt((x * x) + (y * y));
20286 iD.geo.edgeEqual = function(a, b) {
20287 return (a[0] === b[0] && a[1] === b[1]) ||
20288 (a[0] === b[1] && a[1] === b[0]);
20291 // Return the counterclockwise angle in the range (-pi, pi)
20292 // between the positive X axis and the line intersecting a and b.
20293 iD.geo.angle = function(a, b, projection) {
20294 a = projection(a.loc);
20295 b = projection(b.loc);
20296 return Math.atan2(b[1] - a[1], b[0] - a[0]);
20299 // Choose the edge with the minimal distance from `point` to its orthogonal
20300 // projection onto that edge, if such a projection exists, or the distance to
20301 // the closest vertex on that edge. Returns an object with the `index` of the
20302 // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
20303 iD.geo.chooseEdge = function(nodes, point, projection) {
20304 var dist = iD.geo.euclideanDistance,
20305 points = nodes.map(function(n) { return projection(n.loc); }),
20309 function dot(p, q) {
20310 return p[0] * q[0] + p[1] * q[1];
20313 for (var i = 0; i < points.length - 1; i++) {
20315 s = [points[i + 1][0] - o[0],
20316 points[i + 1][1] - o[1]],
20317 v = [point[0] - o[0],
20319 proj = dot(v, s) / dot(s, s),
20324 } else if (proj > 1) {
20327 p = [o[0] + proj * s[0], o[1] + proj * s[1]];
20330 var d = dist(p, point);
20334 loc = projection.invert(p);
20345 // Return the intersection point of 2 line segments.
20346 // From https://github.com/pgkelley4/line-segments-intersect
20347 // This uses the vector cross product approach described below:
20348 // http://stackoverflow.com/a/565282/786339
20349 iD.geo.lineIntersection = function(a, b) {
20350 function subtractPoints(point1, point2) {
20351 return [point1[0] - point2[0], point1[1] - point2[1]];
20353 function crossProduct(point1, point2) {
20354 return point1[0] * point2[1] - point1[1] * point2[0];
20357 var p = [a[0][0], a[0][1]],
20358 p2 = [a[1][0], a[1][1]],
20359 q = [b[0][0], b[0][1]],
20360 q2 = [b[1][0], b[1][1]],
20361 r = subtractPoints(p2, p),
20362 s = subtractPoints(q2, q),
20363 uNumerator = crossProduct(subtractPoints(q, p), r),
20364 denominator = crossProduct(r, s);
20366 if (uNumerator && denominator) {
20367 var u = uNumerator / denominator,
20368 t = crossProduct(subtractPoints(q, p), s) / denominator;
20370 if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
20371 return iD.geo.interp(p, p2, t);
20378 iD.geo.pathIntersections = function(path1, path2) {
20379 var intersections = [];
20380 for (var i = 0; i < path1.length - 1; i++) {
20381 for (var j = 0; j < path2.length - 1; j++) {
20382 var a = [ path1[i], path1[i+1] ],
20383 b = [ path2[j], path2[j+1] ],
20384 hit = iD.geo.lineIntersection(a, b);
20385 if (hit) intersections.push(hit);
20388 return intersections;
20391 // Return whether point is contained in polygon.
20393 // `point` should be a 2-item array of coordinates.
20394 // `polygon` should be an array of 2-item arrays of coordinates.
20396 // From https://github.com/substack/point-in-polygon.
20397 // ray-casting algorithm based on
20398 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
20400 iD.geo.pointInPolygon = function(point, polygon) {
20405 for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
20406 var xi = polygon[i][0], yi = polygon[i][1];
20407 var xj = polygon[j][0], yj = polygon[j][1];
20409 var intersect = ((yi > y) !== (yj > y)) &&
20410 (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
20411 if (intersect) inside = !inside;
20417 iD.geo.polygonContainsPolygon = function(outer, inner) {
20418 return _.every(inner, function(point) {
20419 return iD.geo.pointInPolygon(point, outer);
20423 iD.geo.polygonIntersectsPolygon = function(outer, inner, checkSegments) {
20424 function testSegments(outer, inner) {
20425 for (var i = 0; i < outer.length - 1; i++) {
20426 for (var j = 0; j < inner.length - 1; j++) {
20427 var a = [ outer[i], outer[i+1] ],
20428 b = [ inner[j], inner[j+1] ];
20429 if (iD.geo.lineIntersection(a, b)) return true;
20435 function testPoints(outer, inner) {
20436 return _.some(inner, function(point) {
20437 return iD.geo.pointInPolygon(point, outer);
20441 return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
20444 iD.geo.pathLength = function(path) {
20447 for (var i = 0; i < path.length - 1; i++) {
20448 dx = path[i][0] - path[i + 1][0];
20449 dy = path[i][1] - path[i + 1][1];
20450 length += Math.sqrt(dx * dx + dy * dy);
20454 iD.geo.Extent = function geoExtent(min, max) {
20455 if (!(this instanceof iD.geo.Extent)) return new iD.geo.Extent(min, max);
20456 if (min instanceof iD.geo.Extent) {
20458 } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
20462 this[0] = min || [ Infinity, Infinity];
20463 this[1] = max || min || [-Infinity, -Infinity];
20467 iD.geo.Extent.prototype = new Array(2);
20469 _.extend(iD.geo.Extent.prototype, {
20470 equals: function (obj) {
20471 return this[0][0] === obj[0][0] &&
20472 this[0][1] === obj[0][1] &&
20473 this[1][0] === obj[1][0] &&
20474 this[1][1] === obj[1][1];
20477 extend: function(obj) {
20478 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20479 return iD.geo.Extent([Math.min(obj[0][0], this[0][0]),
20480 Math.min(obj[0][1], this[0][1])],
20481 [Math.max(obj[1][0], this[1][0]),
20482 Math.max(obj[1][1], this[1][1])]);
20485 _extend: function(extent) {
20486 this[0][0] = Math.min(extent[0][0], this[0][0]);
20487 this[0][1] = Math.min(extent[0][1], this[0][1]);
20488 this[1][0] = Math.max(extent[1][0], this[1][0]);
20489 this[1][1] = Math.max(extent[1][1], this[1][1]);
20493 return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
20496 center: function() {
20497 return [(this[0][0] + this[1][0]) / 2,
20498 (this[0][1] + this[1][1]) / 2];
20501 rectangle: function() {
20502 return [this[0][0], this[0][1], this[1][0], this[1][1]];
20505 polygon: function() {
20507 [this[0][0], this[0][1]],
20508 [this[0][0], this[1][1]],
20509 [this[1][0], this[1][1]],
20510 [this[1][0], this[0][1]],
20511 [this[0][0], this[0][1]]
20515 contains: function(obj) {
20516 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20517 return obj[0][0] >= this[0][0] &&
20518 obj[0][1] >= this[0][1] &&
20519 obj[1][0] <= this[1][0] &&
20520 obj[1][1] <= this[1][1];
20523 intersects: function(obj) {
20524 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20525 return obj[0][0] <= this[1][0] &&
20526 obj[0][1] <= this[1][1] &&
20527 obj[1][0] >= this[0][0] &&
20528 obj[1][1] >= this[0][1];
20531 intersection: function(obj) {
20532 if (!this.intersects(obj)) return new iD.geo.Extent();
20533 return new iD.geo.Extent([Math.max(obj[0][0], this[0][0]),
20534 Math.max(obj[0][1], this[0][1])],
20535 [Math.min(obj[1][0], this[1][0]),
20536 Math.min(obj[1][1], this[1][1])]);
20539 percentContainedIn: function(obj) {
20540 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20541 var a1 = this.intersection(obj).area(),
20544 if (a1 === Infinity || a2 === Infinity || a1 === 0 || a2 === 0) {
20551 padByMeters: function(meters) {
20552 var dLat = iD.geo.metersToLat(meters),
20553 dLon = iD.geo.metersToLon(meters, this.center()[1]);
20554 return iD.geo.Extent(
20555 [this[0][0] - dLon, this[0][1] - dLat],
20556 [this[1][0] + dLon, this[1][1] + dLat]);
20559 toParam: function() {
20560 return this.rectangle().join(',');
20564 iD.geo.Turn = function(turn) {
20565 if (!(this instanceof iD.geo.Turn))
20566 return new iD.geo.Turn(turn);
20567 _.extend(this, turn);
20570 iD.geo.Intersection = function(graph, vertexId) {
20571 var vertex = graph.entity(vertexId),
20572 parentWays = graph.parentWays(vertex),
20576 function addHighway(way, adjacentNodeId) {
20577 if (highways[adjacentNodeId]) {
20578 coincident.push(adjacentNodeId);
20580 highways[adjacentNodeId] = way;
20584 // Pre-split ways that would need to be split in
20585 // order to add a restriction. The real split will
20586 // happen when the restriction is added.
20587 parentWays.forEach(function(way) {
20588 if (!way.tags.highway || way.isArea() || way.isDegenerate())
20591 var isFirst = (vertexId === way.first()),
20592 isLast = (vertexId === way.last()),
20593 isAffix = (isFirst || isLast),
20594 isClosingNode = (isFirst && isLast);
20596 if (isAffix && !isClosingNode) {
20597 var index = (isFirst ? 1 : way.nodes.length - 2);
20598 addHighway(way, way.nodes[index]);
20601 var splitIndex, wayA, wayB, indexA, indexB;
20602 if (isClosingNode) {
20603 splitIndex = Math.ceil(way.nodes.length / 2); // split at midpoint
20604 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
20605 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
20607 indexB = way.nodes.length - 2;
20609 splitIndex = _.indexOf(way.nodes, vertex.id, 1); // split at vertexid
20610 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
20611 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
20612 indexA = splitIndex - 1;
20613 indexB = splitIndex + 1;
20615 graph = graph.replace(wayA).replace(wayB);
20616 addHighway(wayA, way.nodes[indexA]);
20617 addHighway(wayB, way.nodes[indexB]);
20621 // remove any ways from this intersection that are coincident
20622 // (i.e. any adjacent node used by more than one intersecting way)
20623 coincident.forEach(function (n) {
20624 delete highways[n];
20628 var intersection = {
20629 highways: highways,
20630 ways: _.values(highways),
20634 intersection.adjacentNodeId = function(fromWayId) {
20635 return _.find(_.keys(highways), function(k) {
20636 return highways[k].id === fromWayId;
20640 intersection.turns = function(fromNodeId) {
20641 var start = highways[fromNodeId];
20645 if (start.first() === vertex.id && start.tags.oneway === 'yes')
20647 if (start.last() === vertex.id && start.tags.oneway === '-1')
20650 function withRestriction(turn) {
20651 graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
20652 if (relation.tags.type !== 'restriction')
20655 var f = relation.memberByRole('from'),
20656 t = relation.memberByRole('to'),
20657 v = relation.memberByRole('via');
20659 if (f && f.id === turn.from.way &&
20660 v && v.id === turn.via.node &&
20661 t && t.id === turn.to.way) {
20662 turn.restriction = relation.id;
20663 } else if (/^only_/.test(relation.tags.restriction) &&
20664 f && f.id === turn.from.way &&
20665 v && v.id === turn.via.node &&
20666 t && t.id !== turn.to.way) {
20667 turn.restriction = relation.id;
20668 turn.indirect_restriction = true;
20672 return iD.geo.Turn(turn);
20677 way: start.id.split(/-(a|b)/)[0]
20679 via = { node: vertex.id },
20682 _.each(highways, function(end, adjacentNodeId) {
20687 if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
20688 turns.push(withRestriction({
20692 node: adjacentNodeId,
20693 way: end.id.split(/-(a|b)/)[0]
20699 if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
20700 turns.push(withRestriction({
20704 node: adjacentNodeId,
20705 way: end.id.split(/-(a|b)/)[0]
20713 if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
20714 turns.push(withRestriction({
20725 return intersection;
20729 iD.geo.inferRestriction = function(graph, from, via, to, projection) {
20730 var fromWay = graph.entity(from.way),
20731 fromNode = graph.entity(from.node),
20732 toWay = graph.entity(to.way),
20733 toNode = graph.entity(to.node),
20734 viaNode = graph.entity(via.node),
20735 fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
20736 (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
20737 toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
20738 (toWay.tags.oneway === '-1' && toWay.last() === via.node),
20739 angle = iD.geo.angle(viaNode, fromNode, projection) -
20740 iD.geo.angle(viaNode, toNode, projection);
20742 angle = angle * 180 / Math.PI;
20747 if (fromNode === toNode)
20748 return 'no_u_turn';
20749 if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
20750 return 'no_u_turn';
20752 return 'no_right_turn';
20754 return 'no_left_turn';
20756 return 'no_straight_on';
20758 // For fixing up rendering of multipolygons with tags on the outer member.
20759 // https://github.com/openstreetmap/iD/issues/613
20760 iD.geo.isSimpleMultipolygonOuterMember = function(entity, graph) {
20761 if (entity.type !== 'way')
20764 var parents = graph.parentRelations(entity);
20765 if (parents.length !== 1)
20768 var parent = parents[0];
20769 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
20772 var members = parent.members, member;
20773 for (var i = 0; i < members.length; i++) {
20774 member = members[i];
20775 if (member.id === entity.id && member.role && member.role !== 'outer')
20776 return false; // Not outer member
20777 if (member.id !== entity.id && (!member.role || member.role === 'outer'))
20778 return false; // Not a simple multipolygon
20784 iD.geo.simpleMultipolygonOuterMember = function(entity, graph) {
20785 if (entity.type !== 'way')
20788 var parents = graph.parentRelations(entity);
20789 if (parents.length !== 1)
20792 var parent = parents[0];
20793 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
20796 var members = parent.members, member, outerMember;
20797 for (var i = 0; i < members.length; i++) {
20798 member = members[i];
20799 if (!member.role || member.role === 'outer') {
20801 return false; // Not a simple multipolygon
20802 outerMember = member;
20806 return outerMember && graph.hasEntity(outerMember.id);
20809 // Join `array` into sequences of connecting ways.
20811 // Segments which share identical start/end nodes will, as much as possible,
20812 // be connected with each other.
20814 // The return value is a nested array. Each constituent array contains elements
20815 // of `array` which have been determined to connect. Each consitituent array
20816 // also has a `nodes` property whose value is an ordered array of member nodes,
20817 // with appropriate order reversal and start/end coordinate de-duplication.
20819 // Members of `array` must have, at minimum, `type` and `id` properties.
20820 // Thus either an array of `iD.Way`s or a relation member array may be
20823 // If an member has a `tags` property, its tags will be reversed via
20824 // `iD.actions.Reverse` in the output.
20826 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
20827 // false) and non-way members are ignored.
20829 iD.geo.joinWays = function(array, graph) {
20830 var joined = [], member, current, nodes, first, last, i, how, what;
20832 array = array.filter(function(member) {
20833 return member.type === 'way' && graph.hasEntity(member.id);
20836 function resolve(member) {
20837 return graph.childNodes(graph.entity(member.id));
20840 function reverse(member) {
20841 return member.tags ? iD.actions.Reverse(member.id, {reverseOneway: true})(graph).entity(member.id) : member;
20844 while (array.length) {
20845 member = array.shift();
20846 current = [member];
20847 current.nodes = nodes = resolve(member).slice();
20848 joined.push(current);
20850 while (array.length && _.first(nodes) !== _.last(nodes)) {
20851 first = _.first(nodes);
20852 last = _.last(nodes);
20854 for (i = 0; i < array.length; i++) {
20856 what = resolve(member);
20858 if (last === _.first(what)) {
20860 what = what.slice(1);
20862 } else if (last === _.last(what)) {
20864 what = what.slice(0, -1).reverse();
20865 member = reverse(member);
20867 } else if (first === _.last(what)) {
20868 how = nodes.unshift;
20869 what = what.slice(0, -1);
20871 } else if (first === _.first(what)) {
20872 how = nodes.unshift;
20873 what = what.slice(1).reverse();
20874 member = reverse(member);
20882 break; // No more joinable ways.
20884 how.apply(current, [member]);
20885 how.apply(nodes, what);
20887 array.splice(i, 1);
20894 Bypasses features of D3's default projection stream pipeline that are unnecessary:
20895 * Antimeridian clipping
20896 * Spherical rotation
20899 iD.geo.RawMercator = function () {
20900 var project = d3.geo.mercator.raw,
20901 k = 512 / Math.PI, // scale
20902 x = 0, y = 0, // translate
20903 clipExtent = [[0, 0], [0, 0]];
20905 function projection(point) {
20906 point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
20907 return [point[0] * k + x, y - point[1] * k];
20910 projection.invert = function(point) {
20911 point = project.invert((point[0] - x) / k, (y - point[1]) / k);
20912 return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
20915 projection.scale = function(_) {
20916 if (!arguments.length) return k;
20921 projection.translate = function(_) {
20922 if (!arguments.length) return [x, y];
20928 projection.clipExtent = function(_) {
20929 if (!arguments.length) return clipExtent;
20934 projection.stream = d3.geo.transform({
20935 point: function(x, y) {
20936 x = projection([x, y]);
20937 this.stream.point(x[0], x[1]);
20944 iD.actions.AddEntity = function(way) {
20945 return function(graph) {
20946 return graph.replace(way);
20949 iD.actions.AddMember = function(relationId, member, memberIndex) {
20950 return function(graph) {
20951 var relation = graph.entity(relationId);
20953 if (isNaN(memberIndex) && member.type === 'way') {
20954 var members = relation.indexedMembers();
20955 members.push(member);
20957 var joined = iD.geo.joinWays(members, graph);
20958 for (var i = 0; i < joined.length; i++) {
20959 var segment = joined[i];
20960 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
20961 if (segment[j] !== member)
20965 memberIndex = segment[j + 1].index;
20966 } else if (j === segment.length - 1) {
20967 memberIndex = segment[j - 1].index + 1;
20969 memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
20975 return graph.replace(relation.addMember(member, memberIndex));
20978 iD.actions.AddMidpoint = function(midpoint, node) {
20979 return function(graph) {
20980 graph = graph.replace(node.move(midpoint.loc));
20982 var parents = _.intersection(
20983 graph.parentWays(graph.entity(midpoint.edge[0])),
20984 graph.parentWays(graph.entity(midpoint.edge[1])));
20986 parents.forEach(function(way) {
20987 for (var i = 0; i < way.nodes.length - 1; i++) {
20988 if (iD.geo.edgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
20989 graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
20991 // Add only one midpoint on doubled-back segments,
20992 // turning them into self-intersections.
21001 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
21002 iD.actions.AddVertex = function(wayId, nodeId, index) {
21003 return function(graph) {
21004 return graph.replace(graph.entity(wayId).addNode(nodeId, index));
21007 iD.actions.ChangeMember = function(relationId, member, memberIndex) {
21008 return function(graph) {
21009 return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
21012 iD.actions.ChangePreset = function(entityId, oldPreset, newPreset) {
21013 return function(graph) {
21014 var entity = graph.entity(entityId),
21015 geometry = entity.geometry(graph),
21016 tags = entity.tags;
21018 if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
21019 if (newPreset) tags = newPreset.applyTags(tags, geometry);
21021 return graph.replace(entity.update({tags: tags}));
21024 iD.actions.ChangeTags = function(entityId, tags) {
21025 return function(graph) {
21026 var entity = graph.entity(entityId);
21027 return graph.replace(entity.update({tags: tags}));
21030 iD.actions.Circularize = function(wayId, projection, maxAngle) {
21031 maxAngle = (maxAngle || 20) * Math.PI / 180;
21033 var action = function(graph) {
21034 var way = graph.entity(wayId);
21036 if (!way.isConvex(graph)) {
21037 graph = action.makeConvex(graph);
21040 var nodes = _.uniq(graph.childNodes(way)),
21041 keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
21042 points = nodes.map(function(n) { return projection(n.loc); }),
21043 keyPoints = keyNodes.map(function(n) { return projection(n.loc); }),
21044 centroid = (points.length === 2) ? iD.geo.interp(points[0], points[1], 0.5) : d3.geom.polygon(points).centroid(),
21045 radius = d3.median(points, function(p) { return iD.geo.euclideanDistance(centroid, p); }),
21046 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
21049 // we need atleast two key nodes for the algorithm to work
21050 if (!keyNodes.length) {
21051 keyNodes = [nodes[0]];
21052 keyPoints = [points[0]];
21055 if (keyNodes.length === 1) {
21056 var index = nodes.indexOf(keyNodes[0]),
21057 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
21059 keyNodes.push(nodes[oppositeIndex]);
21060 keyPoints.push(points[oppositeIndex]);
21063 // key points and nodes are those connected to the ways,
21064 // they are projected onto the circle, inbetween nodes are moved
21065 // to constant intervals between key nodes, extra inbetween nodes are
21066 // added if necessary.
21067 for (var i = 0; i < keyPoints.length; i++) {
21068 var nextKeyNodeIndex = (i + 1) % keyNodes.length,
21069 startNode = keyNodes[i],
21070 endNode = keyNodes[nextKeyNodeIndex],
21071 startNodeIndex = nodes.indexOf(startNode),
21072 endNodeIndex = nodes.indexOf(endNode),
21073 numberNewPoints = -1,
21074 indexRange = endNodeIndex - startNodeIndex,
21075 distance, totalAngle, eachAngle, startAngle, endAngle,
21076 angle, loc, node, j,
21077 inBetweenNodes = [];
21079 if (indexRange < 0) {
21080 indexRange += nodes.length;
21083 // position this key node
21084 distance = iD.geo.euclideanDistance(centroid, keyPoints[i]);
21085 if (distance === 0) { distance = 1e-4; }
21087 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius,
21088 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
21089 graph = graph.replace(keyNodes[i].move(projection.invert(keyPoints[i])));
21091 // figure out the between delta angle we want to match to
21092 startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
21093 endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
21094 totalAngle = endAngle - startAngle;
21096 // detects looping around -pi/pi
21097 if (totalAngle * sign > 0) {
21098 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
21103 eachAngle = totalAngle / (indexRange + numberNewPoints);
21104 } while (Math.abs(eachAngle) > maxAngle);
21106 // move existing points
21107 for (j = 1; j < indexRange; j++) {
21108 angle = startAngle + j * eachAngle;
21109 loc = projection.invert([
21110 centroid[0] + Math.cos(angle)*radius,
21111 centroid[1] + Math.sin(angle)*radius]);
21113 node = nodes[(j + startNodeIndex) % nodes.length].move(loc);
21114 graph = graph.replace(node);
21117 // add new inbetween nodes if necessary
21118 for (j = 0; j < numberNewPoints; j++) {
21119 angle = startAngle + (indexRange + j) * eachAngle;
21120 loc = projection.invert([
21121 centroid[0] + Math.cos(angle) * radius,
21122 centroid[1] + Math.sin(angle) * radius]);
21124 node = iD.Node({loc: loc});
21125 graph = graph.replace(node);
21127 nodes.splice(endNodeIndex + j, 0, node);
21128 inBetweenNodes.push(node.id);
21131 // Check for other ways that share these keyNodes..
21132 // If keyNodes are adjacent in both ways,
21133 // we can add inBetween nodes to that shared way too..
21134 if (indexRange === 1 && inBetweenNodes.length) {
21135 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
21136 endIndex1 = way.nodes.lastIndexOf(endNode.id),
21137 wayDirection1 = (endIndex1 - startIndex1);
21138 if (wayDirection1 < -1) { wayDirection1 = 1; }
21140 /* eslint-disable no-loop-func */
21141 _.each(_.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
21142 if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
21143 var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
21144 endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
21145 wayDirection2 = (endIndex2 - startIndex2),
21146 insertAt = endIndex2;
21147 if (wayDirection2 < -1) { wayDirection2 = 1; }
21149 if (wayDirection1 !== wayDirection2) {
21150 inBetweenNodes.reverse();
21151 insertAt = startIndex2;
21153 for (j = 0; j < inBetweenNodes.length; j++) {
21154 sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
21156 graph = graph.replace(sharedWay);
21159 /* eslint-enable no-loop-func */
21164 // update the way to have all the new nodes
21165 ids = nodes.map(function(n) { return n.id; });
21168 way = way.update({nodes: ids});
21169 graph = graph.replace(way);
21174 action.makeConvex = function(graph) {
21175 var way = graph.entity(wayId),
21176 nodes = _.uniq(graph.childNodes(way)),
21177 points = nodes.map(function(n) { return projection(n.loc); }),
21178 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
21179 hull = d3.geom.hull(points);
21181 // D3 convex hulls go counterclockwise..
21187 for (var i = 0; i < hull.length - 1; i++) {
21188 var startIndex = points.indexOf(hull[i]),
21189 endIndex = points.indexOf(hull[i+1]),
21190 indexRange = (endIndex - startIndex);
21192 if (indexRange < 0) {
21193 indexRange += nodes.length;
21196 // move interior nodes to the surface of the convex hull..
21197 for (var j = 1; j < indexRange; j++) {
21198 var point = iD.geo.interp(hull[i], hull[i+1], j / indexRange),
21199 node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
21200 graph = graph.replace(node);
21206 action.disabled = function(graph) {
21207 if (!graph.entity(wayId).isClosed())
21208 return 'not_closed';
21213 // Connect the ways at the given nodes.
21215 // The last node will survive. All other nodes will be replaced with
21216 // the surviving node in parent ways, and then removed.
21218 // Tags and relation memberships of of non-surviving nodes are merged
21219 // to the survivor.
21221 // This is the inverse of `iD.actions.Disconnect`.
21224 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
21225 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
21227 iD.actions.Connect = function(nodeIds) {
21228 return function(graph) {
21229 var survivor = graph.entity(_.last(nodeIds));
21231 for (var i = 0; i < nodeIds.length - 1; i++) {
21232 var node = graph.entity(nodeIds[i]);
21234 /* eslint-disable no-loop-func */
21235 graph.parentWays(node).forEach(function(parent) {
21236 if (!parent.areAdjacent(node.id, survivor.id)) {
21237 graph = graph.replace(parent.replaceNode(node.id, survivor.id));
21241 graph.parentRelations(node).forEach(function(parent) {
21242 graph = graph.replace(parent.replaceMember(node, survivor));
21244 /* eslint-enable no-loop-func */
21246 survivor = survivor.mergeTags(node.tags);
21247 graph = iD.actions.DeleteNode(node.id)(graph);
21250 graph = graph.replace(survivor);
21255 iD.actions.CopyEntities = function(ids, fromGraph) {
21258 var action = function(graph) {
21259 ids.forEach(function(id) {
21260 fromGraph.entity(id).copy(fromGraph, copies);
21263 for (var id in copies) {
21264 graph = graph.replace(copies[id]);
21270 action.copies = function() {
21276 iD.actions.DeleteMember = function(relationId, memberIndex) {
21277 return function(graph) {
21278 var relation = graph.entity(relationId)
21279 .removeMember(memberIndex);
21281 graph = graph.replace(relation);
21283 if (relation.isDegenerate())
21284 graph = iD.actions.DeleteRelation(relation.id)(graph);
21289 iD.actions.DeleteMultiple = function(ids) {
21291 way: iD.actions.DeleteWay,
21292 node: iD.actions.DeleteNode,
21293 relation: iD.actions.DeleteRelation
21296 var action = function(graph) {
21297 ids.forEach(function(id) {
21298 if (graph.hasEntity(id)) { // It may have been deleted aready.
21299 graph = actions[graph.entity(id).type](id)(graph);
21306 action.disabled = function(graph) {
21307 for (var i = 0; i < ids.length; i++) {
21309 disabled = actions[graph.entity(id).type](id).disabled(graph);
21310 if (disabled) return disabled;
21316 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
21317 iD.actions.DeleteNode = function(nodeId) {
21318 var action = function(graph) {
21319 var node = graph.entity(nodeId);
21321 graph.parentWays(node)
21322 .forEach(function(parent) {
21323 parent = parent.removeNode(nodeId);
21324 graph = graph.replace(parent);
21326 if (parent.isDegenerate()) {
21327 graph = iD.actions.DeleteWay(parent.id)(graph);
21331 graph.parentRelations(node)
21332 .forEach(function(parent) {
21333 parent = parent.removeMembersWithID(nodeId);
21334 graph = graph.replace(parent);
21336 if (parent.isDegenerate()) {
21337 graph = iD.actions.DeleteRelation(parent.id)(graph);
21341 return graph.remove(node);
21344 action.disabled = function() {
21350 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
21351 iD.actions.DeleteRelation = function(relationId) {
21352 function deleteEntity(entity, graph) {
21353 return !graph.parentWays(entity).length &&
21354 !graph.parentRelations(entity).length &&
21355 !entity.hasInterestingTags();
21358 var action = function(graph) {
21359 var relation = graph.entity(relationId);
21361 graph.parentRelations(relation)
21362 .forEach(function(parent) {
21363 parent = parent.removeMembersWithID(relationId);
21364 graph = graph.replace(parent);
21366 if (parent.isDegenerate()) {
21367 graph = iD.actions.DeleteRelation(parent.id)(graph);
21371 _.uniq(_.pluck(relation.members, 'id')).forEach(function(memberId) {
21372 graph = graph.replace(relation.removeMembersWithID(memberId));
21374 var entity = graph.entity(memberId);
21375 if (deleteEntity(entity, graph)) {
21376 graph = iD.actions.DeleteMultiple([memberId])(graph);
21380 return graph.remove(relation);
21383 action.disabled = function(graph) {
21384 if (!graph.entity(relationId).isComplete(graph))
21385 return 'incomplete_relation';
21390 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
21391 iD.actions.DeleteWay = function(wayId) {
21392 function deleteNode(node, graph) {
21393 return !graph.parentWays(node).length &&
21394 !graph.parentRelations(node).length &&
21395 !node.hasInterestingTags();
21398 var action = function(graph) {
21399 var way = graph.entity(wayId);
21401 graph.parentRelations(way)
21402 .forEach(function(parent) {
21403 parent = parent.removeMembersWithID(wayId);
21404 graph = graph.replace(parent);
21406 if (parent.isDegenerate()) {
21407 graph = iD.actions.DeleteRelation(parent.id)(graph);
21411 _.uniq(way.nodes).forEach(function(nodeId) {
21412 graph = graph.replace(way.removeNode(nodeId));
21414 var node = graph.entity(nodeId);
21415 if (deleteNode(node, graph)) {
21416 graph = graph.remove(node);
21420 return graph.remove(way);
21423 action.disabled = function(graph) {
21424 var disabled = false;
21426 graph.parentRelations(graph.entity(wayId)).forEach(function(parent) {
21427 var type = parent.tags.type,
21428 role = parent.memberById(wayId).role || 'outer';
21429 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
21430 disabled = 'part_of_relation';
21439 iD.actions.DeprecateTags = function(entityId) {
21440 return function(graph) {
21441 var entity = graph.entity(entityId),
21442 newtags = _.clone(entity.tags),
21446 // This handles deprecated tags with a single condition
21447 for (var i = 0; i < iD.data.deprecated.length; i++) {
21449 rule = iD.data.deprecated[i];
21450 var match = _.pairs(rule.old)[0],
21451 replacements = rule.replace ? _.pairs(rule.replace) : null;
21453 if (entity.tags[match[0]] && match[1] === '*') {
21455 var value = entity.tags[match[0]];
21456 if (replacements && !newtags[replacements[0][0]]) {
21457 newtags[replacements[0][0]] = value;
21459 delete newtags[match[0]];
21462 } else if (entity.tags[match[0]] === match[1]) {
21463 newtags = _.assign({}, rule.replace || {}, _.omit(newtags, match[0]));
21469 return graph.replace(entity.update({tags: newtags}));
21475 iD.actions.DiscardTags = function(difference) {
21476 return function(graph) {
21477 function discardTags(entity) {
21478 if (!_.isEmpty(entity.tags)) {
21480 _.each(entity.tags, function(v, k) {
21481 if (v) tags[k] = v;
21484 graph = graph.replace(entity.update({
21485 tags: _.omit(tags, iD.data.discarded)
21490 difference.modified().forEach(discardTags);
21491 difference.created().forEach(discardTags);
21496 // Disconect the ways at the given node.
21498 // Optionally, disconnect only the given ways.
21500 // For testing convenience, accepts an ID to assign to the (first) new node.
21501 // Normally, this will be undefined and the way will automatically
21502 // be assigned a new ID.
21504 // This is the inverse of `iD.actions.Connect`.
21507 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
21508 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
21510 iD.actions.Disconnect = function(nodeId, newNodeId) {
21513 var action = function(graph) {
21514 var node = graph.entity(nodeId),
21515 connections = action.connections(graph);
21517 connections.forEach(function(connection) {
21518 var way = graph.entity(connection.wayID),
21519 newNode = iD.Node({id: newNodeId, loc: node.loc, tags: node.tags});
21521 graph = graph.replace(newNode);
21522 if (connection.index === 0 && way.isArea()) {
21523 // replace shared node with shared node..
21524 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
21526 // replace shared node with multiple new nodes..
21527 graph = graph.replace(way.updateNode(newNode.id, connection.index));
21534 action.connections = function(graph) {
21535 var candidates = [],
21537 parentWays = graph.parentWays(graph.entity(nodeId));
21539 parentWays.forEach(function(way) {
21540 if (wayIds && wayIds.indexOf(way.id) === -1) {
21544 if (way.isArea() && (way.nodes[0] === nodeId)) {
21545 candidates.push({wayID: way.id, index: 0});
21547 way.nodes.forEach(function(waynode, index) {
21548 if (waynode === nodeId) {
21549 candidates.push({wayID: way.id, index: index});
21555 return keeping ? candidates : candidates.slice(1);
21558 action.disabled = function(graph) {
21559 var connections = action.connections(graph);
21560 if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
21561 return 'not_connected';
21563 var parentWays = graph.parentWays(graph.entity(nodeId)),
21564 seenRelationIds = {},
21567 parentWays.forEach(function(way) {
21568 if (wayIds && wayIds.indexOf(way.id) === -1)
21571 var relations = graph.parentRelations(way);
21572 relations.forEach(function(relation) {
21573 if (relation.id in seenRelationIds) {
21574 sharedRelation = relation;
21576 seenRelationIds[relation.id] = true;
21581 if (sharedRelation)
21585 action.limitWays = function(_) {
21586 if (!arguments.length) return wayIds;
21593 // Join ways at the end node they share.
21595 // This is the inverse of `iD.actions.Split`.
21598 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
21599 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
21601 iD.actions.Join = function(ids) {
21603 function groupEntitiesByGeometry(graph) {
21604 var entities = ids.map(function(id) { return graph.entity(id); });
21605 return _.extend({line: []}, _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
21608 var action = function(graph) {
21609 var ways = ids.map(graph.entity, graph),
21610 survivor = ways[0];
21612 // Prefer to keep an existing way.
21613 for (var i = 0; i < ways.length; i++) {
21614 if (!ways[i].isNew()) {
21615 survivor = ways[i];
21620 var joined = iD.geo.joinWays(ways, graph)[0];
21622 survivor = survivor.update({nodes: _.pluck(joined.nodes, 'id')});
21623 graph = graph.replace(survivor);
21625 joined.forEach(function(way) {
21626 if (way.id === survivor.id)
21629 graph.parentRelations(way).forEach(function(parent) {
21630 graph = graph.replace(parent.replaceMember(way, survivor));
21633 survivor = survivor.mergeTags(way.tags);
21635 graph = graph.replace(survivor);
21636 graph = iD.actions.DeleteWay(way.id)(graph);
21642 action.disabled = function(graph) {
21643 var geometries = groupEntitiesByGeometry(graph);
21644 if (ids.length < 2 || ids.length !== geometries.line.length)
21645 return 'not_eligible';
21647 var joined = iD.geo.joinWays(ids.map(graph.entity, graph), graph);
21648 if (joined.length > 1)
21649 return 'not_adjacent';
21651 var nodeIds = _.pluck(joined[0].nodes, 'id').slice(1, -1),
21654 conflicting = false;
21656 joined[0].forEach(function(way) {
21657 var parents = graph.parentRelations(way);
21658 parents.forEach(function(parent) {
21659 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
21663 for (var k in way.tags) {
21664 if (!(k in tags)) {
21665 tags[k] = way.tags[k];
21666 } else if (tags[k] && iD.interestingTag(k) && tags[k] !== way.tags[k]) {
21667 conflicting = true;
21673 return 'restriction';
21676 return 'conflicting_tags';
21681 iD.actions.Merge = function(ids) {
21682 function groupEntitiesByGeometry(graph) {
21683 var entities = ids.map(function(id) { return graph.entity(id); });
21684 return _.extend({point: [], area: [], line: [], relation: []},
21685 _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
21688 var action = function(graph) {
21689 var geometries = groupEntitiesByGeometry(graph),
21690 target = geometries.area[0] || geometries.line[0],
21691 points = geometries.point;
21693 points.forEach(function(point) {
21694 target = target.mergeTags(point.tags);
21696 graph.parentRelations(point).forEach(function(parent) {
21697 graph = graph.replace(parent.replaceMember(point, target));
21700 graph = graph.remove(point);
21703 graph = graph.replace(target);
21708 action.disabled = function(graph) {
21709 var geometries = groupEntitiesByGeometry(graph);
21710 if (geometries.point.length === 0 ||
21711 (geometries.area.length + geometries.line.length) !== 1 ||
21712 geometries.relation.length !== 0)
21713 return 'not_eligible';
21718 iD.actions.MergePolygon = function(ids, newRelationId) {
21720 function groupEntities(graph) {
21721 var entities = ids.map(function (id) { return graph.entity(id); });
21726 }, _.groupBy(entities, function(entity) {
21727 if (entity.type === 'way' && entity.isClosed()) {
21728 return 'closedWay';
21729 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
21730 return 'multipolygon';
21737 var action = function(graph) {
21738 var entities = groupEntities(graph);
21740 // An array representing all the polygons that are part of the multipolygon.
21742 // Each element is itself an array of objects with an id property, and has a
21743 // locs property which is an array of the locations forming the polygon.
21744 var polygons = entities.multipolygon.reduce(function(polygons, m) {
21745 return polygons.concat(iD.geo.joinWays(m.members, graph));
21746 }, []).concat(entities.closedWay.map(function(d) {
21747 var member = [{id: d.id}];
21748 member.nodes = graph.childNodes(d);
21752 // contained is an array of arrays of boolean values,
21753 // where contained[j][k] is true iff the jth way is
21754 // contained by the kth way.
21755 var contained = polygons.map(function(w, i) {
21756 return polygons.map(function(d, n) {
21757 if (i === n) return null;
21758 return iD.geo.polygonContainsPolygon(
21759 _.pluck(d.nodes, 'loc'),
21760 _.pluck(w.nodes, 'loc'));
21764 // Sort all polygons as either outer or inner ways
21768 while (polygons.length) {
21769 extractUncontained(polygons);
21770 polygons = polygons.filter(isContained);
21771 contained = contained.filter(isContained).map(filterContained);
21774 function isContained(d, i) {
21775 return _.any(contained[i]);
21778 function filterContained(d) {
21779 return d.filter(isContained);
21782 function extractUncontained(polygons) {
21783 polygons.forEach(function(d, i) {
21784 if (!isContained(d, i)) {
21785 d.forEach(function(member) {
21789 role: outer ? 'outer' : 'inner'
21797 // Move all tags to one relation
21798 var relation = entities.multipolygon[0] ||
21799 iD.Relation({ id: newRelationId, tags: { type: 'multipolygon' }});
21801 entities.multipolygon.slice(1).forEach(function(m) {
21802 relation = relation.mergeTags(m.tags);
21803 graph = graph.remove(m);
21806 entities.closedWay.forEach(function(way) {
21807 function isThisOuter(m) {
21808 return m.id === way.id && m.role !== 'inner';
21810 if (members.some(isThisOuter)) {
21811 relation = relation.mergeTags(way.tags);
21812 graph = graph.replace(way.update({ tags: {} }));
21816 return graph.replace(relation.update({
21818 tags: _.omit(relation.tags, 'area')
21822 action.disabled = function(graph) {
21823 var entities = groupEntities(graph);
21824 if (entities.other.length > 0 ||
21825 entities.closedWay.length + entities.multipolygon.length < 2)
21826 return 'not_eligible';
21827 if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
21828 return 'incomplete_relation';
21833 iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser) {
21834 var option = 'safe', // 'safe', 'force_local', 'force_remote'
21838 return _.isFunction(formatUser) ? formatUser(d) : d;
21842 function mergeLocation(remote, target) {
21843 function pointEqual(a, b) {
21844 var epsilon = 1e-6;
21845 return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
21848 if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
21851 if (option === 'force_remote') {
21852 return target.update({loc: remote.loc});
21855 conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
21860 function mergeNodes(base, remote, target) {
21861 if (option === 'force_local' || _.isEqual(target.nodes, remote.nodes)) {
21864 if (option === 'force_remote') {
21865 return target.update({nodes: remote.nodes});
21868 var ccount = conflicts.length,
21869 o = base.nodes || [],
21870 a = target.nodes || [],
21871 b = remote.nodes || [],
21873 hunks = Diff3.diff3_merge(a, o, b, true);
21875 for (var i = 0; i < hunks.length; i++) {
21876 var hunk = hunks[i];
21878 nodes.push.apply(nodes, hunk.ok);
21880 // for all conflicts, we can assume c.a !== c.b
21881 // because `diff3_merge` called with `true` option to exclude false conflicts..
21882 var c = hunk.conflict;
21883 if (_.isEqual(c.o, c.a)) { // only changed remotely
21884 nodes.push.apply(nodes, c.b);
21885 } else if (_.isEqual(c.o, c.b)) { // only changed locally
21886 nodes.push.apply(nodes, c.a);
21887 } else { // changed both locally and remotely
21888 conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
21894 return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
21898 function mergeChildren(targetWay, children, updates, graph) {
21899 function isUsed(node, targetWay) {
21900 var parentWays = _.pluck(graph.parentWays(node), 'id');
21901 return node.hasInterestingTags() ||
21902 _.without(parentWays, targetWay.id).length > 0 ||
21903 graph.parentRelations(node).length > 0;
21906 var ccount = conflicts.length;
21908 for (var i = 0; i < children.length; i++) {
21909 var id = children[i],
21910 node = graph.hasEntity(id);
21912 // remove unused childNodes..
21913 if (targetWay.nodes.indexOf(id) === -1) {
21914 if (node && !isUsed(node, targetWay)) {
21915 updates.removeIds.push(id);
21920 // restore used childNodes..
21921 var local = localGraph.hasEntity(id),
21922 remote = remoteGraph.hasEntity(id),
21925 if (option === 'force_remote' && remote && remote.visible) {
21926 updates.replacements.push(remote);
21928 } else if (option === 'force_local' && local) {
21929 target = iD.Entity(local);
21931 target = target.update({ version: remote.version });
21933 updates.replacements.push(target);
21935 } else if (option === 'safe' && local && remote && local.version !== remote.version) {
21936 target = iD.Entity(local, { version: remote.version });
21937 if (remote.visible) {
21938 target = mergeLocation(remote, target);
21940 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
21943 if (conflicts.length !== ccount) break;
21944 updates.replacements.push(target);
21952 function updateChildren(updates, graph) {
21953 for (var i = 0; i < updates.replacements.length; i++) {
21954 graph = graph.replace(updates.replacements[i]);
21956 if (updates.removeIds.length) {
21957 graph = iD.actions.DeleteMultiple(updates.removeIds)(graph);
21963 function mergeMembers(remote, target) {
21964 if (option === 'force_local' || _.isEqual(target.members, remote.members)) {
21967 if (option === 'force_remote') {
21968 return target.update({members: remote.members});
21971 conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
21976 function mergeTags(base, remote, target) {
21977 function ignoreKey(k) {
21978 return _.contains(iD.data.discarded, k);
21981 if (option === 'force_local' || _.isEqual(target.tags, remote.tags)) {
21984 if (option === 'force_remote') {
21985 return target.update({tags: remote.tags});
21988 var ccount = conflicts.length,
21989 o = base.tags || {},
21990 a = target.tags || {},
21991 b = remote.tags || {},
21992 keys = _.reject(_.union(_.keys(o), _.keys(a), _.keys(b)), ignoreKey),
21996 for (var i = 0; i < keys.length; i++) {
21999 if (o[k] !== b[k] && a[k] !== b[k]) { // changed remotely..
22000 if (o[k] !== a[k]) { // changed locally..
22001 conflicts.push(t('merge_remote_changes.conflict.tags',
22002 { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
22004 } else { // unchanged locally, accept remote change..
22005 if (b.hasOwnProperty(k)) {
22015 return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
22019 // `graph.base()` is the common ancestor of the two graphs.
22020 // `localGraph` contains user's edits up to saving
22021 // `remoteGraph` contains remote edits to modified nodes
22022 // `graph` must be a descendent of `localGraph` and may include
22023 // some conflict resolution actions performed on it.
22025 // --- ... --- `localGraph` -- ... -- `graph`
22027 // `graph.base()` --- ... --- `remoteGraph`
22029 var action = function(graph) {
22030 var updates = { replacements: [], removeIds: [] },
22031 base = graph.base().entities[id],
22032 local = localGraph.entity(id),
22033 remote = remoteGraph.entity(id),
22034 target = iD.Entity(local, { version: remote.version });
22037 if (!remote.visible) {
22038 if (option === 'force_remote') {
22039 return iD.actions.DeleteMultiple([id])(graph);
22041 } else if (option === 'force_local') {
22042 if (target.type === 'way') {
22043 target = mergeChildren(target, _.uniq(local.nodes), updates, graph);
22044 graph = updateChildren(updates, graph);
22046 return graph.replace(target);
22049 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
22050 return graph; // do nothing
22055 if (target.type === 'node') {
22056 target = mergeLocation(remote, target);
22058 } else if (target.type === 'way') {
22059 // pull in any child nodes that may not be present locally..
22060 graph.rebase(remoteGraph.childNodes(remote), [graph], false);
22061 target = mergeNodes(base, remote, target);
22062 target = mergeChildren(target, _.union(local.nodes, remote.nodes), updates, graph);
22064 } else if (target.type === 'relation') {
22065 target = mergeMembers(remote, target);
22068 target = mergeTags(base, remote, target);
22070 if (!conflicts.length) {
22071 graph = updateChildren(updates, graph).replace(target);
22077 action.withOption = function(opt) {
22082 action.conflicts = function() {
22088 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
22089 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
22090 iD.actions.Move = function(moveIds, tryDelta, projection, cache) {
22091 var delta = tryDelta;
22093 function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
22094 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
22096 function setupCache(graph) {
22097 function canMove(nodeId) {
22098 var parents = _.pluck(graph.parentWays(graph.entity(nodeId)), 'id');
22099 if (parents.length < 3) return true;
22101 // Don't move a vertex where >2 ways meet, unless all parentWays are moving too..
22102 var parentsMoving = _.all(parents, function(id) { return cache.moving[id]; });
22103 if (!parentsMoving) delete cache.moving[nodeId];
22105 return parentsMoving;
22108 function cacheEntities(ids) {
22109 _.each(ids, function(id) {
22110 if (cache.moving[id]) return;
22111 cache.moving[id] = true;
22113 var entity = graph.hasEntity(id);
22114 if (!entity) return;
22116 if (entity.type === 'node') {
22117 cache.nodes.push(id);
22118 cache.startLoc[id] = entity.loc;
22119 } else if (entity.type === 'way') {
22120 cache.ways.push(id);
22121 cacheEntities(entity.nodes);
22123 cacheEntities(_.pluck(entity.members, 'id'));
22128 function cacheIntersections(ids) {
22129 function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
22131 _.each(ids, function(id) {
22132 // consider only intersections with 1 moved and 1 unmoved way.
22133 _.each(graph.childNodes(graph.entity(id)), function(node) {
22134 var parents = graph.parentWays(node);
22135 if (parents.length !== 2) return;
22137 var moved = graph.entity(id),
22138 unmoved = _.find(parents, function(way) { return !cache.moving[way.id]; });
22139 if (!unmoved) return;
22141 // exclude ways that are overly connected..
22142 if (_.intersection(moved.nodes, unmoved.nodes).length > 2) return;
22144 if (moved.isArea() || unmoved.isArea()) return;
22146 cache.intersection[node.id] = {
22149 unmovedId: unmoved.id,
22150 movedIsEP: isEndpoint(moved, node.id),
22151 unmovedIsEP: isEndpoint(unmoved, node.id)
22163 cache.intersection = {};
22164 cache.replacedVertex = {};
22165 cache.startLoc = {};
22169 cacheEntities(moveIds);
22170 cacheIntersections(cache.ways);
22171 cache.nodes = _.filter(cache.nodes, canMove);
22178 // Place a vertex where the moved vertex used to be, to preserve way shape..
22179 function replaceMovedVertex(nodeId, wayId, graph, delta) {
22180 var way = graph.entity(wayId),
22181 moved = graph.entity(nodeId),
22182 movedIndex = way.nodes.indexOf(nodeId),
22183 len, prevIndex, nextIndex;
22185 if (way.isClosed()) {
22186 len = way.nodes.length - 1;
22187 prevIndex = (movedIndex + len - 1) % len;
22188 nextIndex = (movedIndex + len + 1) % len;
22190 len = way.nodes.length;
22191 prevIndex = movedIndex - 1;
22192 nextIndex = movedIndex + 1;
22195 var prev = graph.hasEntity(way.nodes[prevIndex]),
22196 next = graph.hasEntity(way.nodes[nextIndex]);
22198 // Don't add orig vertex at endpoint..
22199 if (!prev || !next) return graph;
22201 var key = wayId + '_' + nodeId,
22202 orig = cache.replacedVertex[key];
22205 cache.replacedVertex[key] = orig;
22206 cache.startLoc[orig.id] = cache.startLoc[nodeId];
22211 start = projection(cache.startLoc[nodeId]);
22212 end = projection.invert(vecAdd(start, delta));
22214 end = cache.startLoc[nodeId];
22216 orig = orig.move(end);
22218 var angle = Math.abs(iD.geo.angle(orig, prev, projection) -
22219 iD.geo.angle(orig, next, projection)) * 180 / Math.PI;
22221 // Don't add orig vertex if it would just make a straight line..
22222 if (angle > 175 && angle < 185) return graph;
22224 // Don't add orig vertex if another point is already nearby (within 10m)
22225 if (iD.geo.sphericalDistance(prev.loc, orig.loc) < 10 ||
22226 iD.geo.sphericalDistance(orig.loc, next.loc) < 10) return graph;
22228 // moving forward or backward along way?
22229 var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
22230 p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
22231 d1 = iD.geo.pathLength(p1),
22232 d2 = iD.geo.pathLength(p2),
22233 insertAt = (d1 < d2) ? movedIndex : nextIndex;
22235 // moving around closed loop?
22236 if (way.isClosed() && insertAt === 0) insertAt = len;
22238 way = way.addNode(orig.id, insertAt);
22239 return graph.replace(orig).replace(way);
22242 // Reorder nodes around intersections that have moved..
22243 function unZorroIntersection(intersection, graph) {
22244 var vertex = graph.entity(intersection.nodeId),
22245 way1 = graph.entity(intersection.movedId),
22246 way2 = graph.entity(intersection.unmovedId),
22247 isEP1 = intersection.movedIsEP,
22248 isEP2 = intersection.unmovedIsEP;
22250 // don't move the vertex if it is the endpoint of both ways.
22251 if (isEP1 && isEP2) return graph;
22253 var nodes1 = _.without(graph.childNodes(way1), vertex),
22254 nodes2 = _.without(graph.childNodes(way2), vertex);
22256 if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
22257 if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
22259 var edge1 = !isEP1 && iD.geo.chooseEdge(nodes1, projection(vertex.loc), projection),
22260 edge2 = !isEP2 && iD.geo.chooseEdge(nodes2, projection(vertex.loc), projection),
22263 // snap vertex to nearest edge (or some point between them)..
22264 if (!isEP1 && !isEP2) {
22265 var epsilon = 1e-4, maxIter = 10;
22266 for (var i = 0; i < maxIter; i++) {
22267 loc = iD.geo.interp(edge1.loc, edge2.loc, 0.5);
22268 edge1 = iD.geo.chooseEdge(nodes1, projection(loc), projection);
22269 edge2 = iD.geo.chooseEdge(nodes2, projection(loc), projection);
22270 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
22272 } else if (!isEP1) {
22278 graph = graph.replace(vertex.move(loc));
22280 // if zorro happened, reorder nodes..
22281 if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
22282 way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
22283 graph = graph.replace(way1);
22285 if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
22286 way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
22287 graph = graph.replace(way2);
22294 function cleanupIntersections(graph) {
22295 _.each(cache.intersection, function(obj) {
22296 graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
22297 graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
22298 graph = unZorroIntersection(obj, graph);
22304 // check if moving way endpoint can cross an unmoved way, if so limit delta..
22305 function limitDelta(graph) {
22306 _.each(cache.intersection, function(obj) {
22307 if (!obj.movedIsEP) return;
22309 var node = graph.entity(obj.nodeId),
22310 start = projection(node.loc),
22311 end = vecAdd(start, delta),
22312 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
22313 movedPath = _.map(_.pluck(movedNodes, 'loc'),
22314 function(loc) { return vecAdd(projection(loc), delta); }),
22315 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
22316 unmovedPath = _.map(_.pluck(unmovedNodes, 'loc'), projection),
22317 hits = iD.geo.pathIntersections(movedPath, unmovedPath);
22319 for (var i = 0; i < hits.length; i++) {
22320 if (_.isEqual(hits[i], end)) continue;
22321 var edge = iD.geo.chooseEdge(unmovedNodes, end, projection);
22322 delta = vecSub(projection(edge.loc), start);
22328 var action = function(graph) {
22329 if (delta[0] === 0 && delta[1] === 0) return graph;
22333 if (!_.isEmpty(cache.intersection)) {
22337 _.each(cache.nodes, function(id) {
22338 var node = graph.entity(id),
22339 start = projection(node.loc),
22340 end = vecAdd(start, delta);
22341 graph = graph.replace(node.move(projection.invert(end)));
22344 if (!_.isEmpty(cache.intersection)) {
22345 graph = cleanupIntersections(graph);
22351 action.disabled = function(graph) {
22352 function incompleteRelation(id) {
22353 var entity = graph.entity(id);
22354 return entity.type === 'relation' && !entity.isComplete(graph);
22357 if (_.any(moveIds, incompleteRelation))
22358 return 'incomplete_relation';
22361 action.delta = function() {
22367 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
22368 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
22369 iD.actions.MoveNode = function(nodeId, loc) {
22370 return function(graph) {
22371 return graph.replace(graph.entity(nodeId).move(loc));
22374 iD.actions.Noop = function() {
22375 return function(graph) {
22380 * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
22383 iD.actions.Orthogonalize = function(wayId, projection) {
22384 var threshold = 12, // degrees within right or straight to alter
22385 lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
22386 upperThreshold = Math.cos(threshold * Math.PI / 180);
22388 var action = function(graph) {
22389 var way = graph.entity(wayId),
22390 nodes = graph.childNodes(way),
22391 points = _.uniq(nodes).map(function(n) { return projection(n.loc); }),
22392 corner = {i: 0, dotp: 1},
22394 i, j, score, motions;
22396 if (nodes.length === 4) {
22397 for (i = 0; i < 1000; i++) {
22398 motions = points.map(calcMotion);
22399 points[corner.i] = addPoints(points[corner.i],motions[corner.i]);
22400 score = corner.dotp;
22401 if (score < epsilon) {
22406 graph = graph.replace(graph.entity(nodes[corner.i].id)
22407 .move(projection.invert(points[corner.i])));
22410 originalPoints = _.clone(points);
22413 for (i = 0; i < 1000; i++) {
22414 motions = points.map(calcMotion);
22415 for (j = 0; j < motions.length; j++) {
22416 points[j] = addPoints(points[j],motions[j]);
22418 var newScore = squareness(points);
22419 if (newScore < score) {
22420 best = _.clone(points);
22423 if (score < epsilon) {
22430 for (i = 0; i < points.length; i++) {
22431 // only move the points that actually moved
22432 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
22433 graph = graph.replace(graph.entity(nodes[i].id)
22434 .move(projection.invert(points[i])));
22438 // remove empty nodes on straight sections
22439 for (i = 0; i < points.length; i++) {
22440 var node = nodes[i];
22442 if (graph.parentWays(node).length > 1 ||
22443 graph.parentRelations(node).length ||
22444 node.hasInterestingTags()) {
22449 var dotp = normalizedDotProduct(i, points);
22450 if (dotp < -1 + epsilon) {
22451 graph = iD.actions.DeleteNode(nodes[i].id)(graph);
22458 function calcMotion(b, i, array) {
22459 var a = array[(i - 1 + array.length) % array.length],
22460 c = array[(i + 1) % array.length],
22461 p = subtractPoints(a, b),
22462 q = subtractPoints(c, b),
22465 scale = 2 * Math.min(iD.geo.euclideanDistance(p, [0, 0]), iD.geo.euclideanDistance(q, [0, 0]));
22466 p = normalizePoint(p, 1.0);
22467 q = normalizePoint(q, 1.0);
22469 dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
22471 // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
22472 if (array.length > 3) {
22473 if (dotp < -0.707106781186547) {
22476 } else if (dotp && Math.abs(dotp) < corner.dotp) {
22478 corner.dotp = Math.abs(dotp);
22481 return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
22485 function squareness(points) {
22486 return points.reduce(function(sum, val, i, array) {
22487 var dotp = normalizedDotProduct(i, array);
22489 dotp = filterDotProduct(dotp);
22490 return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
22494 function normalizedDotProduct(i, points) {
22495 var a = points[(i - 1 + points.length) % points.length],
22497 c = points[(i + 1) % points.length],
22498 p = subtractPoints(a, b),
22499 q = subtractPoints(c, b);
22501 p = normalizePoint(p, 1.0);
22502 q = normalizePoint(q, 1.0);
22504 return p[0] * q[0] + p[1] * q[1];
22507 function subtractPoints(a, b) {
22508 return [a[0] - b[0], a[1] - b[1]];
22511 function addPoints(a, b) {
22512 return [a[0] + b[0], a[1] + b[1]];
22515 function normalizePoint(point, scale) {
22516 var vector = [0, 0];
22517 var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
22518 if (length !== 0) {
22519 vector[0] = point[0] / length;
22520 vector[1] = point[1] / length;
22523 vector[0] *= scale;
22524 vector[1] *= scale;
22529 function filterDotProduct(dotp) {
22530 if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
22537 action.disabled = function(graph) {
22538 var way = graph.entity(wayId),
22539 nodes = graph.childNodes(way),
22540 points = _.uniq(nodes).map(function(n) { return projection(n.loc); });
22542 if (squareness(points)) {
22546 return 'not_squarish';
22551 // Create a restriction relation for `turn`, which must have the following structure:
22554 // from: { node: <node ID>, way: <way ID> },
22555 // via: { node: <node ID> },
22556 // to: { node: <node ID>, way: <way ID> },
22557 // restriction: <'no_right_turn', 'no_left_turn', etc.>
22560 // This specifies a restriction of type `restriction` when traveling from
22561 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
22562 // (The action does not check that these entities form a valid intersection.)
22564 // If `restriction` is not provided, it is automatically determined by
22565 // iD.geo.inferRestriction.
22567 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
22568 // and `to.node` are used to determine which portion of the split ways become
22569 // members of the restriction.
22571 // For testing convenience, accepts an ID to assign to the new relation.
22572 // Normally, this will be undefined and the relation will automatically
22573 // be assigned a new ID.
22575 iD.actions.RestrictTurn = function(turn, projection, restrictionId) {
22576 return function(graph) {
22577 var from = graph.entity(turn.from.way),
22578 via = graph.entity(turn.via.node),
22579 to = graph.entity(turn.to.way);
22581 function isClosingNode(way, nodeId) {
22582 return nodeId === way.first() && nodeId === way.last();
22585 function split(toOrFrom) {
22586 var newID = toOrFrom.newID || iD.Way().id;
22587 graph = iD.actions.Split(via.id, [newID])
22588 .limitWays([toOrFrom.way])(graph);
22590 var a = graph.entity(newID),
22591 b = graph.entity(toOrFrom.way);
22593 if (a.nodes.indexOf(toOrFrom.node) !== -1) {
22600 if (!from.affix(via.id) || isClosingNode(from, via.id)) {
22601 if (turn.from.node === turn.to.node) {
22603 from = to = split(turn.from)[0];
22604 } else if (turn.from.way === turn.to.way) {
22605 // Straight-on or circular
22606 var s = split(turn.from);
22611 from = split(turn.from)[0];
22615 if (!to.affix(via.id) || isClosingNode(to, via.id)) {
22616 to = split(turn.to)[0];
22619 return graph.replace(iD.Relation({
22622 type: 'restriction',
22623 restriction: turn.restriction ||
22624 iD.geo.inferRestriction(
22632 {id: from.id, type: 'way', role: 'from'},
22633 {id: via.id, type: 'node', role: 'via'},
22634 {id: to.id, type: 'way', role: 'to'}
22640 Order the nodes of a way in reverse order and reverse any direction dependent tags
22641 other than `oneway`. (We assume that correcting a backwards oneway is the primary
22642 reason for reversing a way.)
22644 The following transforms are performed:
22647 *:right=* ⟺ *:left=*
22648 *:forward=* ⟺ *:backward=*
22649 direction=up ⟺ direction=down
22650 incline=up ⟺ incline=down
22654 role=forward ⟺ role=backward
22655 role=north ⟺ role=south
22656 role=east ⟺ role=west
22658 In addition, numeric-valued `incline` tags are negated.
22660 The JOSM implementation was used as a guide, but transformations that were of unclear benefit
22661 or adjusted tags that don't seem to be used in practice were omitted.
22664 http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
22665 http://wiki.openstreetmap.org/wiki/Key:direction#Steps
22666 http://wiki.openstreetmap.org/wiki/Key:incline
22667 http://wiki.openstreetmap.org/wiki/Route#Members
22668 http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
22670 iD.actions.Reverse = function(wayId, options) {
22671 var replacements = [
22672 [/:right$/, ':left'], [/:left$/, ':right'],
22673 [/:forward$/, ':backward'], [/:backward$/, ':forward']
22675 numeric = /^([+\-]?)(?=[\d.])/,
22677 forward: 'backward',
22678 backward: 'forward',
22685 function reverseKey(key) {
22686 for (var i = 0; i < replacements.length; ++i) {
22687 var replacement = replacements[i];
22688 if (replacement[0].test(key)) {
22689 return key.replace(replacement[0], replacement[1]);
22695 function reverseValue(key, value) {
22696 if (key === 'incline' && numeric.test(value)) {
22697 return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
22698 } else if (key === 'incline' || key === 'direction') {
22699 return {up: 'down', down: 'up'}[value] || value;
22700 } else if (options && options.reverseOneway && key === 'oneway') {
22701 return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
22703 return {left: 'right', right: 'left'}[value] || value;
22707 return function(graph) {
22708 var way = graph.entity(wayId),
22709 nodes = way.nodes.slice().reverse(),
22710 tags = {}, key, role;
22712 for (key in way.tags) {
22713 tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
22716 graph.parentRelations(way).forEach(function(relation) {
22717 relation.members.forEach(function(member, index) {
22718 if (member.id === way.id && (role = roleReversals[member.role])) {
22719 relation = relation.updateMember({role: role}, index);
22720 graph = graph.replace(relation);
22725 return graph.replace(way.update({nodes: nodes, tags: tags}));
22728 iD.actions.Revert = function(id) {
22730 var action = function(graph) {
22731 var entity = graph.hasEntity(id),
22732 base = graph.base().entities[id];
22734 if (entity && !base) { // entity will be removed..
22735 if (entity.type === 'node') {
22736 graph.parentWays(entity)
22737 .forEach(function(parent) {
22738 parent = parent.removeNode(id);
22739 graph = graph.replace(parent);
22741 if (parent.isDegenerate()) {
22742 graph = iD.actions.DeleteWay(parent.id)(graph);
22747 graph.parentRelations(entity)
22748 .forEach(function(parent) {
22749 parent = parent.removeMembersWithID(id);
22750 graph = graph.replace(parent);
22752 if (parent.isDegenerate()) {
22753 graph = iD.actions.DeleteRelation(parent.id)(graph);
22758 return graph.revert(id);
22763 iD.actions.RotateWay = function(wayId, pivot, angle, projection) {
22764 return function(graph) {
22765 return graph.update(function(graph) {
22766 var way = graph.entity(wayId);
22768 _.unique(way.nodes).forEach(function(id) {
22770 var node = graph.entity(id),
22771 point = projection(node.loc),
22774 radial[0] = point[0] - pivot[0];
22775 radial[1] = point[1] - pivot[1];
22778 radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + pivot[0],
22779 radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + pivot[1]
22782 graph = graph.replace(node.move(projection.invert(point)));
22789 // Split a way at the given node.
22791 // Optionally, split only the given ways, if multiple ways share
22794 // This is the inverse of `iD.actions.Join`.
22796 // For testing convenience, accepts an ID to assign to the new way.
22797 // Normally, this will be undefined and the way will automatically
22798 // be assigned a new ID.
22801 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
22803 iD.actions.Split = function(nodeId, newWayIds) {
22806 // if the way is closed, we need to search for a partner node
22807 // to split the way at.
22809 // The following looks for a node that is both far away from
22810 // the initial node in terms of way segment length and nearby
22811 // in terms of beeline-distance. This assures that areas get
22812 // split on the most "natural" points (independent of the number
22814 // For example: bone-shaped areas get split across their waist
22815 // line, circles across the diameter.
22816 function splitArea(nodes, idxA, graph) {
22817 var lengths = new Array(nodes.length),
22823 function wrap(index) {
22824 return iD.util.wrap(index, nodes.length);
22827 function dist(nA, nB) {
22828 return iD.geo.sphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
22831 // calculate lengths
22833 for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
22834 length += dist(nodes[i], nodes[wrap(i-1)]);
22835 lengths[i] = length;
22839 for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
22840 length += dist(nodes[i], nodes[wrap(i+1)]);
22841 if (length < lengths[i])
22842 lengths[i] = length;
22845 // determine best opposite node to split
22846 for (i = 0; i < nodes.length; i++) {
22847 var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
22857 function split(graph, wayA, newWayId) {
22858 var wayB = iD.Way({id: newWayId, tags: wayA.tags}),
22861 isArea = wayA.isArea(),
22862 isOuter = iD.geo.isSimpleMultipolygonOuterMember(wayA, graph);
22864 if (wayA.isClosed()) {
22865 var nodes = wayA.nodes.slice(0, -1),
22866 idxA = _.indexOf(nodes, nodeId),
22867 idxB = splitArea(nodes, idxA, graph);
22870 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
22871 nodesB = nodes.slice(idxB, idxA + 1);
22873 nodesA = nodes.slice(idxA, idxB + 1);
22874 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
22877 var idx = _.indexOf(wayA.nodes, nodeId, 1);
22878 nodesA = wayA.nodes.slice(0, idx + 1);
22879 nodesB = wayA.nodes.slice(idx);
22882 wayA = wayA.update({nodes: nodesA});
22883 wayB = wayB.update({nodes: nodesB});
22885 graph = graph.replace(wayA);
22886 graph = graph.replace(wayB);
22888 graph.parentRelations(wayA).forEach(function(relation) {
22889 if (relation.isRestriction()) {
22890 var via = relation.memberByRole('via');
22891 if (via && wayB.contains(via.id)) {
22892 relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
22893 graph = graph.replace(relation);
22896 if (relation === isOuter) {
22897 graph = graph.replace(relation.mergeTags(wayA.tags));
22898 graph = graph.replace(wayA.update({tags: {}}));
22899 graph = graph.replace(wayB.update({tags: {}}));
22905 role: relation.memberById(wayA.id).role
22908 graph = iD.actions.AddMember(relation.id, member)(graph);
22912 if (!isOuter && isArea) {
22913 var multipolygon = iD.Relation({
22914 tags: _.extend({}, wayA.tags, {type: 'multipolygon'}),
22916 {id: wayA.id, role: 'outer', type: 'way'},
22917 {id: wayB.id, role: 'outer', type: 'way'}
22920 graph = graph.replace(multipolygon);
22921 graph = graph.replace(wayA.update({tags: {}}));
22922 graph = graph.replace(wayB.update({tags: {}}));
22928 var action = function(graph) {
22929 var candidates = action.ways(graph);
22930 for (var i = 0; i < candidates.length; i++) {
22931 graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
22936 action.ways = function(graph) {
22937 var node = graph.entity(nodeId),
22938 parents = graph.parentWays(node),
22939 hasLines = _.any(parents, function(parent) { return parent.geometry(graph) === 'line'; });
22941 return parents.filter(function(parent) {
22942 if (wayIds && wayIds.indexOf(parent.id) === -1)
22945 if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
22948 if (parent.isClosed()) {
22952 for (var i = 1; i < parent.nodes.length - 1; i++) {
22953 if (parent.nodes[i] === nodeId) {
22962 action.disabled = function(graph) {
22963 var candidates = action.ways(graph);
22964 if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
22965 return 'not_eligible';
22968 action.limitWays = function(_) {
22969 if (!arguments.length) return wayIds;
22977 * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
22980 iD.actions.Straighten = function(wayId, projection) {
22981 function positionAlongWay(n, s, e) {
22982 return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1]))/
22983 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
22986 var action = function(graph) {
22987 var way = graph.entity(wayId),
22988 nodes = graph.childNodes(way),
22989 points = nodes.map(function(n) { return projection(n.loc); }),
22990 startPoint = points[0],
22991 endPoint = points[points.length-1],
22995 for (i = 1; i < points.length-1; i++) {
22996 var node = nodes[i],
22999 if (graph.parentWays(node).length > 1 ||
23000 graph.parentRelations(node).length ||
23001 node.hasInterestingTags()) {
23003 var u = positionAlongWay(point, startPoint, endPoint),
23004 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
23005 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]);
23007 graph = graph.replace(graph.entity(node.id)
23008 .move(projection.invert([p0, p1])));
23011 if (toDelete.indexOf(node) === -1) {
23012 toDelete.push(node);
23017 for (i = 0; i < toDelete.length; i++) {
23018 graph = iD.actions.DeleteNode(toDelete[i].id)(graph);
23024 action.disabled = function(graph) {
23025 // check way isn't too bendy
23026 var way = graph.entity(wayId),
23027 nodes = graph.childNodes(way),
23028 points = nodes.map(function(n) { return projection(n.loc); }),
23029 startPoint = points[0],
23030 endPoint = points[points.length-1],
23031 threshold = 0.2 * Math.sqrt(Math.pow(startPoint[0] - endPoint[0], 2) + Math.pow(startPoint[1] - endPoint[1], 2)),
23034 for (i = 1; i < points.length-1; i++) {
23035 var point = points[i],
23036 u = positionAlongWay(point, startPoint, endPoint),
23037 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
23038 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
23039 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
23041 // to bendy if point is off by 20% of total start/end distance in projected space
23042 if (dist > threshold) {
23043 return 'too_bendy';
23050 // Remove the effects of `turn.restriction` on `turn`, which must have the
23051 // following structure:
23054 // from: { node: <node ID>, way: <way ID> },
23055 // via: { node: <node ID> },
23056 // to: { node: <node ID>, way: <way ID> },
23057 // restriction: <relation ID>
23060 // In the simple case, `restriction` is a reference to a `no_*` restriction
23061 // on the turn itself. In this case, it is simply deleted.
23063 // The more complex case is where `restriction` references an `only_*`
23064 // restriction on a different turn in the same intersection. In that case,
23065 // that restriction is also deleted, but at the same time restrictions on
23066 // the turns other than the first two are created.
23068 iD.actions.UnrestrictTurn = function(turn) {
23069 return function(graph) {
23070 return iD.actions.DeleteRelation(turn.restriction)(graph);
23074 iD.behavior.AddWay = function(context) {
23075 var event = d3.dispatch('start', 'startFromWay', 'startFromNode'),
23076 draw = iD.behavior.Draw(context);
23078 var addWay = function(surface) {
23079 draw.on('click', event.start)
23080 .on('clickWay', event.startFromWay)
23081 .on('clickNode', event.startFromNode)
23082 .on('cancel', addWay.cancel)
23083 .on('finish', addWay.cancel);
23086 .dblclickEnable(false);
23088 surface.call(draw);
23091 addWay.off = function(surface) {
23092 surface.call(draw.off);
23095 addWay.cancel = function() {
23096 window.setTimeout(function() {
23097 context.map().dblclickEnable(true);
23100 context.enter(iD.modes.Browse(context));
23103 addWay.tail = function(text) {
23108 return d3.rebind(addWay, event, 'on');
23110 iD.behavior.Breathe = function() {
23111 var duration = 800,
23112 selector = '.selected.shadow, .selected .shadow',
23113 selected = d3.select(null),
23118 function reset(selection) {
23120 .style('stroke-opacity', null)
23121 .style('stroke-width', null)
23122 .style('fill-opacity', null)
23126 function setAnimationParams(transition, fromTo) {
23128 .style('stroke-opacity', function(d) { return params[d.id][fromTo].opacity; })
23129 .style('stroke-width', function(d) { return params[d.id][fromTo].width; })
23130 .style('fill-opacity', function(d) { return params[d.id][fromTo].opacity; })
23131 .style('r', function(d) { return params[d.id][fromTo].width; });
23134 function calcAnimationParams(selection) {
23137 .each(function(d) {
23138 var s = d3.select(this),
23139 tag = s.node().tagName,
23140 p = {'from': {}, 'to': {}},
23143 // determine base opacity and width
23144 if (tag === 'circle') {
23145 opacity = parseFloat(s.style('fill-opacity') || 0.5);
23146 width = parseFloat(s.style('r') || 15.5);
23148 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
23149 width = parseFloat(s.style('stroke-width') || 10);
23152 // calculate from/to interpolation params..
23154 p.from.opacity = opacity * 0.6;
23155 p.to.opacity = opacity * 1.25;
23156 p.from.width = width * 0.9;
23157 p.to.width = width * (tag === 'circle' ? 1.5 : 1.25);
23162 function run(surface, fromTo) {
23163 var toFrom = (fromTo === 'from' ? 'to': 'from'),
23164 currSelected = surface.selectAll(selector),
23165 currClassed = surface.attr('class'),
23168 if (done || currSelected.empty()) {
23169 selected.call(reset);
23173 if (!_.isEqual(currSelected, selected) || currClassed !== classed) {
23174 selected.call(reset);
23175 classed = currClassed;
23176 selected = currSelected.call(calcAnimationParams);
23181 .call(setAnimationParams, fromTo)
23182 .duration(duration)
23183 .each(function() { ++n; })
23184 .each('end', function() {
23185 if (!--n) { // call once
23186 surface.call(run, toFrom);
23191 var breathe = function(surface) {
23193 d3.timer(function() {
23194 if (done) return true;
23196 var currSelected = surface.selectAll(selector);
23197 if (currSelected.empty()) return false;
23199 surface.call(run, 'from');
23204 breathe.off = function() {
23215 iD.behavior.Copy = function(context) {
23216 var keybinding = d3.keybinding('copy');
23218 function groupEntities(ids, graph) {
23219 var entities = ids.map(function (id) { return graph.entity(id); });
23220 return _.extend({relation: [], way: [], node: []},
23221 _.groupBy(entities, function(entity) { return entity.type; }));
23224 function getDescendants(id, graph, descendants) {
23225 var entity = graph.entity(id),
23228 descendants = descendants || {};
23230 if (entity.type === 'relation') {
23231 children = _.pluck(entity.members, 'id');
23232 } else if (entity.type === 'way') {
23233 children = entity.nodes;
23238 for (i = 0; i < children.length; i++) {
23239 if (!descendants[children[i]]) {
23240 descendants[children[i]] = true;
23241 descendants = getDescendants(children[i], graph, descendants);
23245 return descendants;
23248 function doCopy() {
23249 d3.event.preventDefault();
23250 if (context.inIntro()) return;
23252 var graph = context.graph(),
23253 selected = groupEntities(context.selectedIDs(), graph),
23258 for (i = 0; i < selected.relation.length; i++) {
23259 entity = selected.relation[i];
23260 if (!skip[entity.id] && entity.isComplete(graph)) {
23261 canCopy.push(entity.id);
23262 skip = getDescendants(entity.id, graph, skip);
23265 for (i = 0; i < selected.way.length; i++) {
23266 entity = selected.way[i];
23267 if (!skip[entity.id]) {
23268 canCopy.push(entity.id);
23269 skip = getDescendants(entity.id, graph, skip);
23272 for (i = 0; i < selected.node.length; i++) {
23273 entity = selected.node[i];
23274 if (!skip[entity.id]) {
23275 canCopy.push(entity.id);
23279 context.copyIDs(canCopy);
23283 keybinding.on(iD.ui.cmd('⌘C'), doCopy);
23284 d3.select(document).call(keybinding);
23288 copy.off = function() {
23289 d3.select(document).call(keybinding.off);
23295 `iD.behavior.drag` is like `d3.behavior.drag`, with the following differences:
23297 * The `origin` function is expected to return an [x, y] tuple rather than an
23299 * The events are `start`, `move`, and `end`.
23300 (https://github.com/mbostock/d3/issues/563)
23301 * The `start` event is not dispatched until the first cursor movement occurs.
23302 (https://github.com/mbostock/d3/pull/368)
23303 * The `move` event has a `point` and `delta` [x, y] tuple properties rather
23304 than `x`, `y`, `dx`, and `dy` properties.
23305 * The `end` event is not dispatched if no movement occurs.
23306 * An `off` function is available that unbinds the drag's internal event handlers.
23307 * Delegation is supported via the `delegate` function.
23310 iD.behavior.drag = function() {
23311 function d3_eventCancel() {
23312 d3.event.stopPropagation();
23313 d3.event.preventDefault();
23316 var event = d3.dispatch('start', 'move', 'end'),
23320 event_, target, surface;
23322 event.of = function(thiz, argumentz) {
23323 return function(e1) {
23324 var e0 = e1.sourceEvent = d3.event;
23328 event[e1.type].apply(thiz, argumentz);
23335 var d3_event_userSelectProperty = iD.util.prefixCSSProperty('UserSelect'),
23336 d3_event_userSelectSuppress = d3_event_userSelectProperty ?
23338 var selection = d3.selection(),
23339 select = selection.style(d3_event_userSelectProperty);
23340 selection.style(d3_event_userSelectProperty, 'none');
23341 return function () {
23342 selection.style(d3_event_userSelectProperty, select);
23346 var w = d3.select(window).on('selectstart.' + type, d3_eventCancel);
23347 return function () {
23348 w.on('selectstart.' + type, null);
23352 function mousedown() {
23354 event_ = event.of(target, arguments);
23355 var eventTarget = d3.event.target,
23356 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
23360 selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
23362 var w = d3.select(window)
23363 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
23364 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
23367 offset = origin.apply(target, arguments);
23368 offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
23373 if (touchId === null) d3.event.stopPropagation();
23376 var p = target.parentNode || surface;
23377 return touchId !== null ? d3.touches(p).filter(function(p) {
23378 return p.identifier === touchId;
23379 })[0] : d3.mouse(p);
23382 function dragmove() {
23385 dx = p[0] - origin_[0],
23386 dy = p[1] - origin_[1];
23388 if (dx === 0 && dy === 0)
23403 point: [p[0] + offset[0], p[1] + offset[1]],
23408 function dragend() {
23415 if (d3.event.target === eventTarget) w.on('click.drag', click, true);
23418 w.on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
23419 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
23425 w.on('click.drag', null);
23429 function drag(selection) {
23430 var matchesSelector = iD.util.prefixDOMProperty('matchesSelector'),
23431 delegate = mousedown;
23434 delegate = function() {
23436 target = d3.event.target;
23437 for (; target && target !== root; target = target.parentNode) {
23438 if (target[matchesSelector](selector) &&
23439 (!filter || filter(target.__data__))) {
23440 return mousedown.call(target, target.__data__);
23446 selection.on('mousedown.drag' + selector, delegate)
23447 .on('touchstart.drag' + selector, delegate);
23450 drag.off = function(selection) {
23451 selection.on('mousedown.drag' + selector, null)
23452 .on('touchstart.drag' + selector, null);
23455 drag.delegate = function(_) {
23456 if (!arguments.length) return selector;
23461 drag.filter = function(_) {
23462 if (!arguments.length) return origin;
23467 drag.origin = function (_) {
23468 if (!arguments.length) return origin;
23473 drag.cancel = function() {
23475 .on('mousemove.drag', null)
23476 .on('mouseup.drag', null);
23480 drag.target = function() {
23481 if (!arguments.length) return target;
23482 target = arguments[0];
23483 event_ = event.of(target, Array.prototype.slice.call(arguments, 1));
23487 drag.surface = function() {
23488 if (!arguments.length) return surface;
23489 surface = arguments[0];
23493 return d3.rebind(drag, event, 'on');
23495 iD.behavior.Draw = function(context) {
23496 var event = d3.dispatch('move', 'click', 'clickWay',
23497 'clickNode', 'undo', 'cancel', 'finish'),
23498 keybinding = d3.keybinding('draw'),
23499 hover = iD.behavior.Hover(context)
23501 .on('hover', context.ui().sidebar.hover),
23502 tail = iD.behavior.Tail(),
23503 edit = iD.behavior.Edit(context),
23504 closeTolerance = 4,
23508 if (d3.event.altKey) return {};
23509 else return d3.event.target.__data__ || {};
23512 function mousedown() {
23515 var p = context.container().node();
23516 return touchId !== null ? d3.touches(p).filter(function(p) {
23517 return p.identifier === touchId;
23518 })[0] : d3.mouse(p);
23521 var element = d3.select(this),
23522 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
23526 element.on('mousemove.draw', null);
23528 d3.select(window).on('mouseup.draw', function() {
23529 var t2 = +new Date(),
23531 dist = iD.geo.euclideanDistance(p1, p2);
23533 element.on('mousemove.draw', mousemove);
23534 d3.select(window).on('mouseup.draw', null);
23536 if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
23537 // Prevent a quick second click
23538 d3.select(window).on('click.draw-block', function() {
23539 d3.event.stopPropagation();
23542 context.map().dblclickEnable(false);
23544 window.setTimeout(function() {
23545 context.map().dblclickEnable(true);
23546 d3.select(window).on('click.draw-block', null);
23554 function mousemove() {
23555 event.move(datum());
23560 if (d.type === 'way') {
23561 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection),
23562 edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
23563 event.clickWay(choice.loc, edge);
23565 } else if (d.type === 'node') {
23566 event.clickNode(d);
23569 event.click(context.map().mouseCoordinates());
23573 function backspace() {
23574 d3.event.preventDefault();
23579 d3.event.preventDefault();
23584 d3.event.preventDefault();
23588 function draw(selection) {
23589 context.install(hover);
23590 context.install(edit);
23592 if (!context.inIntro() && !iD.behavior.Draw.usedTails[tail.text()]) {
23593 context.install(tail);
23597 .on('⌫', backspace)
23603 .on('mousedown.draw', mousedown)
23604 .on('mousemove.draw', mousemove);
23606 d3.select(document)
23612 draw.off = function(selection) {
23613 context.ui().sidebar.hover.cancel();
23614 context.uninstall(hover);
23615 context.uninstall(edit);
23617 if (!context.inIntro() && !iD.behavior.Draw.usedTails[tail.text()]) {
23618 context.uninstall(tail);
23619 iD.behavior.Draw.usedTails[tail.text()] = true;
23623 .on('mousedown.draw', null)
23624 .on('mousemove.draw', null);
23627 .on('mouseup.draw', null);
23629 d3.select(document)
23630 .call(keybinding.off);
23633 draw.tail = function(_) {
23638 return d3.rebind(draw, event, 'on');
23641 iD.behavior.Draw.usedTails = {};
23642 iD.behavior.DrawWay = function(context, wayId, index, mode, baseGraph) {
23643 var way = context.entity(wayId),
23644 isArea = context.geometry(wayId) === 'area',
23646 annotation = t((way.isDegenerate() ?
23647 'operations.start.annotation.' :
23648 'operations.continue.annotation.') + context.geometry(wayId)),
23649 draw = iD.behavior.Draw(context);
23651 var startIndex = typeof index === 'undefined' ? way.nodes.length - 1 : 0,
23652 start = iD.Node({loc: context.graph().entity(way.nodes[startIndex]).loc}),
23653 end = iD.Node({loc: context.map().mouseCoordinates()}),
23655 nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
23656 tags: _.clone(way.tags)
23659 var f = context[way.isDegenerate() ? 'replace' : 'perform'];
23661 f(iD.actions.AddEntity(end),
23662 iD.actions.AddVertex(wayId, end.id, index));
23664 f(iD.actions.AddEntity(start),
23665 iD.actions.AddEntity(end),
23666 iD.actions.AddEntity(segment));
23669 function move(datum) {
23672 if (datum.type === 'node' && datum.id !== end.id) {
23674 } else if (datum.type === 'way' && datum.id !== segment.id) {
23675 loc = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
23677 loc = context.map().mouseCoordinates();
23680 context.replace(iD.actions.MoveNode(end.id, loc));
23683 function undone() {
23685 context.enter(iD.modes.Browse(context));
23688 function setActiveElements() {
23689 var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
23690 context.surface().selectAll(iD.util.entitySelector(active))
23691 .classed('active', true);
23694 var drawWay = function(surface) {
23695 draw.on('move', move)
23696 .on('click', drawWay.add)
23697 .on('clickWay', drawWay.addWay)
23698 .on('clickNode', drawWay.addNode)
23699 .on('undo', context.undo)
23700 .on('cancel', drawWay.cancel)
23701 .on('finish', drawWay.finish);
23704 .dblclickEnable(false)
23705 .on('drawn.draw', setActiveElements);
23707 setActiveElements();
23709 surface.call(draw);
23712 .on('undone.draw', undone);
23715 drawWay.off = function(surface) {
23720 .on('drawn.draw', null);
23722 surface.call(draw.off)
23723 .selectAll('.active')
23724 .classed('active', false);
23727 .on('undone.draw', null);
23730 function ReplaceTemporaryNode(newNode) {
23731 return function(graph) {
23734 .replace(way.addNode(newNode.id, index))
23739 .replace(graph.entity(wayId).addNode(newNode.id, index))
23747 // Accept the current position of the temporary node and continue drawing.
23748 drawWay.add = function(loc) {
23750 // prevent duplicate nodes
23751 var last = context.hasEntity(way.nodes[way.nodes.length - (isArea ? 2 : 1)]);
23752 if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
23754 var newNode = iD.Node({loc: loc});
23757 iD.actions.AddEntity(newNode),
23758 ReplaceTemporaryNode(newNode),
23762 context.enter(mode);
23765 // Connect the way to an existing way.
23766 drawWay.addWay = function(loc, edge) {
23767 var previousEdge = startIndex ?
23768 [way.nodes[startIndex], way.nodes[startIndex - 1]] :
23769 [way.nodes[0], way.nodes[1]];
23771 // Avoid creating duplicate segments
23772 if (!isArea && iD.geo.edgeEqual(edge, previousEdge))
23775 var newNode = iD.Node({ loc: loc });
23778 iD.actions.AddMidpoint({ loc: loc, edge: edge}, newNode),
23779 ReplaceTemporaryNode(newNode),
23783 context.enter(mode);
23786 // Connect the way to an existing node and continue drawing.
23787 drawWay.addNode = function(node) {
23789 // Avoid creating duplicate segments
23790 if (way.areAdjacent(node.id, way.nodes[way.nodes.length - 1])) return;
23793 ReplaceTemporaryNode(node),
23797 context.enter(mode);
23800 // Finish the draw operation, removing the temporary node. If the way has enough
23801 // nodes to be valid, it's selected. Otherwise, return to browse mode.
23802 drawWay.finish = function() {
23806 window.setTimeout(function() {
23807 context.map().dblclickEnable(true);
23810 if (context.hasEntity(wayId)) {
23812 iD.modes.Select(context, [wayId])
23813 .suppressMenu(true)
23814 .newFeature(true));
23816 context.enter(iD.modes.Browse(context));
23820 // Cancel the draw operation and return to browse, deleting everything drawn.
23821 drawWay.cancel = function() {
23823 d3.functor(baseGraph),
23824 t('operations.cancel_draw.annotation'));
23826 window.setTimeout(function() {
23827 context.map().dblclickEnable(true);
23831 context.enter(iD.modes.Browse(context));
23834 drawWay.tail = function(text) {
23841 iD.behavior.Edit = function(context) {
23844 .minzoom(context.minEditableZoom());
23847 edit.off = function() {
23854 iD.behavior.Hash = function(context) {
23855 var s0 = null, // cached location.hash
23856 lat = 90 - 1e-8; // allowable latitude range
23858 var parser = function(map, s) {
23859 var q = iD.util.stringQs(s);
23860 var args = (q.map || '').split('/').map(Number);
23861 if (args.length < 3 || args.some(isNaN)) {
23862 return true; // replace bogus hash
23863 } else if (s !== formatter(map).slice(1)) {
23864 map.centerZoom([args[1],
23865 Math.min(lat, Math.max(-lat, args[2]))], args[0]);
23869 var formatter = function(map) {
23870 var mode = context.mode(),
23871 center = map.center(),
23873 precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)),
23874 q = _.omit(iD.util.stringQs(location.hash.substring(1)), 'comment'),
23877 if (mode && mode.id === 'browse') {
23880 var selected = context.selectedIDs().filter(function(id) {
23881 return !context.entity(id).isNew();
23883 if (selected.length) {
23884 newParams.id = selected.join(',');
23888 newParams.map = zoom.toFixed(2) +
23889 '/' + center[0].toFixed(precision) +
23890 '/' + center[1].toFixed(precision);
23892 return '#' + iD.util.qsString(_.assign(q, newParams), true);
23895 function update() {
23896 if (context.inIntro()) return;
23897 var s1 = formatter(context.map());
23898 if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map!
23901 var throttledUpdate = _.throttle(update, 500);
23903 function hashchange() {
23904 if (location.hash === s0) return; // ignore spurious hashchange events
23905 if (parser(context.map(), (s0 = location.hash).substring(1))) {
23906 update(); // replace bogus hash
23912 .on('move.hash', throttledUpdate);
23915 .on('enter.hash', throttledUpdate);
23918 .on('hashchange.hash', hashchange);
23920 if (location.hash) {
23921 var q = iD.util.stringQs(location.hash.substring(1));
23922 if (q.id) context.zoomToEntity(q.id.split(',')[0], !q.map);
23923 if (q.comment) context.storage('comment', q.comment);
23925 if (q.map) hash.hadHash = true;
23929 hash.off = function() {
23930 throttledUpdate.cancel();
23933 .on('move.hash', null);
23936 .on('enter.hash', null);
23939 .on('hashchange.hash', null);
23941 location.hash = '';
23947 The hover behavior adds the `.hover` class on mouseover to all elements to which
23948 the identical datum is bound, and removes it on mouseout.
23950 The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
23951 representation may consist of several elements scattered throughout the DOM hierarchy.
23952 Only one of these elements can have the :hover pseudo-class, but all of them will
23953 have the .hover class.
23955 iD.behavior.Hover = function() {
23956 var dispatch = d3.dispatch('hover'),
23961 function keydown() {
23962 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
23963 dispatch.hover(null);
23964 selection.selectAll('.hover')
23965 .classed('hover-suppressed', true)
23966 .classed('hover', false);
23971 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
23972 dispatch.hover(target ? target.id : null);
23973 selection.selectAll('.hover-suppressed')
23974 .classed('hover-suppressed', false)
23975 .classed('hover', true);
23979 var hover = function(__) {
23982 function enter(d) {
23983 if (d === target) return;
23987 selection.selectAll('.hover')
23988 .classed('hover', false);
23989 selection.selectAll('.hover-suppressed')
23990 .classed('hover-suppressed', false);
23992 if (target instanceof iD.Entity) {
23993 var selector = '.' + target.id;
23995 if (target.type === 'relation') {
23996 target.members.forEach(function(member) {
23997 selector += ', .' + member.id;
24001 var suppressed = altDisables && d3.event && d3.event.altKey;
24003 selection.selectAll(selector)
24004 .classed(suppressed ? 'hover-suppressed' : 'hover', true);
24006 dispatch.hover(target.id);
24008 dispatch.hover(null);
24014 function mouseover() {
24016 var target = d3.event.target;
24017 enter(target ? target.__data__ : null);
24020 function mouseout() {
24022 var target = d3.event.relatedTarget;
24023 enter(target ? target.__data__ : null);
24026 function mousedown() {
24029 .on('mouseup.hover', mouseup);
24032 function mouseup() {
24037 .on('mouseover.hover', mouseover)
24038 .on('mouseout.hover', mouseout)
24039 .on('mousedown.hover', mousedown)
24040 .on('mouseup.hover', mouseup);
24043 .on('keydown.hover', keydown)
24044 .on('keyup.hover', keyup);
24047 hover.off = function(selection) {
24048 selection.selectAll('.hover')
24049 .classed('hover', false);
24050 selection.selectAll('.hover-suppressed')
24051 .classed('hover-suppressed', false);
24054 .on('mouseover.hover', null)
24055 .on('mouseout.hover', null)
24056 .on('mousedown.hover', null)
24057 .on('mouseup.hover', null);
24060 .on('keydown.hover', null)
24061 .on('keyup.hover', null)
24062 .on('mouseup.hover', null);
24065 hover.altDisables = function(_) {
24066 if (!arguments.length) return altDisables;
24071 return d3.rebind(hover, dispatch, 'on');
24073 iD.behavior.Lasso = function(context) {
24075 var behavior = function(selection) {
24079 function mousedown() {
24080 if (d3.event.shiftKey === true) {
24082 mouse = context.mouse();
24086 .on('mousemove.lasso', mousemove)
24087 .on('mouseup.lasso', mouseup);
24089 d3.event.stopPropagation();
24093 function mousemove() {
24095 lasso = iD.ui.Lasso(context).a(mouse);
24096 context.surface().call(lasso);
24099 lasso.b(context.mouse());
24102 function normalize(a, b) {
24104 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
24105 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
24108 function mouseup() {
24110 .on('mousemove.lasso', null)
24111 .on('mouseup.lasso', null);
24113 if (!lasso) return;
24115 var graph = context.graph(),
24116 extent = iD.geo.Extent(
24117 normalize(context.projection.invert(lasso.a()),
24118 context.projection.invert(lasso.b())));
24122 var selected = context.intersects(extent).filter(function(entity) {
24123 return entity.type === 'node' &&
24124 !context.features().isHidden(entity, graph, entity.geometry(graph));
24127 if (selected.length) {
24128 context.enter(iD.modes.Select(context, _.pluck(selected, 'id')));
24133 .on('mousedown.lasso', mousedown);
24136 behavior.off = function(selection) {
24137 selection.on('mousedown.lasso', null);
24142 iD.behavior.Paste = function(context) {
24143 var keybinding = d3.keybinding('paste');
24145 function omitTag(v, k) {
24153 k === 'description' ||
24154 k.indexOf('name') !== -1 ||
24155 k.indexOf('wiki') === 0 ||
24156 k.indexOf('addr:') === 0 ||
24157 k.indexOf('contact:') === 0
24161 function doPaste() {
24162 d3.event.preventDefault();
24163 if (context.inIntro()) return;
24165 var baseGraph = context.graph(),
24166 mouse = context.mouse(),
24167 projection = context.projection,
24168 viewport = iD.geo.Extent(projection.clipExtent()).polygon();
24170 if (!iD.geo.pointInPolygon(mouse, viewport)) return;
24172 var extent = iD.geo.Extent(),
24173 oldIDs = context.copyIDs(),
24174 oldGraph = context.copyGraph(),
24177 if (!oldIDs.length) return;
24179 var action = iD.actions.CopyEntities(oldIDs, oldGraph);
24180 context.perform(action);
24182 var copies = action.copies();
24183 for (var id in copies) {
24184 var oldEntity = oldGraph.entity(id),
24185 newEntity = copies[id];
24187 extent._extend(oldEntity.extent(oldGraph));
24188 newIDs.push(newEntity.id);
24189 context.perform(iD.actions.ChangeTags(newEntity.id, _.omit(newEntity.tags, omitTag)));
24192 // Put pasted objects where mouse pointer is..
24193 var center = projection(extent.center()),
24194 delta = [ mouse[0] - center[0], mouse[1] - center[1] ];
24196 context.perform(iD.actions.Move(newIDs, delta, projection));
24197 context.enter(iD.modes.Move(context, newIDs, baseGraph));
24201 keybinding.on(iD.ui.cmd('⌘V'), doPaste);
24202 d3.select(document).call(keybinding);
24206 paste.off = function() {
24207 d3.select(document).call(keybinding.off);
24212 iD.behavior.Select = function(context) {
24213 function keydown() {
24214 if (d3.event && d3.event.shiftKey) {
24216 .classed('behavior-multiselect', true);
24221 if (!d3.event || !d3.event.shiftKey) {
24223 .classed('behavior-multiselect', false);
24228 var datum = d3.event.target.__data__,
24229 lasso = d3.select('#surface .lasso').node(),
24230 mode = context.mode();
24232 if (!(datum instanceof iD.Entity)) {
24233 if (!d3.event.shiftKey && !lasso && mode.id !== 'browse')
24234 context.enter(iD.modes.Browse(context));
24236 } else if (!d3.event.shiftKey && !lasso) {
24237 // Avoid re-entering Select mode with same entity.
24238 if (context.selectedIDs().length !== 1 || context.selectedIDs()[0] !== datum.id) {
24239 context.enter(iD.modes.Select(context, [datum.id]));
24241 mode.suppressMenu(false).reselect();
24243 } else if (context.selectedIDs().indexOf(datum.id) >= 0) {
24244 var selectedIDs = _.without(context.selectedIDs(), datum.id);
24245 context.enter(selectedIDs.length ?
24246 iD.modes.Select(context, selectedIDs) :
24247 iD.modes.Browse(context));
24250 context.enter(iD.modes.Select(context, context.selectedIDs().concat([datum.id])));
24254 var behavior = function(selection) {
24256 .on('keydown.select', keydown)
24257 .on('keyup.select', keyup);
24259 selection.on('click.select', click);
24264 behavior.off = function(selection) {
24266 .on('keydown.select', null)
24267 .on('keyup.select', null);
24269 selection.on('click.select', null);
24276 iD.behavior.Tail = function() {
24280 tooltipSize = [0, 0],
24281 selectionSize = [0, 0];
24283 function tail(selection) {
24287 .on('resize.tail', function() { selectionSize = selection.dimensions(); });
24290 container.style('display', 'block');
24291 tooltipSize = container.dimensions();
24294 function mousemove() {
24295 if (container.style('display') === 'none') show();
24296 var xoffset = ((d3.event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
24297 -tooltipSize[0] - xmargin : xmargin;
24298 container.classed('left', xoffset > 0);
24299 iD.util.setTransform(container, d3.event.clientX + xoffset, d3.event.clientY);
24302 function mouseleave() {
24303 if (d3.event.relatedTarget !== container.node()) {
24304 container.style('display', 'none');
24308 function mouseenter() {
24309 if (d3.event.relatedTarget !== container.node()) {
24314 container = d3.select(document.body)
24316 .style('display', 'none')
24317 .attr('class', 'tail tooltip-inner');
24319 container.append('div')
24323 .on('mousemove.tail', mousemove)
24324 .on('mouseenter.tail', mouseenter)
24325 .on('mouseleave.tail', mouseleave);
24328 .on('mousemove.tail', mousemove);
24330 tooltipSize = container.dimensions();
24331 selectionSize = selection.dimensions();
24334 tail.off = function(selection) {
24338 .on('mousemove.tail', null)
24342 .on('mousemove.tail', null)
24343 .on('mouseenter.tail', null)
24344 .on('mouseleave.tail', null);
24347 .on('resize.tail', null);
24350 tail.text = function(_) {
24351 if (!arguments.length) return text;
24359 iD.modes.AddArea = function(context) {
24363 title: t('modes.add_area.title'),
24364 description: t('modes.add_area.description'),
24368 var behavior = iD.behavior.AddWay(context)
24369 .tail(t('modes.add_area.tail'))
24370 .on('start', start)
24371 .on('startFromWay', startFromWay)
24372 .on('startFromNode', startFromNode),
24373 defaultTags = {area: 'yes'};
24375 function start(loc) {
24376 var graph = context.graph(),
24377 node = iD.Node({loc: loc}),
24378 way = iD.Way({tags: defaultTags});
24381 iD.actions.AddEntity(node),
24382 iD.actions.AddEntity(way),
24383 iD.actions.AddVertex(way.id, node.id),
24384 iD.actions.AddVertex(way.id, node.id));
24386 context.enter(iD.modes.DrawArea(context, way.id, graph));
24389 function startFromWay(loc, edge) {
24390 var graph = context.graph(),
24391 node = iD.Node({loc: loc}),
24392 way = iD.Way({tags: defaultTags});
24395 iD.actions.AddEntity(node),
24396 iD.actions.AddEntity(way),
24397 iD.actions.AddVertex(way.id, node.id),
24398 iD.actions.AddVertex(way.id, node.id),
24399 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
24401 context.enter(iD.modes.DrawArea(context, way.id, graph));
24404 function startFromNode(node) {
24405 var graph = context.graph(),
24406 way = iD.Way({tags: defaultTags});
24409 iD.actions.AddEntity(way),
24410 iD.actions.AddVertex(way.id, node.id),
24411 iD.actions.AddVertex(way.id, node.id));
24413 context.enter(iD.modes.DrawArea(context, way.id, graph));
24416 mode.enter = function() {
24417 context.install(behavior);
24420 mode.exit = function() {
24421 context.uninstall(behavior);
24426 iD.modes.AddLine = function(context) {
24430 title: t('modes.add_line.title'),
24431 description: t('modes.add_line.description'),
24435 var behavior = iD.behavior.AddWay(context)
24436 .tail(t('modes.add_line.tail'))
24437 .on('start', start)
24438 .on('startFromWay', startFromWay)
24439 .on('startFromNode', startFromNode);
24441 function start(loc) {
24442 var baseGraph = context.graph(),
24443 node = iD.Node({loc: loc}),
24447 iD.actions.AddEntity(node),
24448 iD.actions.AddEntity(way),
24449 iD.actions.AddVertex(way.id, node.id));
24451 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24454 function startFromWay(loc, edge) {
24455 var baseGraph = context.graph(),
24456 node = iD.Node({loc: loc}),
24460 iD.actions.AddEntity(node),
24461 iD.actions.AddEntity(way),
24462 iD.actions.AddVertex(way.id, node.id),
24463 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
24465 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24468 function startFromNode(node) {
24469 var baseGraph = context.graph(),
24473 iD.actions.AddEntity(way),
24474 iD.actions.AddVertex(way.id, node.id));
24476 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24479 mode.enter = function() {
24480 context.install(behavior);
24483 mode.exit = function() {
24484 context.uninstall(behavior);
24489 iD.modes.AddPoint = function(context) {
24493 title: t('modes.add_point.title'),
24494 description: t('modes.add_point.description'),
24498 var behavior = iD.behavior.Draw(context)
24499 .tail(t('modes.add_point.tail'))
24501 .on('clickWay', addWay)
24502 .on('clickNode', addNode)
24503 .on('cancel', cancel)
24504 .on('finish', cancel);
24506 function add(loc) {
24507 var node = iD.Node({loc: loc});
24510 iD.actions.AddEntity(node),
24511 t('operations.add.annotation.point'));
24514 iD.modes.Select(context, [node.id])
24515 .suppressMenu(true)
24516 .newFeature(true));
24519 function addWay(loc) {
24523 function addNode(node) {
24527 function cancel() {
24528 context.enter(iD.modes.Browse(context));
24531 mode.enter = function() {
24532 context.install(behavior);
24535 mode.exit = function() {
24536 context.uninstall(behavior);
24541 iD.modes.Browse = function(context) {
24545 title: t('modes.browse.title'),
24546 description: t('modes.browse.description')
24550 iD.behavior.Paste(context),
24551 iD.behavior.Hover(context)
24552 .on('hover', context.ui().sidebar.hover),
24553 iD.behavior.Select(context),
24554 iD.behavior.Lasso(context),
24555 iD.modes.DragNode(context).behavior];
24557 mode.enter = function() {
24558 behaviors.forEach(function(behavior) {
24559 context.install(behavior);
24562 // Get focus on the body.
24563 if (document.activeElement && document.activeElement.blur) {
24564 document.activeElement.blur();
24568 context.ui().sidebar.show(sidebar);
24570 context.ui().sidebar.select(null);
24574 mode.exit = function() {
24575 context.ui().sidebar.hover.cancel();
24576 behaviors.forEach(function(behavior) {
24577 context.uninstall(behavior);
24581 context.ui().sidebar.hide();
24585 mode.sidebar = function(_) {
24586 if (!arguments.length) return sidebar;
24593 iD.modes.DragNode = function(context) {
24604 hover = iD.behavior.Hover(context)
24606 .on('hover', context.ui().sidebar.hover),
24607 edit = iD.behavior.Edit(context);
24609 function edge(point, size) {
24610 var pad = [30, 100, 30, 100];
24611 if (point[0] > size[0] - pad[0]) return [-10, 0];
24612 else if (point[0] < pad[2]) return [10, 0];
24613 else if (point[1] > size[1] - pad[1]) return [0, -10];
24614 else if (point[1] < pad[3]) return [0, 10];
24618 function startNudge(nudge) {
24619 if (nudgeInterval) window.clearInterval(nudgeInterval);
24620 nudgeInterval = window.setInterval(function() {
24621 context.pan(nudge);
24625 function stopNudge() {
24626 if (nudgeInterval) window.clearInterval(nudgeInterval);
24627 nudgeInterval = null;
24630 function moveAnnotation(entity) {
24631 return t('operations.move.annotation.' + entity.geometry(context.graph()));
24634 function connectAnnotation(entity) {
24635 return t('operations.connect.annotation.' + entity.geometry(context.graph()));
24638 function origin(entity) {
24639 return context.projection(entity.loc);
24642 function start(entity) {
24643 cancelled = d3.event.sourceEvent.shiftKey ||
24644 context.features().hasHiddenConnections(entity, context.graph());
24646 if (cancelled) return behavior.cancel();
24648 wasMidpoint = entity.type === 'midpoint';
24650 var midpoint = entity;
24651 entity = iD.Node();
24652 context.perform(iD.actions.AddMidpoint(midpoint, entity));
24654 var vertex = context.surface()
24655 .selectAll('.' + entity.id);
24656 behavior.target(vertex.node(), entity);
24660 iD.actions.Noop());
24663 activeIDs = _.pluck(context.graph().parentWays(entity), 'id');
24664 activeIDs.push(entity.id);
24666 context.enter(mode);
24670 if (d3.event.sourceEvent.altKey) {
24674 return d3.event.sourceEvent.target.__data__ || {};
24677 // via https://gist.github.com/shawnbot/4166283
24678 function childOf(p, c) {
24679 if (p === c) return false;
24680 while (c && c !== p) c = c.parentNode;
24684 function move(entity) {
24685 if (cancelled) return;
24686 d3.event.sourceEvent.stopPropagation();
24688 var nudge = childOf(context.container().node(),
24689 d3.event.sourceEvent.toElement) &&
24690 edge(d3.event.point, context.map().dimensions());
24692 if (nudge) startNudge(nudge);
24695 var loc = context.map().mouseCoordinates();
24698 if (d.type === 'node' && d.id !== entity.id) {
24700 } else if (d.type === 'way' && !d3.select(d3.event.sourceEvent.target).classed('fill')) {
24701 loc = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
24705 iD.actions.MoveNode(entity.id, loc),
24706 moveAnnotation(entity));
24709 function end(entity) {
24710 if (cancelled) return;
24714 if (d.type === 'way') {
24715 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection);
24717 iD.actions.AddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
24718 connectAnnotation(d));
24720 } else if (d.type === 'node' && d.id !== entity.id) {
24722 iD.actions.Connect([d.id, entity.id]),
24723 connectAnnotation(d));
24725 } else if (wasMidpoint) {
24728 t('operations.add.annotation.vertex'));
24733 moveAnnotation(entity));
24736 var reselection = selectedIDs.filter(function(id) {
24737 return context.graph().hasEntity(id);
24740 if (reselection.length) {
24742 iD.modes.Select(context, reselection)
24743 .suppressMenu(true));
24745 context.enter(iD.modes.Browse(context));
24749 function cancel() {
24751 context.enter(iD.modes.Browse(context));
24754 function setActiveElements() {
24755 context.surface().selectAll(iD.util.entitySelector(activeIDs))
24756 .classed('active', true);
24759 var behavior = iD.behavior.drag()
24760 .delegate('g.node, g.point, g.midpoint')
24761 .surface(context.surface().node())
24763 .on('start', start)
24767 mode.enter = function() {
24768 context.install(hover);
24769 context.install(edit);
24772 .on('undone.drag-node', cancel);
24775 .on('drawn.drag-node', setActiveElements);
24777 setActiveElements();
24780 mode.exit = function() {
24781 context.ui().sidebar.hover.cancel();
24782 context.uninstall(hover);
24783 context.uninstall(edit);
24786 .on('undone.drag-node', null);
24789 .on('drawn.drag-node', null);
24792 .selectAll('.active')
24793 .classed('active', false);
24798 mode.selectedIDs = function(_) {
24799 if (!arguments.length) return selectedIDs;
24804 mode.behavior = behavior;
24808 iD.modes.DrawArea = function(context, wayId, baseGraph) {
24816 mode.enter = function() {
24817 var way = context.entity(wayId),
24818 headId = way.nodes[way.nodes.length - 2],
24819 tailId = way.first();
24821 behavior = iD.behavior.DrawWay(context, wayId, -1, mode, baseGraph)
24822 .tail(t('modes.draw_area.tail'));
24824 var addNode = behavior.addNode;
24826 behavior.addNode = function(node) {
24827 if (node.id === headId || node.id === tailId) {
24834 context.install(behavior);
24837 mode.exit = function() {
24838 context.uninstall(behavior);
24841 mode.selectedIDs = function() {
24847 iD.modes.DrawLine = function(context, wayId, baseGraph, affix) {
24855 mode.enter = function() {
24856 var way = context.entity(wayId),
24857 index = (affix === 'prefix') ? 0 : undefined,
24858 headId = (affix === 'prefix') ? way.first() : way.last();
24860 behavior = iD.behavior.DrawWay(context, wayId, index, mode, baseGraph)
24861 .tail(t('modes.draw_line.tail'));
24863 var addNode = behavior.addNode;
24865 behavior.addNode = function(node) {
24866 if (node.id === headId) {
24873 context.install(behavior);
24876 mode.exit = function() {
24877 context.uninstall(behavior);
24880 mode.selectedIDs = function() {
24886 iD.modes.Move = function(context, entityIDs, baseGraph) {
24892 var keybinding = d3.keybinding('move'),
24893 edit = iD.behavior.Edit(context),
24894 annotation = entityIDs.length === 1 ?
24895 t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
24896 t('operations.move.annotation.multiple'),
24901 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
24903 function edge(point, size) {
24904 var pad = [30, 100, 30, 100];
24905 if (point[0] > size[0] - pad[0]) return [-10, 0];
24906 else if (point[0] < pad[2]) return [10, 0];
24907 else if (point[1] > size[1] - pad[1]) return [0, -10];
24908 else if (point[1] < pad[3]) return [0, 10];
24912 function startNudge(nudge) {
24913 if (nudgeInterval) window.clearInterval(nudgeInterval);
24914 nudgeInterval = window.setInterval(function() {
24915 context.pan(nudge);
24917 var currMouse = context.mouse(),
24918 origMouse = context.projection(origin),
24919 delta = vecSub(vecSub(currMouse, origMouse), nudge),
24920 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
24922 context.overwrite(action, annotation);
24927 function stopNudge() {
24928 if (nudgeInterval) window.clearInterval(nudgeInterval);
24929 nudgeInterval = null;
24933 var currMouse = context.mouse(),
24934 origMouse = context.projection(origin),
24935 delta = vecSub(currMouse, origMouse),
24936 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
24938 context.overwrite(action, annotation);
24940 var nudge = edge(currMouse, context.map().dimensions());
24941 if (nudge) startNudge(nudge);
24945 function finish() {
24946 d3.event.stopPropagation();
24947 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
24951 function cancel() {
24953 while (context.graph() !== baseGraph) context.pop();
24954 context.enter(iD.modes.Browse(context));
24957 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
24962 function undone() {
24963 context.enter(iD.modes.Browse(context));
24966 mode.enter = function() {
24967 origin = context.map().mouseCoordinates();
24970 context.install(edit);
24977 .on('mousemove.move', move)
24978 .on('click.move', finish);
24981 .on('undone.move', undone);
24987 d3.select(document)
24991 mode.exit = function() {
24994 context.uninstall(edit);
24997 .on('mousemove.move', null)
24998 .on('click.move', null);
25001 .on('undone.move', null);
25008 iD.modes.RotateWay = function(context, wayId) {
25014 var keybinding = d3.keybinding('rotate-way'),
25015 edit = iD.behavior.Edit(context);
25017 mode.enter = function() {
25018 context.install(edit);
25020 var annotation = t('operations.rotate.annotation.' + context.geometry(wayId)),
25021 way = context.graph().entity(wayId),
25022 nodes = _.uniq(context.graph().childNodes(way)),
25023 points = nodes.map(function(n) { return context.projection(n.loc); }),
25024 pivot = d3.geom.polygon(points).centroid(),
25031 function rotate() {
25033 var mousePoint = context.mouse(),
25034 newAngle = Math.atan2(mousePoint[1] - pivot[1], mousePoint[0] - pivot[0]);
25036 if (typeof angle === 'undefined') angle = newAngle;
25039 iD.actions.RotateWay(wayId, pivot, newAngle - angle, context.projection),
25045 function finish() {
25046 d3.event.stopPropagation();
25047 context.enter(iD.modes.Select(context, [wayId])
25048 .suppressMenu(true));
25051 function cancel() {
25053 context.enter(iD.modes.Select(context, [wayId])
25054 .suppressMenu(true));
25057 function undone() {
25058 context.enter(iD.modes.Browse(context));
25062 .on('mousemove.rotate-way', rotate)
25063 .on('click.rotate-way', finish);
25066 .on('undone.rotate-way', undone);
25072 d3.select(document)
25076 mode.exit = function() {
25077 context.uninstall(edit);
25080 .on('mousemove.rotate-way', null)
25081 .on('click.rotate-way', null);
25084 .on('undone.rotate-way', null);
25091 iD.modes.Save = function(context) {
25092 var ui = iD.ui.Commit(context)
25093 .on('cancel', cancel)
25096 function cancel() {
25097 context.enter(iD.modes.Browse(context));
25100 function save(e, tryAgain) {
25101 function withChildNodes(ids, graph) {
25102 return _.uniq(_.reduce(ids, function(result, id) {
25103 var e = graph.entity(id);
25104 if (e.type === 'way') {
25106 var cn = graph.childNodes(e);
25107 result.push.apply(result, _.pluck(_.filter(cn, 'version'), 'id'));
25109 /* eslint-disable no-console */
25110 if (typeof console !== 'undefined') console.error(err);
25111 /* eslint-enable no-console */
25118 var loading = iD.ui.Loading(context).message(t('save.uploading')).blocking(true),
25119 history = context.history(),
25120 origChanges = history.changes(iD.actions.DiscardTags(history.difference())),
25121 localGraph = context.graph(),
25122 remoteGraph = iD.Graph(history.base(), true),
25123 modified = _.filter(history.difference().summary(), {changeType: 'modified'}),
25124 toCheck = _.pluck(_.pluck(modified, 'entity'), 'id'),
25125 toLoad = withChildNodes(toCheck, localGraph),
25129 if (!tryAgain) history.perform(iD.actions.Noop()); // checkpoint
25130 context.container().call(loading);
25132 if (toCheck.length) {
25133 context.connection().loadMultiple(toLoad, loaded);
25139 // Reload modified entities into an alternate graph and check for conflicts..
25140 function loaded(err, result) {
25141 if (errors.length) return;
25145 msg: err.responseText,
25146 details: [ t('save.status_code', { code: err.status }) ]
25152 _.each(result.data, function(entity) {
25153 remoteGraph.replace(entity);
25154 toLoad = _.without(toLoad, entity.id);
25156 // Because loadMultiple doesn't download /full like loadEntity,
25157 // need to also load children that aren't already being checked..
25158 if (!entity.visible) return;
25159 if (entity.type === 'way') {
25160 loadMore.push.apply(loadMore,
25161 _.difference(entity.nodes, toCheck, toLoad, loadMore));
25162 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
25163 loadMore.push.apply(loadMore,
25164 _.difference(_.pluck(entity.members, 'id'), toCheck, toLoad, loadMore));
25168 if (loadMore.length) {
25169 toLoad.push.apply(toLoad, loadMore);
25170 context.connection().loadMultiple(loadMore, loaded);
25173 if (!toLoad.length) {
25180 function checkConflicts() {
25181 function choice(id, text, action) {
25182 return { id: id, text: text, action: function() { history.replace(action); } };
25184 function formatUser(d) {
25185 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
25187 function entityName(entity) {
25188 return iD.util.displayName(entity) || (iD.util.displayType(entity.id) + ' ' + entity.id);
25191 function compareVersions(local, remote) {
25192 if (local.version !== remote.version) return false;
25194 if (local.type === 'way') {
25195 var children = _.union(local.nodes, remote.nodes);
25197 for (var i = 0; i < children.length; i++) {
25198 var a = localGraph.hasEntity(children[i]),
25199 b = remoteGraph.hasEntity(children[i]);
25201 if (a && b && a.version !== b.version) return false;
25208 _.each(toCheck, function(id) {
25209 var local = localGraph.entity(id),
25210 remote = remoteGraph.entity(id);
25212 if (compareVersions(local, remote)) return;
25214 var action = iD.actions.MergeRemoteChanges,
25215 merge = action(id, localGraph, remoteGraph, formatUser);
25217 history.replace(merge);
25219 var mergeConflicts = merge.conflicts();
25220 if (!mergeConflicts.length) return; // merged safely
25222 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
25223 forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
25224 keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
25225 keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
25229 name: entityName(local),
25230 details: mergeConflicts,
25233 choice(id, keepMine, forceLocal),
25234 choice(id, keepTheirs, forceRemote)
25243 function finalize() {
25244 if (conflicts.length) {
25245 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
25247 } else if (errors.length) {
25250 var changes = history.changes(iD.actions.DiscardTags(history.difference()));
25251 if (changes.modified.length || changes.created.length || changes.deleted.length) {
25252 context.connection().putChangeset(
25255 history.imageryUsed(),
25256 function(err, changeset_id) {
25259 msg: err.responseText,
25260 details: [ t('save.status_code', { code: err.status }) ]
25264 history.clearSaved();
25265 success(e, changeset_id);
25266 // Add delay to allow for postgres replication #1646 #2678
25267 window.setTimeout(function() {
25273 } else { // changes were insignificant or reverted by user
25282 function showConflicts() {
25283 var selection = context.container()
25284 .select('#sidebar')
25286 .attr('class','sidebar-component');
25290 selection.call(iD.ui.Conflicts(context)
25292 .on('download', function() {
25293 var data = JXON.stringify(context.connection().osmChangeJXON('CHANGEME', origChanges)),
25294 win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
25297 .on('cancel', function() {
25299 selection.remove();
25301 .on('save', function() {
25302 for (var i = 0; i < conflicts.length; i++) {
25303 if (conflicts[i].chosen === 1) { // user chose "keep theirs"
25304 var entity = context.hasEntity(conflicts[i].id);
25305 if (entity && entity.type === 'way') {
25306 var children = _.uniq(entity.nodes);
25307 for (var j = 0; j < children.length; j++) {
25308 history.replace(iD.actions.Revert(children[j]));
25311 history.replace(iD.actions.Revert(conflicts[i].id));
25315 selection.remove();
25322 function showErrors() {
25323 var selection = iD.ui.confirm(context.container());
25329 .select('.modal-section.header')
25331 .text(t('save.error'));
25333 addErrors(selection, errors);
25334 selection.okButton();
25338 function addErrors(selection, data) {
25339 var message = selection
25340 .select('.modal-section.message-text');
25342 var items = message
25343 .selectAll('.error-container')
25346 var enter = items.enter()
25348 .attr('class', 'error-container');
25352 .attr('class', 'error-description')
25354 .classed('hide-toggle', true)
25355 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
25356 .on('click', function() {
25357 var error = d3.select(this),
25358 detail = d3.select(this.nextElementSibling),
25359 exp = error.classed('expanded');
25361 detail.style('display', exp ? 'none' : 'block');
25362 error.classed('expanded', !exp);
25364 d3.event.preventDefault();
25367 var details = enter
25369 .attr('class', 'error-detail-container')
25370 .style('display', 'none');
25374 .attr('class', 'error-detail-list')
25376 .data(function(d) { return d.details || []; })
25379 .attr('class', 'error-detail-item')
25380 .text(function(d) { return d; });
25389 function success(e, changeset_id) {
25390 context.enter(iD.modes.Browse(context)
25391 .sidebar(iD.ui.Success(context)
25396 .on('cancel', function() {
25397 context.ui().sidebar.hide();
25405 mode.enter = function() {
25406 context.connection().authenticate(function(err) {
25410 context.ui().sidebar.show(ui);
25415 mode.exit = function() {
25416 context.ui().sidebar.hide();
25421 iD.modes.Select = function(context, selectedIDs) {
25427 var keybinding = d3.keybinding('select'),
25430 iD.behavior.Copy(context),
25431 iD.behavior.Paste(context),
25432 iD.behavior.Breathe(context),
25433 iD.behavior.Hover(context),
25434 iD.behavior.Select(context),
25435 iD.behavior.Lasso(context),
25436 iD.modes.DragNode(context)
25437 .selectedIDs(selectedIDs)
25441 newFeature = false,
25442 suppressMenu = false;
25444 var wrap = context.container()
25445 .select('.inspector-wrap');
25448 function singular() {
25449 if (selectedIDs.length === 1) {
25450 return context.hasEntity(selectedIDs[0]);
25454 function closeMenu() {
25456 context.surface().call(radialMenu.close);
25460 function positionMenu() {
25461 if (suppressMenu || !radialMenu) { return; }
25463 var entity = singular();
25464 if (entity && context.geometry(entity.id) === 'relation') {
25465 suppressMenu = true;
25466 } else if (entity && entity.type === 'node') {
25467 radialMenu.center(context.projection(entity.loc));
25469 var point = context.mouse(),
25470 viewport = iD.geo.Extent(context.projection.clipExtent()).polygon();
25471 if (iD.geo.pointInPolygon(point, viewport)) {
25472 radialMenu.center(point);
25474 suppressMenu = true;
25479 function showMenu() {
25481 if (!suppressMenu && radialMenu) {
25482 context.surface().call(radialMenu);
25486 function toggleMenu() {
25487 if (d3.select('.radial-menu').empty()) {
25494 mode.selectedIDs = function() {
25495 return selectedIDs;
25498 mode.reselect = function() {
25499 var surfaceNode = context.surface().node();
25500 if (surfaceNode.focus) { // FF doesn't support it
25501 surfaceNode.focus();
25508 mode.newFeature = function(_) {
25509 if (!arguments.length) return newFeature;
25514 mode.suppressMenu = function(_) {
25515 if (!arguments.length) return suppressMenu;
25520 mode.enter = function() {
25521 function update() {
25523 if (_.any(selectedIDs, function(id) { return !context.hasEntity(id); })) {
25524 // Exit mode if selected entity gets undone
25525 context.enter(iD.modes.Browse(context));
25529 function dblclick() {
25530 var target = d3.select(d3.event.target),
25531 datum = target.datum();
25533 if (datum instanceof iD.Way && !target.classed('fill')) {
25534 var choice = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection),
25537 var prev = datum.nodes[choice.index - 1],
25538 next = datum.nodes[choice.index];
25541 iD.actions.AddMidpoint({loc: choice.loc, edge: [prev, next]}, node),
25542 t('operations.add.annotation.vertex'));
25544 d3.event.preventDefault();
25545 d3.event.stopPropagation();
25549 function selectElements(drawn) {
25550 var entity = singular();
25551 if (entity && context.geometry(entity.id) === 'relation') {
25552 suppressMenu = true;
25556 var selection = context.surface()
25557 .selectAll(iD.util.entityOrMemberSelector(selectedIDs, context.graph()));
25559 if (selection.empty()) {
25560 if (drawn) { // Exit mode if selected DOM elements have disappeared..
25561 context.enter(iD.modes.Browse(context));
25565 .classed('selected', true);
25570 if (!context.inIntro()) {
25571 context.enter(iD.modes.Browse(context));
25576 behaviors.forEach(function(behavior) {
25577 context.install(behavior);
25580 var operations = _.without(d3.values(iD.operations), iD.operations.Delete)
25581 .map(function(o) { return o(selectedIDs, context); })
25582 .filter(function(o) { return o.available(); });
25584 operations.unshift(iD.operations.Delete(selectedIDs, context));
25587 .on('⎋', esc, true)
25588 .on('space', toggleMenu);
25590 operations.forEach(function(operation) {
25591 operation.keys.forEach(function(key) {
25592 keybinding.on(key, function() {
25593 if (!(context.inIntro() || operation.disabled())) {
25600 d3.select(document)
25603 radialMenu = iD.ui.RadialMenu(context, operations);
25605 context.ui().sidebar
25606 .select(singular() ? singular().id : null, newFeature);
25609 .on('undone.select', update)
25610 .on('redone.select', update);
25613 .on('move.select', closeMenu)
25614 .on('drawn.select', selectElements);
25618 var show = d3.event && !suppressMenu;
25624 timeout = window.setTimeout(function() {
25630 .on('dblclick.select', dblclick);
25633 if (selectedIDs.length > 1) {
25634 var entities = iD.ui.SelectionList(context, selectedIDs);
25635 context.ui().sidebar.show(entities);
25639 mode.exit = function() {
25640 if (timeout) window.clearTimeout(timeout);
25642 if (inspector) wrap.call(inspector.close);
25644 behaviors.forEach(function(behavior) {
25645 context.uninstall(behavior);
25650 radialMenu = undefined;
25653 .on('undone.select', null)
25654 .on('redone.select', null);
25657 .on('dblclick.select', null)
25658 .selectAll('.selected')
25659 .classed('selected', false);
25661 context.map().on('drawn.select', null);
25662 context.ui().sidebar.hide();
25667 iD.operations = {};
25668 iD.operations.Circularize = function(selectedIDs, context) {
25669 var entityId = selectedIDs[0],
25670 entity = context.entity(entityId),
25671 extent = entity.extent(context.graph()),
25672 geometry = context.geometry(entityId),
25673 action = iD.actions.Circularize(entityId, context.projection);
25675 var operation = function() {
25676 var annotation = t('operations.circularize.annotation.' + geometry);
25677 context.perform(action, annotation);
25680 operation.available = function() {
25681 return selectedIDs.length === 1 &&
25682 entity.type === 'way' &&
25683 _.uniq(entity.nodes).length > 1;
25686 operation.disabled = function() {
25688 if (extent.percentContainedIn(context.extent()) < 0.8) {
25689 reason = 'too_large';
25690 } else if (context.hasHiddenConnections(entityId)) {
25691 reason = 'connected_to_hidden';
25693 return action.disabled(context.graph()) || reason;
25696 operation.tooltip = function() {
25697 var disable = operation.disabled();
25699 t('operations.circularize.' + disable) :
25700 t('operations.circularize.description.' + geometry);
25703 operation.id = 'circularize';
25704 operation.keys = [t('operations.circularize.key')];
25705 operation.title = t('operations.circularize.title');
25709 iD.operations.Continue = function(selectedIDs, context) {
25710 var graph = context.graph(),
25711 entities = selectedIDs.map(function(id) { return graph.entity(id); }),
25712 geometries = _.extend({line: [], vertex: []},
25713 _.groupBy(entities, function(entity) { return entity.geometry(graph); })),
25714 vertex = geometries.vertex[0];
25716 function candidateWays() {
25717 return graph.parentWays(vertex).filter(function(parent) {
25718 return parent.geometry(graph) === 'line' &&
25719 parent.affix(vertex.id) &&
25720 (geometries.line.length === 0 || geometries.line[0] === parent);
25724 var operation = function() {
25725 var candidate = candidateWays()[0];
25726 context.enter(iD.modes.DrawLine(
25730 candidate.affix(vertex.id)));
25733 operation.available = function() {
25734 return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
25735 !context.features().hasHiddenConnections(vertex, context.graph());
25738 operation.disabled = function() {
25739 var candidates = candidateWays();
25740 if (candidates.length === 0)
25741 return 'not_eligible';
25742 if (candidates.length > 1)
25746 operation.tooltip = function() {
25747 var disable = operation.disabled();
25749 t('operations.continue.' + disable) :
25750 t('operations.continue.description');
25753 operation.id = 'continue';
25754 operation.keys = [t('operations.continue.key')];
25755 operation.title = t('operations.continue.title');
25759 iD.operations.Delete = function(selectedIDs, context) {
25760 var action = iD.actions.DeleteMultiple(selectedIDs);
25762 var operation = function() {
25766 if (selectedIDs.length > 1) {
25767 annotation = t('operations.delete.annotation.multiple', {n: selectedIDs.length});
25770 var id = selectedIDs[0],
25771 entity = context.entity(id),
25772 geometry = context.geometry(id),
25773 parents = context.graph().parentWays(entity),
25774 parent = parents[0];
25776 annotation = t('operations.delete.annotation.' + geometry);
25778 // Select the next closest node in the way.
25779 if (geometry === 'vertex' && parents.length === 1 && parent.nodes.length > 2) {
25780 var nodes = parent.nodes,
25781 i = nodes.indexOf(id);
25785 } else if (i === nodes.length - 1) {
25788 var a = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
25789 b = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
25790 i = a < b ? i - 1 : i + 1;
25793 nextSelectedID = nodes[i];
25797 if (nextSelectedID && context.hasEntity(nextSelectedID)) {
25798 context.enter(iD.modes.Select(context, [nextSelectedID]));
25800 context.enter(iD.modes.Browse(context));
25808 operation.available = function() {
25812 operation.disabled = function() {
25814 if (_.any(selectedIDs, context.hasHiddenConnections)) {
25815 reason = 'connected_to_hidden';
25817 return action.disabled(context.graph()) || reason;
25820 operation.tooltip = function() {
25821 var disable = operation.disabled();
25823 t('operations.delete.' + disable) :
25824 t('operations.delete.description');
25827 operation.id = 'delete';
25828 operation.keys = [iD.ui.cmd('⌘⌫'), iD.ui.cmd('⌘⌦')];
25829 operation.title = t('operations.delete.title');
25833 iD.operations.Disconnect = function(selectedIDs, context) {
25834 var vertices = _.filter(selectedIDs, function vertex(entityId) {
25835 return context.geometry(entityId) === 'vertex';
25838 var entityId = vertices[0],
25839 action = iD.actions.Disconnect(entityId);
25841 if (selectedIDs.length > 1) {
25842 action.limitWays(_.without(selectedIDs, entityId));
25845 var operation = function() {
25846 context.perform(action, t('operations.disconnect.annotation'));
25849 operation.available = function() {
25850 return vertices.length === 1;
25853 operation.disabled = function() {
25855 if (_.any(selectedIDs, context.hasHiddenConnections)) {
25856 reason = 'connected_to_hidden';
25858 return action.disabled(context.graph()) || reason;
25861 operation.tooltip = function() {
25862 var disable = operation.disabled();
25864 t('operations.disconnect.' + disable) :
25865 t('operations.disconnect.description');
25868 operation.id = 'disconnect';
25869 operation.keys = [t('operations.disconnect.key')];
25870 operation.title = t('operations.disconnect.title');
25874 iD.operations.Merge = function(selectedIDs, context) {
25875 var join = iD.actions.Join(selectedIDs),
25876 merge = iD.actions.Merge(selectedIDs),
25877 mergePolygon = iD.actions.MergePolygon(selectedIDs);
25879 var operation = function() {
25880 var annotation = t('operations.merge.annotation', {n: selectedIDs.length}),
25883 if (!join.disabled(context.graph())) {
25885 } else if (!merge.disabled(context.graph())) {
25888 action = mergePolygon;
25891 context.perform(action, annotation);
25892 context.enter(iD.modes.Select(context, selectedIDs.filter(function(id) { return context.hasEntity(id); }))
25893 .suppressMenu(true));
25896 operation.available = function() {
25897 return selectedIDs.length >= 2;
25900 operation.disabled = function() {
25901 return join.disabled(context.graph()) &&
25902 merge.disabled(context.graph()) &&
25903 mergePolygon.disabled(context.graph());
25906 operation.tooltip = function() {
25907 var j = join.disabled(context.graph()),
25908 m = merge.disabled(context.graph()),
25909 p = mergePolygon.disabled(context.graph());
25911 if (j === 'restriction' && m && p)
25912 return t('operations.merge.restriction', {relation: context.presets().item('type/restriction').name()});
25914 if (p === 'incomplete_relation' && j && m)
25915 return t('operations.merge.incomplete_relation');
25918 return t('operations.merge.' + j);
25920 return t('operations.merge.description');
25923 operation.id = 'merge';
25924 operation.keys = [t('operations.merge.key')];
25925 operation.title = t('operations.merge.title');
25929 iD.operations.Move = function(selectedIDs, context) {
25930 var extent = selectedIDs.reduce(function(extent, id) {
25931 return extent.extend(context.entity(id).extent(context.graph()));
25932 }, iD.geo.Extent());
25934 var operation = function() {
25935 context.enter(iD.modes.Move(context, selectedIDs));
25938 operation.available = function() {
25939 return selectedIDs.length > 1 ||
25940 context.entity(selectedIDs[0]).type !== 'node';
25943 operation.disabled = function() {
25945 if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
25946 reason = 'too_large';
25947 } else if (_.any(selectedIDs, context.hasHiddenConnections)) {
25948 reason = 'connected_to_hidden';
25950 return iD.actions.Move(selectedIDs).disabled(context.graph()) || reason;
25953 operation.tooltip = function() {
25954 var disable = operation.disabled();
25956 t('operations.move.' + disable) :
25957 t('operations.move.description');
25960 operation.id = 'move';
25961 operation.keys = [t('operations.move.key')];
25962 operation.title = t('operations.move.title');
25966 iD.operations.Orthogonalize = function(selectedIDs, context) {
25967 var entityId = selectedIDs[0],
25968 entity = context.entity(entityId),
25969 extent = entity.extent(context.graph()),
25970 geometry = context.geometry(entityId),
25971 action = iD.actions.Orthogonalize(entityId, context.projection);
25973 var operation = function() {
25974 var annotation = t('operations.orthogonalize.annotation.' + geometry);
25975 context.perform(action, annotation);
25978 operation.available = function() {
25979 return selectedIDs.length === 1 &&
25980 entity.type === 'way' &&
25981 entity.isClosed() &&
25982 _.uniq(entity.nodes).length > 2;
25985 operation.disabled = function() {
25987 if (extent.percentContainedIn(context.extent()) < 0.8) {
25988 reason = 'too_large';
25989 } else if (context.hasHiddenConnections(entityId)) {
25990 reason = 'connected_to_hidden';
25992 return action.disabled(context.graph()) || reason;
25995 operation.tooltip = function() {
25996 var disable = operation.disabled();
25998 t('operations.orthogonalize.' + disable) :
25999 t('operations.orthogonalize.description.' + geometry);
26002 operation.id = 'orthogonalize';
26003 operation.keys = [t('operations.orthogonalize.key')];
26004 operation.title = t('operations.orthogonalize.title');
26008 iD.operations.Reverse = function(selectedIDs, context) {
26009 var entityId = selectedIDs[0];
26011 var operation = function() {
26013 iD.actions.Reverse(entityId),
26014 t('operations.reverse.annotation'));
26017 operation.available = function() {
26018 return selectedIDs.length === 1 &&
26019 context.geometry(entityId) === 'line';
26022 operation.disabled = function() {
26026 operation.tooltip = function() {
26027 return t('operations.reverse.description');
26030 operation.id = 'reverse';
26031 operation.keys = [t('operations.reverse.key')];
26032 operation.title = t('operations.reverse.title');
26036 iD.operations.Rotate = function(selectedIDs, context) {
26037 var entityId = selectedIDs[0],
26038 entity = context.entity(entityId),
26039 extent = entity.extent(context.graph()),
26040 geometry = context.geometry(entityId);
26042 var operation = function() {
26043 context.enter(iD.modes.RotateWay(context, entityId));
26046 operation.available = function() {
26047 if (selectedIDs.length !== 1 || entity.type !== 'way')
26049 if (geometry === 'area')
26051 if (entity.isClosed() &&
26052 context.graph().parentRelations(entity).some(function(r) { return r.isMultipolygon(); }))
26057 operation.disabled = function() {
26058 if (extent.percentContainedIn(context.extent()) < 0.8) {
26059 return 'too_large';
26060 } else if (context.hasHiddenConnections(entityId)) {
26061 return 'connected_to_hidden';
26067 operation.tooltip = function() {
26068 var disable = operation.disabled();
26070 t('operations.rotate.' + disable) :
26071 t('operations.rotate.description');
26074 operation.id = 'rotate';
26075 operation.keys = [t('operations.rotate.key')];
26076 operation.title = t('operations.rotate.title');
26080 iD.operations.Split = function(selectedIDs, context) {
26081 var vertices = _.filter(selectedIDs, function vertex(entityId) {
26082 return context.geometry(entityId) === 'vertex';
26085 var entityId = vertices[0],
26086 action = iD.actions.Split(entityId);
26088 if (selectedIDs.length > 1) {
26089 action.limitWays(_.without(selectedIDs, entityId));
26092 var operation = function() {
26095 var ways = action.ways(context.graph());
26096 if (ways.length === 1) {
26097 annotation = t('operations.split.annotation.' + context.geometry(ways[0].id));
26099 annotation = t('operations.split.annotation.multiple', {n: ways.length});
26102 var difference = context.perform(action, annotation);
26103 context.enter(iD.modes.Select(context, difference.extantIDs()));
26106 operation.available = function() {
26107 return vertices.length === 1;
26110 operation.disabled = function() {
26112 if (_.any(selectedIDs, context.hasHiddenConnections)) {
26113 reason = 'connected_to_hidden';
26115 return action.disabled(context.graph()) || reason;
26118 operation.tooltip = function() {
26119 var disable = operation.disabled();
26121 return t('operations.split.' + disable);
26124 var ways = action.ways(context.graph());
26125 if (ways.length === 1) {
26126 return t('operations.split.description.' + context.geometry(ways[0].id));
26128 return t('operations.split.description.multiple');
26132 operation.id = 'split';
26133 operation.keys = [t('operations.split.key')];
26134 operation.title = t('operations.split.title');
26138 iD.operations.Straighten = function(selectedIDs, context) {
26139 var entityId = selectedIDs[0],
26140 action = iD.actions.Straighten(entityId, context.projection);
26142 function operation() {
26143 var annotation = t('operations.straighten.annotation');
26144 context.perform(action, annotation);
26147 operation.available = function() {
26148 var entity = context.entity(entityId);
26149 return selectedIDs.length === 1 &&
26150 entity.type === 'way' &&
26151 !entity.isClosed() &&
26152 _.uniq(entity.nodes).length > 2;
26155 operation.disabled = function() {
26157 if (context.hasHiddenConnections(entityId)) {
26158 reason = 'connected_to_hidden';
26160 return action.disabled(context.graph()) || reason;
26163 operation.tooltip = function() {
26164 var disable = operation.disabled();
26166 t('operations.straighten.' + disable) :
26167 t('operations.straighten.description');
26170 operation.id = 'straighten';
26171 operation.keys = [t('operations.straighten.key')];
26172 operation.title = t('operations.straighten.title');
26176 iD.Connection = function(useHttps) {
26177 if (typeof useHttps !== 'boolean') {
26178 useHttps = window.location.protocol === 'https:';
26181 var event = d3.dispatch('authenticating', 'authenticated', 'auth', 'loading', 'loaded'),
26182 protocol = useHttps ? 'https:' : 'http:',
26183 url = protocol + '//www.openstreetmap.org',
26189 url: protocol + '//www.openstreetmap.org',
26190 oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
26191 oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
26192 loading: authenticating,
26193 done: authenticated
26197 memberStr = 'member',
26200 relationStr = 'relation',
26205 connection.changesetURL = function(changesetId) {
26206 return url + '/changeset/' + changesetId;
26209 connection.changesetsURL = function(center, zoom) {
26210 var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
26211 return url + '/history#map=' +
26212 Math.floor(zoom) + '/' +
26213 center[1].toFixed(precision) + '/' +
26214 center[0].toFixed(precision);
26217 connection.entityURL = function(entity) {
26218 return url + '/' + entity.type + '/' + entity.osmId();
26221 connection.userURL = function(username) {
26222 return url + '/user/' + username;
26225 connection.loadFromURL = function(url, callback) {
26226 function done(err, dom) {
26227 return callback(err, parse(dom));
26229 return d3.xml(url).get(done);
26232 connection.loadEntity = function(id, callback) {
26233 var type = iD.Entity.id.type(id),
26234 osmID = iD.Entity.id.toOSM(id);
26236 connection.loadFromURL(
26237 url + '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
26238 function(err, entities) {
26239 if (callback) callback(err, {data: entities});
26243 connection.loadEntityVersion = function(id, version, callback) {
26244 var type = iD.Entity.id.type(id),
26245 osmID = iD.Entity.id.toOSM(id);
26247 connection.loadFromURL(
26248 url + '/api/0.6/' + type + '/' + osmID + '/' + version,
26249 function(err, entities) {
26250 if (callback) callback(err, {data: entities});
26254 connection.loadMultiple = function(ids, callback) {
26255 _.each(_.groupBy(_.uniq(ids), iD.Entity.id.type), function(v, k) {
26256 var type = k + 's',
26257 osmIDs = _.map(v, iD.Entity.id.toOSM);
26259 _.each(_.chunk(osmIDs, 150), function(arr) {
26260 connection.loadFromURL(
26261 url + '/api/0.6/' + type + '?' + type + '=' + arr.join(),
26262 function(err, entities) {
26263 if (callback) callback(err, {data: entities});
26269 function authenticating() {
26270 event.authenticating();
26273 function authenticated() {
26274 event.authenticated();
26277 function getLoc(attrs) {
26278 var lon = attrs.lon && attrs.lon.value,
26279 lat = attrs.lat && attrs.lat.value;
26280 return [parseFloat(lon), parseFloat(lat)];
26283 function getNodes(obj) {
26284 var elems = obj.getElementsByTagName(ndStr),
26285 nodes = new Array(elems.length);
26286 for (var i = 0, l = elems.length; i < l; i++) {
26287 nodes[i] = 'n' + elems[i].attributes.ref.value;
26292 function getTags(obj) {
26293 var elems = obj.getElementsByTagName(tagStr),
26295 for (var i = 0, l = elems.length; i < l; i++) {
26296 var attrs = elems[i].attributes;
26297 tags[attrs.k.value] = attrs.v.value;
26302 function getMembers(obj) {
26303 var elems = obj.getElementsByTagName(memberStr),
26304 members = new Array(elems.length);
26305 for (var i = 0, l = elems.length; i < l; i++) {
26306 var attrs = elems[i].attributes;
26308 id: attrs.type.value[0] + attrs.ref.value,
26309 type: attrs.type.value,
26310 role: attrs.role.value
26316 function getVisible(attrs) {
26317 return (!attrs.visible || attrs.visible.value !== 'false');
26321 node: function nodeData(obj) {
26322 var attrs = obj.attributes;
26323 return new iD.Node({
26324 id: iD.Entity.id.fromOSM(nodeStr, attrs.id.value),
26325 loc: getLoc(attrs),
26326 version: attrs.version.value,
26327 user: attrs.user && attrs.user.value,
26328 tags: getTags(obj),
26329 visible: getVisible(attrs)
26333 way: function wayData(obj) {
26334 var attrs = obj.attributes;
26335 return new iD.Way({
26336 id: iD.Entity.id.fromOSM(wayStr, attrs.id.value),
26337 version: attrs.version.value,
26338 user: attrs.user && attrs.user.value,
26339 tags: getTags(obj),
26340 nodes: getNodes(obj),
26341 visible: getVisible(attrs)
26345 relation: function relationData(obj) {
26346 var attrs = obj.attributes;
26347 return new iD.Relation({
26348 id: iD.Entity.id.fromOSM(relationStr, attrs.id.value),
26349 version: attrs.version.value,
26350 user: attrs.user && attrs.user.value,
26351 tags: getTags(obj),
26352 members: getMembers(obj),
26353 visible: getVisible(attrs)
26358 function parse(dom) {
26359 if (!dom || !dom.childNodes) return;
26361 var root = dom.childNodes[0],
26362 children = root.childNodes,
26365 for (var i = 0, l = children.length; i < l; i++) {
26366 var child = children[i],
26367 parser = parsers[child.nodeName];
26369 entities.push(parser(child));
26376 connection.authenticated = function() {
26377 return oauth.authenticated();
26380 // Generate Changeset XML. Returns a string.
26381 connection.changesetJXON = function(tags) {
26385 tag: _.map(tags, function(value, key) {
26386 return { '@k': key, '@v': value };
26395 // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
26396 // XML. Returns a string.
26397 connection.osmChangeJXON = function(changeset_id, changes) {
26398 function nest(x, order) {
26400 for (var i = 0; i < x.length; i++) {
26401 var tagName = Object.keys(x[i])[0];
26402 if (!groups[tagName]) groups[tagName] = [];
26403 groups[tagName].push(x[i][tagName]);
26406 order.forEach(function(o) {
26407 if (groups[o]) ordered[o] = groups[o];
26412 function rep(entity) {
26413 return entity.asJXON(changeset_id);
26419 '@generator': 'iD',
26420 'create': nest(changes.created.map(rep), ['node', 'way', 'relation']),
26421 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
26422 'delete': _.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {'@if-unused': true})
26427 connection.changesetTags = function(comment, imageryUsed) {
26428 var detected = iD.detect(),
26430 created_by: 'iD ' + iD.version,
26431 imagery_used: imageryUsed.join(';').substr(0, 255),
26432 host: (window.location.origin + window.location.pathname).substr(0, 255),
26433 locale: detected.locale
26437 tags.comment = comment.substr(0, 255);
26443 connection.putChangeset = function(changes, comment, imageryUsed, callback) {
26446 path: '/api/0.6/changeset/create',
26447 options: { header: { 'Content-Type': 'text/xml' } },
26448 content: JXON.stringify(connection.changesetJXON(connection.changesetTags(comment, imageryUsed)))
26449 }, function(err, changeset_id) {
26450 if (err) return callback(err);
26453 path: '/api/0.6/changeset/' + changeset_id + '/upload',
26454 options: { header: { 'Content-Type': 'text/xml' } },
26455 content: JXON.stringify(connection.osmChangeJXON(changeset_id, changes))
26457 if (err) return callback(err);
26458 // POST was successful, safe to call the callback.
26459 // Still attempt to close changeset, but ignore response because #2667
26460 // Add delay to allow for postgres replication #1646 #2678
26461 window.setTimeout(function() { callback(null, changeset_id); }, 2500);
26464 path: '/api/0.6/changeset/' + changeset_id + '/close',
26465 options: { header: { 'Content-Type': 'text/xml' } }
26466 }, d3.functor(true));
26471 connection.userDetails = function(callback) {
26473 callback(undefined, userDetails);
26477 function done(err, user_details) {
26478 if (err) return callback(err);
26480 var u = user_details.getElementsByTagName('user')[0],
26481 img = u.getElementsByTagName('img'),
26484 if (img && img[0] && img[0].getAttribute('href')) {
26485 image_url = img[0].getAttribute('href');
26489 display_name: u.attributes.display_name.value,
26490 image_url: image_url,
26491 id: u.attributes.id.value
26494 callback(undefined, userDetails);
26497 oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
26500 connection.userChangesets = function(callback) {
26501 connection.userDetails(function(err, user) {
26502 if (err) return callback(err);
26504 function done(changesets) {
26505 callback(undefined, Array.prototype.map.call(changesets.getElementsByTagName('changeset'),
26506 function (changeset) {
26507 return { tags: getTags(changeset) };
26511 d3.xml(url + '/api/0.6/changesets?user=' + user.id).get()
26513 .on('error', callback);
26517 connection.status = function(callback) {
26518 function done(capabilities) {
26519 var apiStatus = capabilities.getElementsByTagName('status');
26520 callback(undefined, apiStatus[0].getAttribute('api'));
26522 d3.xml(url + '/api/capabilities').get()
26524 .on('error', callback);
26527 function abortRequest(i) { i.abort(); }
26529 connection.tileZoom = function(_) {
26530 if (!arguments.length) return tileZoom;
26535 connection.loadTiles = function(projection, dimensions, callback) {
26539 var s = projection.scale() * 2 * Math.PI,
26540 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
26541 ts = 256 * Math.pow(2, z - tileZoom),
26543 s / 2 - projection.translate()[0],
26544 s / 2 - projection.translate()[1]];
26546 var tiles = d3.geo.tile()
26547 .scaleExtent([tileZoom, tileZoom])
26550 .translate(projection.translate())()
26551 .map(function(tile) {
26552 var x = tile[0] * ts - origin[0],
26553 y = tile[1] * ts - origin[1];
26556 id: tile.toString(),
26557 extent: iD.geo.Extent(
26558 projection.invert([x, y + ts]),
26559 projection.invert([x + ts, y]))
26563 function bboxUrl(tile) {
26564 return url + '/api/0.6/map?bbox=' + tile.extent.toParam();
26567 _.filter(inflight, function(v, i) {
26568 var wanted = _.find(tiles, function(tile) {
26569 return i === tile.id;
26571 if (!wanted) delete inflight[i];
26573 }).map(abortRequest);
26575 tiles.forEach(function(tile) {
26578 if (loadedTiles[id] || inflight[id]) return;
26580 if (_.isEmpty(inflight)) {
26584 inflight[id] = connection.loadFromURL(bboxUrl(tile), function(err, parsed) {
26585 loadedTiles[id] = true;
26586 delete inflight[id];
26588 if (callback) callback(err, _.extend({data: parsed}, tile));
26590 if (_.isEmpty(inflight)) {
26597 connection.switch = function(options) {
26599 oauth.options(_.extend({
26600 loading: authenticating,
26601 done: authenticated
26604 connection.flush();
26608 connection.toggle = function(_) {
26613 connection.flush = function() {
26614 userDetails = undefined;
26615 _.forEach(inflight, abortRequest);
26621 connection.loadedTiles = function(_) {
26622 if (!arguments.length) return loadedTiles;
26627 connection.logout = function() {
26628 userDetails = undefined;
26634 connection.authenticate = function(callback) {
26635 userDetails = undefined;
26636 function done(err, res) {
26638 if (callback) callback(err, res);
26640 return oauth.authenticate(done);
26643 return d3.rebind(connection, event, 'on');
26646 iD.Difference represents the difference between two graphs.
26647 It knows how to calculate the set of entities that were
26648 created, modified, or deleted, and also contains the logic
26649 for recursively extending a difference to the complete set
26650 of entities that will require a redraw, taking into account
26651 child and parent relationships.
26653 iD.Difference = function(base, head) {
26654 var changes = {}, length = 0;
26656 function changed(h, b) {
26657 return h !== b && !_.isEqual(_.omit(h, 'v'), _.omit(b, 'v'));
26660 _.each(head.entities, function(h, id) {
26661 var b = base.entities[id];
26662 if (changed(h, b)) {
26663 changes[id] = {base: b, head: h};
26668 _.each(base.entities, function(b, id) {
26669 var h = head.entities[id];
26670 if (!changes[id] && changed(h, b)) {
26671 changes[id] = {base: b, head: h};
26676 function addParents(parents, result) {
26677 for (var i = 0; i < parents.length; i++) {
26678 var parent = parents[i];
26680 if (parent.id in result)
26683 result[parent.id] = parent;
26684 addParents(head.parentRelations(parent), result);
26688 var difference = {};
26690 difference.length = function() {
26694 difference.changes = function() {
26698 difference.extantIDs = function() {
26700 _.each(changes, function(change, id) {
26701 if (change.head) result.push(id);
26706 difference.modified = function() {
26708 _.each(changes, function(change) {
26709 if (change.base && change.head) result.push(change.head);
26714 difference.created = function() {
26716 _.each(changes, function(change) {
26717 if (!change.base && change.head) result.push(change.head);
26722 difference.deleted = function() {
26724 _.each(changes, function(change) {
26725 if (change.base && !change.head) result.push(change.base);
26730 difference.summary = function() {
26733 function addEntity(entity, graph, changeType) {
26734 relevant[entity.id] = {
26737 changeType: changeType
26741 function addParents(entity) {
26742 var parents = head.parentWays(entity);
26743 for (var j = parents.length - 1; j >= 0; j--) {
26744 var parent = parents[j];
26745 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
26749 _.each(changes, function(change) {
26750 if (change.head && change.head.geometry(head) !== 'vertex') {
26751 addEntity(change.head, head, change.base ? 'modified' : 'created');
26753 } else if (change.base && change.base.geometry(base) !== 'vertex') {
26754 addEntity(change.base, base, 'deleted');
26756 } else if (change.base && change.head) { // modified vertex
26757 var moved = !_.isEqual(change.base.loc, change.head.loc),
26758 retagged = !_.isEqual(change.base.tags, change.head.tags);
26761 addParents(change.head);
26764 if (retagged || (moved && change.head.hasInterestingTags())) {
26765 addEntity(change.head, head, 'modified');
26768 } else if (change.head && change.head.hasInterestingTags()) { // created vertex
26769 addEntity(change.head, head, 'created');
26771 } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
26772 addEntity(change.base, base, 'deleted');
26776 return d3.values(relevant);
26779 difference.complete = function(extent) {
26780 var result = {}, id, change;
26782 for (id in changes) {
26783 change = changes[id];
26785 var h = change.head,
26790 (!h || !h.intersects(extent, head)) &&
26791 (!b || !b.intersects(extent, base)))
26796 if (entity.type === 'way') {
26797 var nh = h ? h.nodes : [],
26798 nb = b ? b.nodes : [],
26801 diff = _.difference(nh, nb);
26802 for (i = 0; i < diff.length; i++) {
26803 result[diff[i]] = head.hasEntity(diff[i]);
26806 diff = _.difference(nb, nh);
26807 for (i = 0; i < diff.length; i++) {
26808 result[diff[i]] = head.hasEntity(diff[i]);
26812 addParents(head.parentWays(entity), result);
26813 addParents(head.parentRelations(entity), result);
26821 iD.Entity = function(attrs) {
26822 // For prototypal inheritance.
26823 if (this instanceof iD.Entity) return;
26825 // Create the appropriate subtype.
26826 if (attrs && attrs.type) {
26827 return iD.Entity[attrs.type].apply(this, arguments);
26828 } else if (attrs && attrs.id) {
26829 return iD.Entity[iD.Entity.id.type(attrs.id)].apply(this, arguments);
26832 // Initialize a generic Entity (used only in tests).
26833 return (new iD.Entity()).initialize(arguments);
26836 iD.Entity.id = function(type) {
26837 return iD.Entity.id.fromOSM(type, iD.Entity.id.next[type]--);
26840 iD.Entity.id.next = {node: -1, way: -1, relation: -1};
26842 iD.Entity.id.fromOSM = function(type, id) {
26843 return type[0] + id;
26846 iD.Entity.id.toOSM = function(id) {
26847 return id.slice(1);
26850 iD.Entity.id.type = function(id) {
26851 return {'n': 'node', 'w': 'way', 'r': 'relation'}[id[0]];
26854 // A function suitable for use as the second argument to d3.selection#data().
26855 iD.Entity.key = function(entity) {
26856 return entity.id + 'v' + (entity.v || 0);
26859 iD.Entity.prototype = {
26862 initialize: function(sources) {
26863 for (var i = 0; i < sources.length; ++i) {
26864 var source = sources[i];
26865 for (var prop in source) {
26866 if (Object.prototype.hasOwnProperty.call(source, prop)) {
26867 if (source[prop] === undefined) {
26870 this[prop] = source[prop];
26876 if (!this.id && this.type) {
26877 this.id = iD.Entity.id(this.type);
26879 if (!this.hasOwnProperty('visible')) {
26880 this.visible = true;
26884 Object.freeze(this);
26885 Object.freeze(this.tags);
26887 if (this.loc) Object.freeze(this.loc);
26888 if (this.nodes) Object.freeze(this.nodes);
26889 if (this.members) Object.freeze(this.members);
26895 copy: function(resolver, copies) {
26896 if (copies[this.id])
26897 return copies[this.id];
26899 var copy = iD.Entity(this, {id: undefined, user: undefined, version: undefined});
26900 copies[this.id] = copy;
26905 osmId: function() {
26906 return iD.Entity.id.toOSM(this.id);
26909 isNew: function() {
26910 return this.osmId() < 0;
26913 update: function(attrs) {
26914 return iD.Entity(this, attrs, {v: 1 + (this.v || 0)});
26917 mergeTags: function(tags) {
26918 var merged = _.clone(this.tags), changed = false;
26919 for (var k in tags) {
26920 var t1 = merged[k],
26925 } else if (t1 !== t2) {
26927 merged[k] = _.union(t1.split(/;\s*/), t2.split(/;\s*/)).join(';');
26930 return changed ? this.update({tags: merged}) : this;
26933 intersects: function(extent, resolver) {
26934 return this.extent(resolver).intersects(extent);
26937 isUsed: function(resolver) {
26938 return _.without(Object.keys(this.tags), 'area').length > 0 ||
26939 resolver.parentRelations(this).length > 0;
26942 hasInterestingTags: function() {
26943 return _.keys(this.tags).some(iD.interestingTag);
26946 isHighwayIntersection: function() {
26950 deprecatedTags: function() {
26951 var tags = _.pairs(this.tags);
26952 var deprecated = {};
26954 iD.data.deprecated.forEach(function(d) {
26955 var match = _.pairs(d.old)[0];
26956 tags.forEach(function(t) {
26957 if (t[0] === match[0] &&
26958 (t[1] === match[1] || match[1] === '*')) {
26959 deprecated[t[0]] = t[1];
26967 iD.Graph = function(other, mutable) {
26968 if (!(this instanceof iD.Graph)) return new iD.Graph(other, mutable);
26970 if (other instanceof iD.Graph) {
26971 var base = other.base();
26972 this.entities = _.assign(Object.create(base.entities), other.entities);
26973 this._parentWays = _.assign(Object.create(base.parentWays), other._parentWays);
26974 this._parentRels = _.assign(Object.create(base.parentRels), other._parentRels);
26977 this.entities = Object.create({});
26978 this._parentWays = Object.create({});
26979 this._parentRels = Object.create({});
26980 this.rebase(other || [], [this]);
26983 this.transients = {};
26984 this._childNodes = {};
26985 this.frozen = !mutable;
26988 iD.Graph.prototype = {
26989 hasEntity: function(id) {
26990 return this.entities[id];
26993 entity: function(id) {
26994 var entity = this.entities[id];
26996 throw new Error('entity ' + id + ' not found');
27001 transient: function(entity, key, fn) {
27002 var id = entity.id,
27003 transients = this.transients[id] ||
27004 (this.transients[id] = {});
27006 if (transients[key] !== undefined) {
27007 return transients[key];
27010 transients[key] = fn.call(entity);
27012 return transients[key];
27015 parentWays: function(entity) {
27016 var parents = this._parentWays[entity.id],
27020 for (var i = 0; i < parents.length; i++) {
27021 result.push(this.entity(parents[i]));
27027 isPoi: function(entity) {
27028 var parentWays = this._parentWays[entity.id];
27029 return !parentWays || parentWays.length === 0;
27032 isShared: function(entity) {
27033 var parentWays = this._parentWays[entity.id];
27034 return parentWays && parentWays.length > 1;
27037 parentRelations: function(entity) {
27038 var parents = this._parentRels[entity.id],
27042 for (var i = 0; i < parents.length; i++) {
27043 result.push(this.entity(parents[i]));
27049 childNodes: function(entity) {
27050 if (this._childNodes[entity.id]) return this._childNodes[entity.id];
27051 if (!entity.nodes) return [];
27054 for (var i = 0; i < entity.nodes.length; i++) {
27055 nodes[i] = this.entity(entity.nodes[i]);
27058 if (iD.debug) Object.freeze(nodes);
27060 this._childNodes[entity.id] = nodes;
27061 return this._childNodes[entity.id];
27066 'entities': iD.util.getPrototypeOf(this.entities),
27067 'parentWays': iD.util.getPrototypeOf(this._parentWays),
27068 'parentRels': iD.util.getPrototypeOf(this._parentRels)
27072 // Unlike other graph methods, rebase mutates in place. This is because it
27073 // is used only during the history operation that merges newly downloaded
27074 // data into each state. To external consumers, it should appear as if the
27075 // graph always contained the newly downloaded data.
27076 rebase: function(entities, stack, force) {
27077 var base = this.base(),
27080 for (i = 0; i < entities.length; i++) {
27081 var entity = entities[i];
27083 if (!entity.visible || (!force && base.entities[entity.id]))
27086 // Merging data into the base graph
27087 base.entities[entity.id] = entity;
27088 this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
27090 // Restore provisionally-deleted nodes that are discovered to have an extant parent
27091 if (entity.type === 'way') {
27092 for (j = 0; j < entity.nodes.length; j++) {
27093 id = entity.nodes[j];
27094 for (k = 1; k < stack.length; k++) {
27095 var ents = stack[k].entities;
27096 if (ents.hasOwnProperty(id) && ents[id] === undefined) {
27104 for (i = 0; i < stack.length; i++) {
27105 stack[i]._updateRebased();
27109 _updateRebased: function() {
27110 var base = this.base(),
27111 i, k, child, id, keys;
27113 keys = Object.keys(this._parentWays);
27114 for (i = 0; i < keys.length; i++) {
27116 if (base.parentWays[child]) {
27117 for (k = 0; k < base.parentWays[child].length; k++) {
27118 id = base.parentWays[child][k];
27119 if (!this.entities.hasOwnProperty(id) && !_.contains(this._parentWays[child], id)) {
27120 this._parentWays[child].push(id);
27126 keys = Object.keys(this._parentRels);
27127 for (i = 0; i < keys.length; i++) {
27129 if (base.parentRels[child]) {
27130 for (k = 0; k < base.parentRels[child].length; k++) {
27131 id = base.parentRels[child][k];
27132 if (!this.entities.hasOwnProperty(id) && !_.contains(this._parentRels[child], id)) {
27133 this._parentRels[child].push(id);
27139 this.transients = {};
27141 // this._childNodes is not updated, under the assumption that
27142 // ways are always downloaded with their child nodes.
27145 // Updates calculated properties (parentWays, parentRels) for the specified change
27146 _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
27148 parentWays = parentWays || this._parentWays;
27149 parentRels = parentRels || this._parentRels;
27151 var type = entity && entity.type || oldentity && oldentity.type,
27152 removed, added, ways, rels, i;
27155 if (type === 'way') {
27157 // Update parentWays
27158 if (oldentity && entity) {
27159 removed = _.difference(oldentity.nodes, entity.nodes);
27160 added = _.difference(entity.nodes, oldentity.nodes);
27161 } else if (oldentity) {
27162 removed = oldentity.nodes;
27164 } else if (entity) {
27166 added = entity.nodes;
27168 for (i = 0; i < removed.length; i++) {
27169 parentWays[removed[i]] = _.without(parentWays[removed[i]], oldentity.id);
27171 for (i = 0; i < added.length; i++) {
27172 ways = _.without(parentWays[added[i]], entity.id);
27173 ways.push(entity.id);
27174 parentWays[added[i]] = ways;
27177 } else if (type === 'relation') {
27179 // Update parentRels
27180 if (oldentity && entity) {
27181 removed = _.difference(oldentity.members, entity.members);
27182 added = _.difference(entity.members, oldentity);
27183 } else if (oldentity) {
27184 removed = oldentity.members;
27186 } else if (entity) {
27188 added = entity.members;
27190 for (i = 0; i < removed.length; i++) {
27191 parentRels[removed[i].id] = _.without(parentRels[removed[i].id], oldentity.id);
27193 for (i = 0; i < added.length; i++) {
27194 rels = _.without(parentRels[added[i].id], entity.id);
27195 rels.push(entity.id);
27196 parentRels[added[i].id] = rels;
27201 replace: function(entity) {
27202 if (this.entities[entity.id] === entity)
27205 return this.update(function() {
27206 this._updateCalculated(this.entities[entity.id], entity);
27207 this.entities[entity.id] = entity;
27211 remove: function(entity) {
27212 return this.update(function() {
27213 this._updateCalculated(entity, undefined);
27214 this.entities[entity.id] = undefined;
27218 revert: function(id) {
27219 var baseEntity = this.base().entities[id],
27220 headEntity = this.entities[id];
27222 if (headEntity === baseEntity)
27225 return this.update(function() {
27226 this._updateCalculated(headEntity, baseEntity);
27227 delete this.entities[id];
27231 update: function() {
27232 var graph = this.frozen ? iD.Graph(this, true) : this;
27234 for (var i = 0; i < arguments.length; i++) {
27235 arguments[i].call(graph, graph);
27238 if (this.frozen) graph.frozen = true;
27243 // Obliterates any existing entities
27244 load: function(entities) {
27245 var base = this.base();
27246 this.entities = Object.create(base.entities);
27248 for (var i in entities) {
27249 this.entities[i] = entities[i];
27250 this._updateCalculated(base.entities[i], this.entities[i]);
27256 iD.History = function(context) {
27257 var stack, index, tree,
27258 imageryUsed = ['Bing'],
27259 dispatch = d3.dispatch('change', 'undone', 'redone'),
27260 lock = iD.util.SessionMutex('lock');
27262 function perform(actions) {
27263 actions = Array.prototype.slice.call(actions);
27267 if (!_.isFunction(_.last(actions))) {
27268 annotation = actions.pop();
27271 var graph = stack[index].graph;
27272 for (var i = 0; i < actions.length; i++) {
27273 graph = actions[i](graph);
27278 annotation: annotation,
27279 imageryUsed: imageryUsed
27283 function change(previous) {
27284 var difference = iD.Difference(previous, history.graph());
27285 dispatch.change(difference);
27289 // iD uses namespaced keys so multiple installations do not conflict
27290 function getKey(n) {
27291 return 'iD_' + window.location.origin + '_' + n;
27295 graph: function() {
27296 return stack[index].graph;
27300 return stack[0].graph;
27303 merge: function(entities, extent) {
27304 stack[0].graph.rebase(entities, _.pluck(stack, 'graph'), false);
27305 tree.rebase(entities, false);
27307 dispatch.change(undefined, extent);
27310 perform: function() {
27311 var previous = stack[index].graph;
27313 stack = stack.slice(0, index + 1);
27314 stack.push(perform(arguments));
27317 return change(previous);
27320 replace: function() {
27321 var previous = stack[index].graph;
27323 // assert(index == stack.length - 1)
27324 stack[index] = perform(arguments);
27326 return change(previous);
27330 var previous = stack[index].graph;
27335 return change(previous);
27339 // Same as calling pop and then perform
27340 overwrite: function() {
27341 var previous = stack[index].graph;
27347 stack = stack.slice(0, index + 1);
27348 stack.push(perform(arguments));
27351 return change(previous);
27355 var previous = stack[index].graph;
27357 // Pop to the next annotated state.
27358 while (index > 0) {
27360 if (stack[index].annotation) break;
27364 return change(previous);
27368 var previous = stack[index].graph;
27370 while (index < stack.length - 1) {
27372 if (stack[index].annotation) break;
27376 return change(previous);
27379 undoAnnotation: function() {
27382 if (stack[i].annotation) return stack[i].annotation;
27387 redoAnnotation: function() {
27389 while (i <= stack.length - 1) {
27390 if (stack[i].annotation) return stack[i].annotation;
27395 intersects: function(extent) {
27396 return tree.intersects(extent, stack[index].graph);
27399 difference: function() {
27400 var base = stack[0].graph,
27401 head = stack[index].graph;
27402 return iD.Difference(base, head);
27405 changes: function(action) {
27406 var base = stack[0].graph,
27407 head = stack[index].graph;
27410 head = action(head);
27413 var difference = iD.Difference(base, head);
27416 modified: difference.modified(),
27417 created: difference.created(),
27418 deleted: difference.deleted()
27422 validate: function(changes) {
27423 return _(iD.validations)
27424 .map(function(fn) { return fn()(changes, stack[index].graph); })
27429 hasChanges: function() {
27430 return this.difference().length() > 0;
27433 imageryUsed: function(sources) {
27435 imageryUsed = sources;
27438 return _(stack.slice(1, index + 1))
27439 .pluck('imageryUsed')
27442 .without(undefined, 'Custom')
27447 reset: function() {
27448 stack = [{graph: iD.Graph()}];
27450 tree = iD.Tree(stack[0].graph);
27455 toJSON: function() {
27456 if (!this.hasChanges()) return;
27458 var allEntities = {},
27462 var s = stack.map(function(i) {
27463 var modified = [], deleted = [];
27465 _.forEach(i.graph.entities, function(entity, id) {
27467 var key = iD.Entity.key(entity);
27468 allEntities[key] = entity;
27469 modified.push(key);
27474 // make sure that the originals of changed or deleted entities get merged
27475 // into the base of the stack after restoring the data from JSON.
27476 if (id in base.graph.entities) {
27477 baseEntities[id] = base.graph.entities[id];
27479 // get originals of parent entities too
27480 _.forEach(base.graph._parentWays[id], function(parentId) {
27481 if (parentId in base.graph.entities) {
27482 baseEntities[parentId] = base.graph.entities[parentId];
27489 if (modified.length) x.modified = modified;
27490 if (deleted.length) x.deleted = deleted;
27491 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
27492 if (i.annotation) x.annotation = i.annotation;
27497 return JSON.stringify({
27499 entities: _.values(allEntities),
27500 baseEntities: _.values(baseEntities),
27502 nextIDs: iD.Entity.id.next,
27507 fromJSON: function(json, loadChildNodes) {
27508 var h = JSON.parse(json),
27509 loadComplete = true;
27511 iD.Entity.id.next = h.nextIDs;
27514 if (h.version === 2 || h.version === 3) {
27515 var allEntities = {};
27517 h.entities.forEach(function(entity) {
27518 allEntities[iD.Entity.key(entity)] = iD.Entity(entity);
27521 if (h.version === 3) {
27522 // This merges originals for changed entities into the base of
27523 // the stack even if the current stack doesn't have them (for
27524 // example when iD has been restarted in a different region)
27525 var baseEntities = h.baseEntities.map(function(d) { return iD.Entity(d); });
27526 stack[0].graph.rebase(baseEntities, _.pluck(stack, 'graph'), true);
27527 tree.rebase(baseEntities, true);
27529 // When we restore a modified way, we also need to fetch any missing
27530 // childnodes that would normally have been downloaded with it.. #2142
27531 if (loadChildNodes) {
27532 var missing = _(baseEntities)
27533 .filter('type', 'way')
27537 .reject(function(n) { return stack[0].graph.hasEntity(n); })
27540 if (!_.isEmpty(missing)) {
27541 loadComplete = false;
27542 context.redrawEnable(false);
27544 var loading = iD.ui.Loading(context).blocking(true);
27545 context.container().call(loading);
27547 var childNodesLoaded = function(err, result) {
27549 var visible = _.groupBy(result.data, 'visible');
27550 if (!_.isEmpty(visible.true)) {
27551 missing = _.difference(missing, _.pluck(visible.true, 'id'));
27552 stack[0].graph.rebase(visible.true, _.pluck(stack, 'graph'), true);
27553 tree.rebase(visible.true, true);
27556 // fetch older versions of nodes that were deleted..
27557 _.each(visible.false, function(entity) {
27558 context.connection()
27559 .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
27563 if (err || _.isEmpty(missing)) {
27565 context.redrawEnable(true);
27570 context.connection().loadMultiple(missing, childNodesLoaded);
27575 stack = h.stack.map(function(d) {
27576 var entities = {}, entity;
27579 d.modified.forEach(function(key) {
27580 entity = allEntities[key];
27581 entities[entity.id] = entity;
27586 d.deleted.forEach(function(id) {
27587 entities[id] = undefined;
27592 graph: iD.Graph(stack[0].graph).load(entities),
27593 annotation: d.annotation,
27594 imageryUsed: d.imageryUsed
27598 } else { // original version
27599 stack = h.stack.map(function(d) {
27602 for (var i in d.entities) {
27603 var entity = d.entities[i];
27604 entities[i] = entity === 'undefined' ? undefined : iD.Entity(entity);
27607 d.graph = iD.Graph(stack[0].graph).load(entities);
27612 if (loadComplete) {
27620 if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
27624 clearSaved: function() {
27625 context.debouncedSave.cancel();
27626 if (lock.locked()) context.storage(getKey('saved_history'), null);
27631 return lock.lock();
27634 unlock: function() {
27638 // is iD not open in another window and it detects that
27639 // there's a history stored in localStorage that's recoverable?
27640 restorableChanges: function() {
27641 return lock.locked() && !!context.storage(getKey('saved_history'));
27644 // load history from a version stored in localStorage
27645 restore: function() {
27646 if (!lock.locked()) return;
27648 var json = context.storage(getKey('saved_history'));
27649 if (json) history.fromJSON(json, true);
27658 return d3.rebind(history, dispatch, 'on');
27660 iD.Node = iD.Entity.node = function iD_Node() {
27661 if (!(this instanceof iD_Node)) {
27662 return (new iD_Node()).initialize(arguments);
27663 } else if (arguments.length) {
27664 this.initialize(arguments);
27668 iD.Node.prototype = Object.create(iD.Entity.prototype);
27670 _.extend(iD.Node.prototype, {
27673 extent: function() {
27674 return new iD.geo.Extent(this.loc);
27677 geometry: function(graph) {
27678 return graph.transient(this, 'geometry', function() {
27679 return graph.isPoi(this) ? 'point' : 'vertex';
27683 move: function(loc) {
27684 return this.update({loc: loc});
27687 isIntersection: function(resolver) {
27688 return resolver.transient(this, 'isIntersection', function() {
27689 return resolver.parentWays(this).filter(function(parent) {
27690 return (parent.tags.highway ||
27691 parent.tags.waterway ||
27692 parent.tags.railway ||
27693 parent.tags.aeroway) &&
27694 parent.geometry(resolver) === 'line';
27699 isHighwayIntersection: function(resolver) {
27700 return resolver.transient(this, 'isHighwayIntersection', function() {
27701 return resolver.parentWays(this).filter(function(parent) {
27702 return parent.tags.highway && parent.geometry(resolver) === 'line';
27707 asJXON: function(changeset_id) {
27710 '@id': this.osmId(),
27711 '@lon': this.loc[0],
27712 '@lat': this.loc[1],
27713 '@version': (this.version || 0),
27714 tag: _.map(this.tags, function(v, k) {
27715 return { keyAttributes: { k: k, v: v } };
27719 if (changeset_id) r.node['@changeset'] = changeset_id;
27723 asGeoJSON: function() {
27726 coordinates: this.loc
27730 iD.Relation = iD.Entity.relation = function iD_Relation() {
27731 if (!(this instanceof iD_Relation)) {
27732 return (new iD_Relation()).initialize(arguments);
27733 } else if (arguments.length) {
27734 this.initialize(arguments);
27738 iD.Relation.prototype = Object.create(iD.Entity.prototype);
27740 iD.Relation.creationOrder = function(a, b) {
27741 var aId = parseInt(iD.Entity.id.toOSM(a.id), 10);
27742 var bId = parseInt(iD.Entity.id.toOSM(b.id), 10);
27744 if (aId < 0 || bId < 0) return aId - bId;
27748 _.extend(iD.Relation.prototype, {
27752 copy: function(resolver, copies) {
27753 if (copies[this.id])
27754 return copies[this.id];
27756 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
27758 var members = this.members.map(function(member) {
27759 return _.extend({}, member, {id: resolver.entity(member.id).copy(resolver, copies).id});
27762 copy = copy.update({members: members});
27763 copies[this.id] = copy;
27768 extent: function(resolver, memo) {
27769 return resolver.transient(this, 'extent', function() {
27770 if (memo && memo[this.id]) return iD.geo.Extent();
27772 memo[this.id] = true;
27774 var extent = iD.geo.Extent();
27775 for (var i = 0; i < this.members.length; i++) {
27776 var member = resolver.hasEntity(this.members[i].id);
27778 extent._extend(member.extent(resolver, memo));
27785 geometry: function(graph) {
27786 return graph.transient(this, 'geometry', function() {
27787 return this.isMultipolygon() ? 'area' : 'relation';
27791 isDegenerate: function() {
27792 return this.members.length === 0;
27795 // Return an array of members, each extended with an 'index' property whose value
27796 // is the member index.
27797 indexedMembers: function() {
27798 var result = new Array(this.members.length);
27799 for (var i = 0; i < this.members.length; i++) {
27800 result[i] = _.extend({}, this.members[i], {index: i});
27805 // Return the first member with the given role. A copy of the member object
27806 // is returned, extended with an 'index' property whose value is the member index.
27807 memberByRole: function(role) {
27808 for (var i = 0; i < this.members.length; i++) {
27809 if (this.members[i].role === role) {
27810 return _.extend({}, this.members[i], {index: i});
27815 // Return the first member with the given id. A copy of the member object
27816 // is returned, extended with an 'index' property whose value is the member index.
27817 memberById: function(id) {
27818 for (var i = 0; i < this.members.length; i++) {
27819 if (this.members[i].id === id) {
27820 return _.extend({}, this.members[i], {index: i});
27825 // Return the first member with the given id and role. A copy of the member object
27826 // is returned, extended with an 'index' property whose value is the member index.
27827 memberByIdAndRole: function(id, role) {
27828 for (var i = 0; i < this.members.length; i++) {
27829 if (this.members[i].id === id && this.members[i].role === role) {
27830 return _.extend({}, this.members[i], {index: i});
27835 addMember: function(member, index) {
27836 var members = this.members.slice();
27837 members.splice(index === undefined ? members.length : index, 0, member);
27838 return this.update({members: members});
27841 updateMember: function(member, index) {
27842 var members = this.members.slice();
27843 members.splice(index, 1, _.extend({}, members[index], member));
27844 return this.update({members: members});
27847 removeMember: function(index) {
27848 var members = this.members.slice();
27849 members.splice(index, 1);
27850 return this.update({members: members});
27853 removeMembersWithID: function(id) {
27854 var members = _.reject(this.members, function(m) { return m.id === id; });
27855 return this.update({members: members});
27858 // Wherever a member appears with id `needle.id`, replace it with a member
27859 // with id `replacement.id`, type `replacement.type`, and the original role,
27860 // unless a member already exists with that id and role. Return an updated
27862 replaceMember: function(needle, replacement) {
27863 if (!this.memberById(needle.id))
27868 for (var i = 0; i < this.members.length; i++) {
27869 var member = this.members[i];
27870 if (member.id !== needle.id) {
27871 members.push(member);
27872 } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
27873 members.push({id: replacement.id, type: replacement.type, role: member.role});
27877 return this.update({members: members});
27880 asJXON: function(changeset_id) {
27883 '@id': this.osmId(),
27884 '@version': this.version || 0,
27885 member: _.map(this.members, function(member) {
27886 return { keyAttributes: { type: member.type, role: member.role, ref: iD.Entity.id.toOSM(member.id) } };
27888 tag: _.map(this.tags, function(v, k) {
27889 return { keyAttributes: { k: k, v: v } };
27893 if (changeset_id) r.relation['@changeset'] = changeset_id;
27897 asGeoJSON: function(resolver) {
27898 return resolver.transient(this, 'GeoJSON', function () {
27899 if (this.isMultipolygon()) {
27901 type: 'MultiPolygon',
27902 coordinates: this.multipolygon(resolver)
27906 type: 'FeatureCollection',
27907 properties: this.tags,
27908 features: this.members.map(function (member) {
27909 return _.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
27916 area: function(resolver) {
27917 return resolver.transient(this, 'area', function() {
27918 return d3.geo.area(this.asGeoJSON(resolver));
27922 isMultipolygon: function() {
27923 return this.tags.type === 'multipolygon';
27926 isComplete: function(resolver) {
27927 for (var i = 0; i < this.members.length; i++) {
27928 if (!resolver.hasEntity(this.members[i].id)) {
27935 isRestriction: function() {
27936 return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
27939 // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
27940 // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
27942 // This corresponds to the structure needed for rendering a multipolygon path using a
27943 // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
27945 // In the case of invalid geometries, this function will still return a result which
27946 // includes the nodes of all way members, but some Nds may be unclosed and some inner
27947 // rings not matched with the intended outer ring.
27949 multipolygon: function(resolver) {
27950 var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
27951 inners = this.members.filter(function(m) { return 'inner' === m.role; });
27953 outers = iD.geo.joinWays(outers, resolver);
27954 inners = iD.geo.joinWays(inners, resolver);
27956 outers = outers.map(function(outer) { return _.pluck(outer.nodes, 'loc'); });
27957 inners = inners.map(function(inner) { return _.pluck(inner.nodes, 'loc'); });
27959 var result = outers.map(function(o) {
27960 // Heuristic for detecting counterclockwise winding order. Assumes
27961 // that OpenStreetMap polygons are not hemisphere-spanning.
27962 return [d3.geo.area({type: 'Polygon', coordinates: [o]}) > 2 * Math.PI ? o.reverse() : o];
27965 function findOuter(inner) {
27968 for (o = 0; o < outers.length; o++) {
27970 if (iD.geo.polygonContainsPolygon(outer, inner))
27974 for (o = 0; o < outers.length; o++) {
27976 if (iD.geo.polygonIntersectsPolygon(outer, inner))
27981 for (var i = 0; i < inners.length; i++) {
27982 var inner = inners[i];
27984 if (d3.geo.area({type: 'Polygon', coordinates: [inner]}) < 2 * Math.PI) {
27985 inner = inner.reverse();
27988 var o = findOuter(inners[i]);
27989 if (o !== undefined)
27990 result[o].push(inners[i]);
27992 result.push([inners[i]]); // Invalid geometry
28000 'chair_lift': true,
28001 'mixed_lift': true,
28006 'magic_carpet': true,
28011 'motorway_link': true
28017 'piste:halfpipe': true
28041 iD.interestingTag = function (key) {
28042 return key !== 'attribution' &&
28043 key !== 'created_by' &&
28044 key !== 'source' &&
28046 key.indexOf('tiger:') !== 0;
28049 iD.Tree = function(head) {
28050 var rtree = rbush(),
28053 function entityRectangle(entity) {
28054 var rect = entity.extent(head).rectangle();
28055 rect.id = entity.id;
28056 rectangles[entity.id] = rect;
28060 function updateParents(entity, insertions, memo) {
28061 head.parentWays(entity).forEach(function(way) {
28062 if (rectangles[way.id]) {
28063 rtree.remove(rectangles[way.id]);
28064 insertions[way.id] = way;
28066 updateParents(way, insertions, memo);
28069 head.parentRelations(entity).forEach(function(relation) {
28070 if (memo[entity.id]) return;
28071 memo[entity.id] = true;
28072 if (rectangles[relation.id]) {
28073 rtree.remove(rectangles[relation.id]);
28074 insertions[relation.id] = relation;
28076 updateParents(relation, insertions, memo);
28082 tree.rebase = function(entities, force) {
28083 var insertions = {};
28085 for (var i = 0; i < entities.length; i++) {
28086 var entity = entities[i];
28088 if (!entity.visible)
28091 if (head.entities.hasOwnProperty(entity.id) || rectangles[entity.id]) {
28094 } else if (rectangles[entity.id]) {
28095 rtree.remove(rectangles[entity.id]);
28099 insertions[entity.id] = entity;
28100 updateParents(entity, insertions, {});
28103 rtree.load(_.map(insertions, entityRectangle));
28108 tree.intersects = function(extent, graph) {
28109 if (graph !== head) {
28110 var diff = iD.Difference(head, graph),
28115 diff.deleted().forEach(function(entity) {
28116 rtree.remove(rectangles[entity.id]);
28117 delete rectangles[entity.id];
28120 diff.modified().forEach(function(entity) {
28121 rtree.remove(rectangles[entity.id]);
28122 insertions[entity.id] = entity;
28123 updateParents(entity, insertions, {});
28126 diff.created().forEach(function(entity) {
28127 insertions[entity.id] = entity;
28130 rtree.load(_.map(insertions, entityRectangle));
28133 return rtree.search(extent.rectangle()).map(function(rect) {
28134 return head.entity(rect.id);
28140 iD.Way = iD.Entity.way = function iD_Way() {
28141 if (!(this instanceof iD_Way)) {
28142 return (new iD_Way()).initialize(arguments);
28143 } else if (arguments.length) {
28144 this.initialize(arguments);
28148 iD.Way.prototype = Object.create(iD.Entity.prototype);
28150 _.extend(iD.Way.prototype, {
28154 copy: function(resolver, copies) {
28155 if (copies[this.id])
28156 return copies[this.id];
28158 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
28160 var nodes = this.nodes.map(function(id) {
28161 return resolver.entity(id).copy(resolver, copies).id;
28164 copy = copy.update({nodes: nodes});
28165 copies[this.id] = copy;
28170 extent: function(resolver) {
28171 return resolver.transient(this, 'extent', function() {
28172 var extent = iD.geo.Extent();
28173 for (var i = 0; i < this.nodes.length; i++) {
28174 var node = resolver.hasEntity(this.nodes[i]);
28176 extent._extend(node.extent());
28183 first: function() {
28184 return this.nodes[0];
28188 return this.nodes[this.nodes.length - 1];
28191 contains: function(node) {
28192 return this.nodes.indexOf(node) >= 0;
28195 affix: function(node) {
28196 if (this.nodes[0] === node) return 'prefix';
28197 if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
28200 layer: function() {
28201 // explicit layer tag, clamp between -10, 10..
28202 if (this.tags.layer !== undefined) {
28203 return Math.max(-10, Math.min(+(this.tags.layer), 10));
28206 // implied layer tag..
28207 if (this.tags.location === 'overground') return 1;
28208 if (this.tags.location === 'underground') return -1;
28209 if (this.tags.location === 'underwater') return -10;
28211 if (this.tags.power === 'line') return 10;
28212 if (this.tags.power === 'minor_line') return 10;
28213 if (this.tags.aerialway) return 10;
28214 if (this.tags.bridge) return 1;
28215 if (this.tags.cutting) return -1;
28216 if (this.tags.tunnel) return -1;
28217 if (this.tags.waterway) return -1;
28218 if (this.tags.man_made === 'pipeline') return -10;
28219 if (this.tags.boundary) return -10;
28223 isOneWay: function() {
28224 // explicit oneway tag..
28225 if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
28226 if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
28228 // implied oneway tag..
28229 for (var key in this.tags) {
28230 if (key in iD.oneWayTags && (this.tags[key] in iD.oneWayTags[key]))
28236 isClosed: function() {
28237 return this.nodes.length > 0 && this.first() === this.last();
28240 isConvex: function(resolver) {
28241 if (!this.isClosed() || this.isDegenerate()) return null;
28243 var nodes = _.uniq(resolver.childNodes(this)),
28244 coords = _.pluck(nodes, 'loc'),
28245 curr = 0, prev = 0;
28247 for (var i = 0; i < coords.length; i++) {
28248 var o = coords[(i+1) % coords.length],
28250 b = coords[(i+2) % coords.length],
28251 res = iD.geo.cross(o, a, b);
28253 curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
28256 } else if (prev && curr !== prev) {
28264 isArea: function() {
28265 if (this.tags.area === 'yes')
28267 if (!this.isClosed() || this.tags.area === 'no')
28269 for (var key in this.tags)
28270 if (key in iD.areaKeys && !(this.tags[key] in iD.areaKeys[key]))
28275 isDegenerate: function() {
28276 return _.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
28279 areAdjacent: function(n1, n2) {
28280 for (var i = 0; i < this.nodes.length; i++) {
28281 if (this.nodes[i] === n1) {
28282 if (this.nodes[i - 1] === n2) return true;
28283 if (this.nodes[i + 1] === n2) return true;
28289 geometry: function(graph) {
28290 return graph.transient(this, 'geometry', function() {
28291 return this.isArea() ? 'area' : 'line';
28295 addNode: function(id, index) {
28296 var nodes = this.nodes.slice();
28297 nodes.splice(index === undefined ? nodes.length : index, 0, id);
28298 return this.update({nodes: nodes});
28301 updateNode: function(id, index) {
28302 var nodes = this.nodes.slice();
28303 nodes.splice(index, 1, id);
28304 return this.update({nodes: nodes});
28307 replaceNode: function(needle, replacement) {
28308 if (this.nodes.indexOf(needle) < 0)
28311 var nodes = this.nodes.slice();
28312 for (var i = 0; i < nodes.length; i++) {
28313 if (nodes[i] === needle) {
28314 nodes[i] = replacement;
28317 return this.update({nodes: nodes});
28320 removeNode: function(id) {
28323 for (var i = 0; i < this.nodes.length; i++) {
28324 var node = this.nodes[i];
28325 if (node !== id && nodes[nodes.length - 1] !== node) {
28330 // Preserve circularity
28331 if (this.nodes.length > 1 && this.first() === id && this.last() === id && nodes[nodes.length - 1] !== nodes[0]) {
28332 nodes.push(nodes[0]);
28335 return this.update({nodes: nodes});
28338 asJXON: function(changeset_id) {
28341 '@id': this.osmId(),
28342 '@version': this.version || 0,
28343 nd: _.map(this.nodes, function(id) {
28344 return { keyAttributes: { ref: iD.Entity.id.toOSM(id) } };
28346 tag: _.map(this.tags, function(v, k) {
28347 return { keyAttributes: { k: k, v: v } };
28351 if (changeset_id) r.way['@changeset'] = changeset_id;
28355 asGeoJSON: function(resolver) {
28356 return resolver.transient(this, 'GeoJSON', function() {
28357 var coordinates = _.pluck(resolver.childNodes(this), 'loc');
28358 if (this.isArea() && this.isClosed()) {
28361 coordinates: [coordinates]
28365 type: 'LineString',
28366 coordinates: coordinates
28372 area: function(resolver) {
28373 return resolver.transient(this, 'area', function() {
28374 var nodes = resolver.childNodes(this);
28378 coordinates: [_.pluck(nodes, 'loc')]
28381 if (!this.isClosed() && nodes.length) {
28382 json.coordinates[0].push(nodes[0].loc);
28385 var area = d3.geo.area(json);
28387 // Heuristic for detecting counterclockwise winding order. Assumes
28388 // that OpenStreetMap polygons are not hemisphere-spanning.
28389 if (area > 2 * Math.PI) {
28390 json.coordinates[0] = json.coordinates[0].reverse();
28391 area = d3.geo.area(json);
28394 return isNaN(area) ? 0 : area;
28398 iD.Background = function(context) {
28399 var dispatch = d3.dispatch('change'),
28400 baseLayer = iD.TileLayer().projection(context.projection),
28401 overlayLayers = [];
28403 var backgroundSources;
28405 function findSource(id) {
28406 return _.find(backgroundSources, function(d) {
28407 return d.id && d.id === id;
28411 function updateImagery() {
28412 var b = background.baseLayerSource(),
28413 o = overlayLayers.map(function (d) { return d.source().id; }).join(','),
28414 q = iD.util.stringQs(location.hash.substring(1));
28417 if (id === 'custom') {
28418 id = 'custom:' + b.template;
28424 delete q.background;
28433 location.replace('#' + iD.util.qsString(q, true));
28435 var imageryUsed = [b.imageryUsed()];
28437 overlayLayers.forEach(function (d) {
28438 var source = d.source();
28439 if (!source.isLocatorOverlay()) {
28440 imageryUsed.push(source.imageryUsed());
28444 var gpx = context.layers().layer('gpx');
28445 if (gpx && gpx.enabled() && gpx.hasGpx()) {
28446 imageryUsed.push('Local GPX');
28449 context.history().imageryUsed(imageryUsed);
28452 function background(selection) {
28453 var base = selection.selectAll('.layer-background')
28457 .insert('div', '.layer-data')
28458 .attr('class', 'layer layer-background');
28460 base.call(baseLayer);
28462 var overlays = selection.selectAll('.layer-overlay')
28463 .data(overlayLayers, function(d) { return d.source().name(); });
28466 .insert('div', '.layer-data')
28467 .attr('class', 'layer layer-overlay');
28469 overlays.each(function(layer) {
28470 d3.select(this).call(layer);
28477 background.sources = function(extent) {
28478 return backgroundSources.filter(function(source) {
28479 return source.intersects(extent);
28483 background.dimensions = function(_) {
28484 baseLayer.dimensions(_);
28486 overlayLayers.forEach(function(layer) {
28487 layer.dimensions(_);
28491 background.baseLayerSource = function(d) {
28492 if (!arguments.length) return baseLayer.source();
28494 baseLayer.source(d);
28501 background.bing = function() {
28502 background.baseLayerSource(findSource('Bing'));
28505 background.showsLayer = function(d) {
28506 return d === baseLayer.source() ||
28507 (d.id === 'custom' && baseLayer.source().id === 'custom') ||
28508 overlayLayers.some(function(l) { return l.source() === d; });
28511 background.overlayLayerSources = function() {
28512 return overlayLayers.map(function (l) { return l.source(); });
28515 background.toggleOverlayLayer = function(d) {
28518 for (var i = 0; i < overlayLayers.length; i++) {
28519 layer = overlayLayers[i];
28520 if (layer.source() === d) {
28521 overlayLayers.splice(i, 1);
28528 layer = iD.TileLayer()
28530 .projection(context.projection)
28531 .dimensions(baseLayer.dimensions());
28533 overlayLayers.push(layer);
28538 background.nudge = function(d, zoom) {
28539 baseLayer.source().nudge(d, zoom);
28544 background.offset = function(d) {
28545 if (!arguments.length) return baseLayer.source().offset();
28546 baseLayer.source().offset(d);
28551 background.load = function(imagery) {
28552 function parseMap(qmap) {
28553 if (!qmap) return false;
28554 var args = qmap.split('/').map(Number);
28555 if (args.length < 3 || args.some(isNaN)) return false;
28556 return iD.geo.Extent([args[1], args[2]]);
28559 var q = iD.util.stringQs(location.hash.substring(1)),
28560 chosen = q.background || q.layer,
28561 extent = parseMap(q.map),
28564 backgroundSources = imagery.map(function(source) {
28565 if (source.type === 'bing') {
28566 return iD.BackgroundSource.Bing(source, dispatch);
28568 return iD.BackgroundSource(source);
28572 backgroundSources.unshift(iD.BackgroundSource.None());
28574 if (!chosen && extent) {
28575 best = _.find(this.sources(extent), function(s) { return s.best(); });
28578 if (chosen && chosen.indexOf('custom:') === 0) {
28579 background.baseLayerSource(iD.BackgroundSource.Custom(chosen.replace(/^custom:/, '')));
28581 background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
28584 var locator = _.find(backgroundSources, function(d) {
28585 return d.overlay && d.default;
28589 background.toggleOverlayLayer(locator);
28592 var overlays = (q.overlays || '').split(',');
28593 overlays.forEach(function(overlay) {
28594 overlay = findSource(overlay);
28595 if (overlay) background.toggleOverlayLayer(overlay);
28599 var gpx = context.layers().layer('gpx');
28600 if (gpx) { gpx.url(q.gpx); }
28604 return d3.rebind(background, dispatch, 'on');
28606 iD.BackgroundSource = function(data) {
28607 var source = _.clone(data),
28609 name = source.name,
28610 best = !!source.best;
28612 source.scaleExtent = data.scaleExtent || [0, 20];
28613 source.overzoom = data.overzoom !== false;
28615 source.offset = function(_) {
28616 if (!arguments.length) return offset;
28621 source.nudge = function(_, zoomlevel) {
28622 offset[0] += _[0] / Math.pow(2, zoomlevel);
28623 offset[1] += _[1] / Math.pow(2, zoomlevel);
28627 source.name = function() {
28631 source.best = function() {
28635 source.imageryUsed = function() {
28636 return source.id || name;
28639 source.url = function(coord) {
28640 return data.template
28641 .replace('{x}', coord[0])
28642 .replace('{y}', coord[1])
28643 // TMS-flipped y coordinate
28644 .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
28645 .replace(/\{z(oom)?\}/, coord[2])
28646 .replace(/\{switch:([^}]+)\}/, function(s, r) {
28647 var subdomains = r.split(',');
28648 return subdomains[(coord[0] + coord[1]) % subdomains.length];
28650 .replace('{u}', function() {
28652 for (var zoom = coord[2]; zoom > 0; zoom--) {
28654 var mask = 1 << (zoom - 1);
28655 if ((coord[0] & mask) !== 0) b++;
28656 if ((coord[1] & mask) !== 0) b += 2;
28663 source.intersects = function(extent) {
28664 extent = extent.polygon();
28665 return !data.polygon || data.polygon.some(function(polygon) {
28666 return iD.geo.polygonIntersectsPolygon(polygon, extent, true);
28670 source.validZoom = function(z) {
28671 return source.scaleExtent[0] <= z &&
28672 (source.overzoom || source.scaleExtent[1] > z);
28675 source.isLocatorOverlay = function() {
28676 return name === 'Locator Overlay';
28679 source.copyrightNotices = function() {};
28684 iD.BackgroundSource.Bing = function(data, dispatch) {
28685 // http://msdn.microsoft.com/en-us/library/ff701716.aspx
28686 // http://msdn.microsoft.com/en-us/library/ff701701.aspx
28688 data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
28690 var bing = iD.BackgroundSource(data),
28691 key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
28692 url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
28693 key + '&jsonp={callback}',
28696 d3.jsonp(url, function(json) {
28697 providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
28699 attribution: provider.attribution,
28700 areas: provider.coverageAreas.map(function(area) {
28702 zoom: [area.zoomMin, area.zoomMax],
28703 extent: iD.geo.Extent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
28711 bing.copyrightNotices = function(zoom, extent) {
28712 zoom = Math.min(zoom, 21);
28713 return providers.filter(function(provider) {
28714 return _.any(provider.areas, function(area) {
28715 return extent.intersects(area.extent) &&
28716 area.zoom[0] <= zoom &&
28717 area.zoom[1] >= zoom;
28719 }).map(function(provider) {
28720 return provider.attribution;
28724 bing.logo = 'bing_maps.png';
28725 bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
28730 iD.BackgroundSource.None = function() {
28731 var source = iD.BackgroundSource({id: 'none', template: ''});
28733 source.name = function() {
28734 return t('background.none');
28737 source.imageryUsed = function() {
28744 iD.BackgroundSource.Custom = function(template) {
28745 var source = iD.BackgroundSource({id: 'custom', template: template});
28747 source.name = function() {
28748 return t('background.custom');
28751 source.imageryUsed = function() {
28752 return 'Custom (' + template + ')';
28757 iD.Features = function(context) {
28758 var major_roads = {
28760 'motorway_link': true,
28762 'trunk_link': true,
28764 'primary_link': true,
28766 'secondary_link': true,
28768 'tertiary_link': true,
28769 'residential': true
28772 var minor_roads = {
28774 'living_street': true,
28776 'unclassified': true,
28786 'pedestrian': true,
28790 var past_futures = {
28792 'construction': true,
28794 'dismantled': true,
28797 'demolished': true,
28798 'obliterated': true
28801 var dispatch = d3.dispatch('change', 'redraw'),
28809 function update() {
28810 _hidden = features.hidden();
28815 function defineFeature(k, filter, max) {
28819 enabled: true, // whether the user wants it enabled..
28821 currentMax: (max || Infinity),
28822 defaultMax: (max || Infinity),
28823 enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
28824 disable: function() { this.enabled = false; this.currentMax = 0; },
28825 hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
28826 autoHidden: function() { return this.hidden() && this.currentMax > 0; }
28831 defineFeature('points', function isPoint(entity, resolver, geometry) {
28832 return geometry === 'point';
28835 defineFeature('major_roads', function isMajorRoad(entity) {
28836 return major_roads[entity.tags.highway];
28839 defineFeature('minor_roads', function isMinorRoad(entity) {
28840 return minor_roads[entity.tags.highway];
28843 defineFeature('paths', function isPath(entity) {
28844 return paths[entity.tags.highway];
28847 defineFeature('buildings', function isBuilding(entity) {
28849 !!entity.tags['building:part'] ||
28850 (!!entity.tags.building && entity.tags.building !== 'no') ||
28851 entity.tags.amenity === 'shelter' ||
28852 entity.tags.parking === 'multi-storey' ||
28853 entity.tags.parking === 'sheds' ||
28854 entity.tags.parking === 'carports' ||
28855 entity.tags.parking === 'garage_boxes'
28859 defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
28860 return geometry === 'area' &&
28861 !_features.buildings.filter(entity) &&
28862 !_features.water.filter(entity);
28865 defineFeature('boundaries', function isBoundary(entity) {
28866 return !!entity.tags.boundary;
28869 defineFeature('water', function isWater(entity) {
28871 !!entity.tags.waterway ||
28872 entity.tags.natural === 'water' ||
28873 entity.tags.natural === 'coastline' ||
28874 entity.tags.natural === 'bay' ||
28875 entity.tags.landuse === 'pond' ||
28876 entity.tags.landuse === 'basin' ||
28877 entity.tags.landuse === 'reservoir' ||
28878 entity.tags.landuse === 'salt_pond'
28882 defineFeature('rail', function isRail(entity) {
28884 !!entity.tags.railway ||
28885 entity.tags.landuse === 'railway'
28887 major_roads[entity.tags.highway] ||
28888 minor_roads[entity.tags.highway] ||
28889 paths[entity.tags.highway]
28893 defineFeature('power', function isPower(entity) {
28894 return !!entity.tags.power;
28897 // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
28898 defineFeature('past_future', function isPastFuture(entity) {
28900 major_roads[entity.tags.highway] ||
28901 minor_roads[entity.tags.highway] ||
28902 paths[entity.tags.highway]
28903 ) { return false; }
28905 var strings = Object.keys(entity.tags);
28907 for (var i = 0; i < strings.length; i++) {
28908 var s = strings[i];
28909 if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
28914 // Lines or areas that don't match another feature filter.
28915 // IMPORTANT: The 'others' feature must be the last one defined,
28916 // so that code in getMatches can skip this test if `hasMatch = true`
28917 defineFeature('others', function isOther(entity, resolver, geometry) {
28918 return (geometry === 'line' || geometry === 'area');
28922 function features() {}
28924 features.features = function() {
28928 features.keys = function() {
28932 features.enabled = function(k) {
28933 if (!arguments.length) {
28934 return _.filter(_keys, function(k) { return _features[k].enabled; });
28936 return _features[k] && _features[k].enabled;
28939 features.disabled = function(k) {
28940 if (!arguments.length) {
28941 return _.reject(_keys, function(k) { return _features[k].enabled; });
28943 return _features[k] && !_features[k].enabled;
28946 features.hidden = function(k) {
28947 if (!arguments.length) {
28948 return _.filter(_keys, function(k) { return _features[k].hidden(); });
28950 return _features[k] && _features[k].hidden();
28953 features.autoHidden = function(k) {
28954 if (!arguments.length) {
28955 return _.filter(_keys, function(k) { return _features[k].autoHidden(); });
28957 return _features[k] && _features[k].autoHidden();
28960 features.enable = function(k) {
28961 if (_features[k] && !_features[k].enabled) {
28962 _features[k].enable();
28967 features.disable = function(k) {
28968 if (_features[k] && _features[k].enabled) {
28969 _features[k].disable();
28974 features.toggle = function(k) {
28975 if (_features[k]) {
28976 (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
28981 features.resetStats = function() {
28982 _.each(_features, function(f) { f.count = 0; });
28986 features.gatherStats = function(d, resolver, dimensions) {
28987 var needsRedraw = false,
28988 type = _.groupBy(d, function(ent) { return ent.type; }),
28989 entities = [].concat(type.relation || [], type.way || [], type.node || []),
28990 currHidden, geometry, matches;
28992 _.each(_features, function(f) { f.count = 0; });
28994 // adjust the threshold for point/building culling based on viewport size..
28995 // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
28996 _cullFactor = dimensions[0] * dimensions[1] / 1000000;
28998 for (var i = 0; i < entities.length; i++) {
28999 geometry = entities[i].geometry(resolver);
29000 if (!(geometry === 'vertex' || geometry === 'relation')) {
29001 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
29002 for (var j = 0; j < matches.length; j++) {
29003 _features[matches[j]].count++;
29008 currHidden = features.hidden();
29009 if (currHidden !== _hidden) {
29010 _hidden = currHidden;
29011 needsRedraw = true;
29015 return needsRedraw;
29018 features.stats = function() {
29019 _.each(_keys, function(k) { _stats[k] = _features[k].count; });
29023 features.clear = function(d) {
29024 for (var i = 0; i < d.length; i++) {
29025 features.clearEntity(d[i]);
29029 features.clearEntity = function(entity) {
29030 delete _cache[iD.Entity.key(entity)];
29033 features.reset = function() {
29037 features.getMatches = function(entity, resolver, geometry) {
29038 if (geometry === 'vertex' || geometry === 'relation') return {};
29040 var ent = iD.Entity.key(entity);
29041 if (!_cache[ent]) {
29045 if (!_cache[ent].matches) {
29049 for (var i = 0; i < _keys.length; i++) {
29050 if (_keys[i] === 'others') {
29051 if (hasMatch) continue;
29053 // Multipolygon members:
29055 // 1. is a way that hasn't matched other "interesting" feature rules,
29056 // 2. and it belongs to a single parent multipolygon relation
29057 // ...then match whatever feature rules the parent multipolygon has matched.
29058 // see #2548, #2887
29061 // For this to work, getMatches must be called on relations before ways.
29063 if (entity.type === 'way') {
29064 var parents = features.getParents(entity, resolver, geometry);
29065 if (parents.length === 1 && parents[0].isMultipolygon()) {
29066 var pkey = iD.Entity.key(parents[0]);
29067 if (_cache[pkey] && _cache[pkey].matches) {
29068 matches = _.clone(_cache[pkey].matches);
29075 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
29076 matches[_keys[i]] = hasMatch = true;
29079 _cache[ent].matches = matches;
29082 return _cache[ent].matches;
29085 features.getParents = function(entity, resolver, geometry) {
29086 if (geometry === 'point') return [];
29088 var ent = iD.Entity.key(entity);
29089 if (!_cache[ent]) {
29093 if (!_cache[ent].parents) {
29095 if (geometry === 'vertex') {
29096 parents = resolver.parentWays(entity);
29097 } else { // 'line', 'area', 'relation'
29098 parents = resolver.parentRelations(entity);
29100 _cache[ent].parents = parents;
29102 return _cache[ent].parents;
29105 features.isHiddenFeature = function(entity, resolver, geometry) {
29106 if (!_hidden.length) return false;
29107 if (!entity.version) return false;
29109 var matches = features.getMatches(entity, resolver, geometry);
29111 for (var i = 0; i < _hidden.length; i++) {
29112 if (matches[_hidden[i]]) return true;
29117 features.isHiddenChild = function(entity, resolver, geometry) {
29118 if (!_hidden.length) return false;
29119 if (!entity.version || geometry === 'point') return false;
29121 var parents = features.getParents(entity, resolver, geometry);
29122 if (!parents.length) return false;
29124 for (var i = 0; i < parents.length; i++) {
29125 if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
29132 features.hasHiddenConnections = function(entity, resolver) {
29133 if (!_hidden.length) return false;
29134 var childNodes, connections;
29136 if (entity.type === 'midpoint') {
29137 childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
29140 childNodes = entity.nodes ? resolver.childNodes(entity) : [];
29141 connections = features.getParents(entity, resolver, entity.geometry(resolver));
29144 // gather ways connected to child nodes..
29145 connections = _.reduce(childNodes, function(result, e) {
29146 return resolver.isShared(e) ? _.union(result, resolver.parentWays(e)) : result;
29149 return connections.length ? _.any(connections, function(e) {
29150 return features.isHidden(e, resolver, e.geometry(resolver));
29154 features.isHidden = function(entity, resolver, geometry) {
29155 if (!_hidden.length) return false;
29156 if (!entity.version) return false;
29158 var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
29159 return fn(entity, resolver, geometry);
29162 features.filter = function(d, resolver) {
29163 if (!_hidden.length) return d;
29166 for (var i = 0; i < d.length; i++) {
29168 if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
29169 result.push(entity);
29175 return d3.rebind(features, dispatch, 'on');
29177 iD.Map = function(context) {
29178 var dimensions = [1, 1],
29179 dispatch = d3.dispatch('move', 'drawn'),
29180 projection = context.projection,
29181 zoom = d3.behavior.zoom()
29182 .translate(projection.translate())
29183 .scale(projection.scale() * 2 * Math.PI)
29184 .scaleExtent([1024, 256 * Math.pow(2, 24)])
29185 .on('zoom', zoomPan),
29186 dblclickEnabled = true,
29187 redrawEnabled = true,
29189 transformed = false,
29191 drawLayers = iD.svg.Layers(projection, context),
29192 drawPoints = iD.svg.Points(projection, context),
29193 drawVertices = iD.svg.Vertices(projection, context),
29194 drawLines = iD.svg.Lines(projection),
29195 drawAreas = iD.svg.Areas(projection),
29196 drawMidpoints = iD.svg.Midpoints(projection, context),
29197 drawLabels = iD.svg.Labels(projection, context),
29204 function map(selection) {
29206 .on('change.map', redraw);
29207 context.background()
29208 .on('change.map', redraw);
29210 .on('redraw.map', redraw);
29213 .on('dblclick.map', dblClick)
29216 supersurface = selection.append('div')
29217 .attr('id', 'supersurface')
29218 .call(iD.util.setTransform, 0, 0);
29220 // Need a wrapper div because Opera can't cope with an absolutely positioned
29221 // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
29222 wrapper = supersurface
29224 .attr('class', 'layer layer-data');
29226 map.surface = surface = wrapper
29228 .selectAll('.surface')
29229 .attr('id', 'surface');
29232 .on('mousedown.zoom', function() {
29233 if (d3.event.button === 2) {
29234 d3.event.stopPropagation();
29237 .on('mouseup.zoom', function() {
29238 if (resetTransform()) redraw();
29240 .on('mousemove.map', function() {
29241 mousemove = d3.event;
29243 .on('mouseover.vertices', function() {
29244 if (map.editable() && !transformed) {
29245 var hover = d3.event.target.__data__;
29246 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
29247 dispatch.drawn({full: false});
29250 .on('mouseout.vertices', function() {
29251 if (map.editable() && !transformed) {
29252 var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__;
29253 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
29254 dispatch.drawn({full: false});
29260 .call(context.background());
29263 context.on('enter.map', function() {
29264 if (map.editable() && !transformed) {
29265 var all = context.intersects(map.extent()),
29266 filter = d3.functor(true),
29267 graph = context.graph();
29269 all = context.features().filter(all, graph);
29271 .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
29272 .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
29273 dispatch.drawn({full: false});
29277 map.dimensions(selection.dimensions());
29279 drawLabels.supersurface(supersurface);
29282 function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }
29284 function drawVector(difference, extent) {
29285 var graph = context.graph(),
29286 features = context.features(),
29287 all = context.intersects(map.extent()),
29291 var complete = difference.complete(map.extent());
29292 data = _.compact(_.values(complete));
29293 filter = function(d) { return d.id in complete; };
29294 features.clear(data);
29297 // force a full redraw if gatherStats detects that a feature
29298 // should be auto-hidden (e.g. points or buildings)..
29299 if (features.gatherStats(all, graph, dimensions)) {
29300 extent = undefined;
29304 data = context.intersects(map.extent().intersection(extent));
29305 var set = d3.set(_.pluck(data, 'id'));
29306 filter = function(d) { return set.has(d.id); };
29310 filter = d3.functor(true);
29314 data = features.filter(data, graph);
29317 .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
29318 .call(drawLines, graph, data, filter)
29319 .call(drawAreas, graph, data, filter)
29320 .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
29321 .call(drawLabels, graph, data, filter, dimensions, !difference && !extent)
29322 .call(drawPoints, graph, data, filter);
29324 dispatch.drawn({full: true});
29327 function editOff() {
29328 context.features().resetStats();
29329 surface.selectAll('.layer-osm *').remove();
29330 dispatch.drawn({full: true});
29333 function dblClick() {
29334 if (!dblclickEnabled) {
29335 d3.event.preventDefault();
29336 d3.event.stopImmediatePropagation();
29340 function zoomPan() {
29341 if (Math.log(d3.event.scale) / Math.LN2 - 8 < minzoom) {
29342 surface.interrupt();
29343 iD.ui.flash(context.container())
29344 .select('.content')
29345 .text(t('cannot_zoom'));
29346 setZoom(context.minEditableZoom(), true);
29348 dispatch.move(map);
29353 .translate(d3.event.translate)
29354 .scale(d3.event.scale / (2 * Math.PI));
29356 var scale = d3.event.scale / transformStart[0],
29357 tX = (d3.event.translate[0] / scale - transformStart[1][0]) * scale,
29358 tY = (d3.event.translate[1] / scale - transformStart[1][1]) * scale;
29360 transformed = true;
29361 iD.util.setTransform(supersurface, tX, tY, scale);
29364 dispatch.move(map);
29367 function resetTransform() {
29368 if (!transformed) return false;
29370 surface.selectAll('.radial-menu').interrupt().remove();
29371 iD.util.setTransform(supersurface, 0, 0);
29372 transformed = false;
29376 function redraw(difference, extent) {
29377 if (!surface || !redrawEnabled) return;
29379 clearTimeout(timeoutId);
29381 // If we are in the middle of a zoom/pan, we can't do differenced redraws.
29382 // It would result in artifacts where differenced entities are redrawn with
29383 // one transform and unchanged entities with another.
29384 if (resetTransform()) {
29385 difference = extent = undefined;
29388 var zoom = String(~~map.zoom());
29389 if (surface.attr('data-zoom') !== zoom) {
29390 surface.attr('data-zoom', zoom)
29391 .classed('low-zoom', zoom <= 16);
29395 supersurface.call(context.background());
29399 if (map.editable()) {
29400 context.loadTiles(projection, dimensions);
29401 drawVector(difference, extent);
29410 projection.scale() * 2 * Math.PI,
29411 projection.translate().slice()];
29417 function queueRedraw() {
29418 clearTimeout(timeoutId);
29419 timeoutId = setTimeout(function() { redraw(); }, 300);
29422 function pointLocation(p) {
29423 var translate = projection.translate(),
29424 scale = projection.scale() * 2 * Math.PI;
29425 return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
29428 function locationPoint(l) {
29429 var translate = projection.translate(),
29430 scale = projection.scale() * 2 * Math.PI;
29431 return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
29434 map.mouse = function() {
29435 var e = mousemove || d3.event, s;
29436 while ((s = e.sourceEvent)) e = s;
29440 map.mouseCoordinates = function() {
29441 return projection.invert(map.mouse());
29444 map.dblclickEnable = function(_) {
29445 if (!arguments.length) return dblclickEnabled;
29446 dblclickEnabled = _;
29450 map.redrawEnable = function(_) {
29451 if (!arguments.length) return redrawEnabled;
29456 function interpolateZoom(_) {
29457 var k = projection.scale(),
29458 t = projection.translate();
29460 surface.node().__chart__ = {
29467 projection.scale(k).translate(t); // undo setZoom projection changes
29469 zoom.event(surface.transition());
29472 function setZoom(_, force) {
29473 if (_ === map.zoom() && !force)
29475 var scale = 256 * Math.pow(2, _),
29476 center = pxCenter(),
29477 l = pointLocation(center);
29478 scale = Math.max(1024, Math.min(256 * Math.pow(2, 24), scale));
29479 projection.scale(scale / (2 * Math.PI));
29481 var t = projection.translate();
29482 l = locationPoint(l);
29483 t[0] += center[0] - l[0];
29484 t[1] += center[1] - l[1];
29485 projection.translate(t);
29486 zoom.translate(projection.translate());
29490 function setCenter(_) {
29491 var c = map.center();
29492 if (_[0] === c[0] && _[1] === c[1])
29494 var t = projection.translate(),
29496 ll = projection(_);
29497 projection.translate([
29498 t[0] - ll[0] + pxC[0],
29499 t[1] - ll[1] + pxC[1]]);
29500 zoom.translate(projection.translate());
29504 map.pan = function(d) {
29505 var t = projection.translate();
29508 projection.translate(t);
29509 zoom.translate(projection.translate());
29510 dispatch.move(map);
29514 map.dimensions = function(_) {
29515 if (!arguments.length) return dimensions;
29516 var center = map.center();
29518 drawLayers.dimensions(dimensions);
29519 context.background().dimensions(dimensions);
29520 projection.clipExtent([[0, 0], dimensions]);
29521 mouse = iD.util.fastMouse(supersurface.node());
29526 function zoomIn(integer) {
29527 interpolateZoom(~~map.zoom() + integer);
29530 function zoomOut(integer) {
29531 interpolateZoom(~~map.zoom() - integer);
29534 map.zoomIn = function() { zoomIn(1); };
29535 map.zoomInFurther = function() { zoomIn(4); };
29537 map.zoomOut = function() { zoomOut(1); };
29538 map.zoomOutFurther = function() { zoomOut(4); };
29540 map.center = function(loc) {
29541 if (!arguments.length) {
29542 return projection.invert(pxCenter());
29545 if (setCenter(loc)) {
29546 dispatch.move(map);
29552 map.zoom = function(z) {
29553 if (!arguments.length) {
29554 return Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8, 0);
29558 surface.interrupt();
29559 iD.ui.flash(context.container())
29560 .select('.content')
29561 .text(t('cannot_zoom'));
29562 z = context.minEditableZoom();
29566 dispatch.move(map);
29572 map.zoomTo = function(entity, zoomLimits) {
29573 var extent = entity.extent(context.graph());
29574 if (!isFinite(extent.area())) return;
29576 var zoom = map.trimmedExtentZoom(extent);
29577 zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
29578 map.centerZoom(extent.center(), Math.min(Math.max(zoom, zoomLimits[0]), zoomLimits[1]));
29581 map.centerZoom = function(loc, z) {
29582 var centered = setCenter(loc),
29583 zoomed = setZoom(z);
29585 if (centered || zoomed) {
29586 dispatch.move(map);
29592 map.centerEase = function(loc) {
29593 var from = map.center().slice(),
29597 surface.one('mousedown.ease', function() {
29601 d3.timer(function() {
29602 if (stop) return true;
29603 map.center(iD.geo.interp(from, loc, (t += 1) / 10));
29609 map.extent = function(_) {
29610 if (!arguments.length) {
29611 return new iD.geo.Extent(projection.invert([0, dimensions[1]]),
29612 projection.invert([dimensions[0], 0]));
29614 var extent = iD.geo.Extent(_);
29615 map.centerZoom(extent.center(), map.extentZoom(extent));
29619 map.trimmedExtent = function(_) {
29620 if (!arguments.length) {
29621 var headerY = 60, footerY = 30, pad = 10;
29622 return new iD.geo.Extent(projection.invert([pad, dimensions[1] - footerY - pad]),
29623 projection.invert([dimensions[0] - pad, headerY + pad]));
29625 var extent = iD.geo.Extent(_);
29626 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
29630 function calcZoom(extent, dim) {
29631 var tl = projection([extent[0][0], extent[1][1]]),
29632 br = projection([extent[1][0], extent[0][1]]);
29634 // Calculate maximum zoom that fits extent
29635 var hFactor = (br[0] - tl[0]) / dim[0],
29636 vFactor = (br[1] - tl[1]) / dim[1],
29637 hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
29638 vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
29639 newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
29644 map.extentZoom = function(_) {
29645 return calcZoom(iD.geo.Extent(_), dimensions);
29648 map.trimmedExtentZoom = function(_) {
29649 var trimY = 120, trimX = 40,
29650 trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
29651 return calcZoom(iD.geo.Extent(_), trimmed);
29654 map.editable = function() {
29655 return map.zoom() >= context.minEditableZoom();
29658 map.minzoom = function(_) {
29659 if (!arguments.length) return minzoom;
29664 map.layers = drawLayers;
29666 return d3.rebind(map, dispatch, 'on');
29668 iD.TileLayer = function() {
29669 var tileSize = 256,
29670 tile = d3.geo.tile(),
29675 transformProp = iD.util.prefixCSSProperty('Transform'),
29676 source = d3.functor('');
29678 function tileSizeAtZoom(d, z) {
29679 return (tileSize * Math.pow(2, z - d[2])) / tileSize;
29682 function atZoom(t, distance) {
29683 var power = Math.pow(2, distance);
29685 Math.floor(t[0] * power),
29686 Math.floor(t[1] * power),
29690 function lookUp(d) {
29691 for (var up = -1; up > -d[2]; up--) {
29692 var tile = atZoom(d, up);
29693 if (cache[source.url(tile)] !== false) {
29699 function uniqueBy(a, n) {
29700 var o = [], seen = {};
29701 for (var i = 0; i < a.length; i++) {
29702 if (seen[a[i][n]] === undefined) {
29704 seen[a[i][n]] = true;
29710 function addSource(d) {
29711 d.push(source.url(d));
29715 // Update tiles based on current state of `projection`.
29716 function background(selection) {
29717 tile.scale(projection.scale() * 2 * Math.PI)
29718 .translate(projection.translate());
29721 projection.scale() * Math.PI - projection.translate()[0],
29722 projection.scale() * Math.PI - projection.translate()[1]];
29724 z = Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
29729 // Derive the tiles onscreen, remove those offscreen and position them.
29730 // Important that this part not depend on `projection` because it's
29731 // rentered when tiles load/error (see #644).
29732 function render(selection) {
29735 if (source.validZoom(z)) {
29736 tile().forEach(function(d) {
29738 if (d[3] === '') return;
29739 if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
29741 if (cache[d[3]] === false && lookUp(d)) {
29742 requests.push(addSource(lookUp(d)));
29746 requests = uniqueBy(requests, 3).filter(function(r) {
29747 // don't re-request tiles which have failed in the past
29748 return cache[r[3]] !== false;
29752 var pixelOffset = [
29753 source.offset()[0] * Math.pow(2, z),
29754 source.offset()[1] * Math.pow(2, z)
29758 cache[d[3]] = true;
29762 .classed('tile-loaded', true);
29766 function error(d) {
29767 cache[d[3]] = false;
29775 function imageTransform(d) {
29776 var _ts = tileSize * Math.pow(2, z - d[2]);
29777 var scale = tileSizeAtZoom(d, z);
29778 return 'translate(' +
29779 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
29780 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
29781 'scale(' + scale + ',' + scale + ')';
29784 var image = selection
29786 .data(requests, function(d) { return d[3]; });
29789 .style(transformProp, imageTransform)
29790 .classed('tile-removing', true)
29792 var tile = d3.select(this);
29793 window.setTimeout(function() {
29794 if (tile.classed('tile-removing')) {
29800 image.enter().append('img')
29801 .attr('class', 'tile')
29802 .attr('src', function(d) { return d[3]; })
29803 .on('error', error)
29807 .style(transformProp, imageTransform)
29808 .classed('tile-removing', false);
29811 background.projection = function(_) {
29812 if (!arguments.length) return projection;
29817 background.dimensions = function(_) {
29818 if (!arguments.length) return tile.size();
29823 background.source = function(_) {
29824 if (!arguments.length) return source;
29827 tile.scaleExtent(source.scaleExtent);
29834 PointTransform: function(projection) {
29835 return function(entity) {
29836 // http://jsperf.com/short-array-join
29837 var pt = projection(entity.loc);
29838 return 'translate(' + pt[0] + ',' + pt[1] + ')';
29842 Path: function(projection, graph, polygon) {
29844 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
29845 project = projection.stream,
29846 path = d3.geo.path()
29847 .projection({stream: function(output) { return polygon ? project(output) : project(clip(output)); }});
29849 return function(entity) {
29850 if (entity.id in cache) {
29851 return cache[entity.id];
29853 return cache[entity.id] = path(entity.asGeoJSON(graph));
29858 OneWaySegments: function(projection, graph, dt) {
29859 return function(entity) {
29865 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
29866 coordinates = graph.childNodes(entity).map(function(n) {
29870 if (entity.tags.oneway === '-1') coordinates.reverse();
29873 type: 'LineString',
29874 coordinates: coordinates
29875 }, projection.stream(clip({
29876 lineStart: function() {},
29877 lineEnd: function() {
29880 point: function(x, y) {
29884 var span = iD.geo.euclideanDistance(a, b) - offset;
29887 var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
29888 dx = dt * Math.cos(angle),
29889 dy = dt * Math.sin(angle),
29890 p = [a[0] + offset * Math.cos(angle),
29891 a[1] + offset * Math.sin(angle)];
29893 var segment = 'M' + a[0] + ',' + a[1] +
29894 'L' + p[0] + ',' + p[1];
29896 for (span -= dt; span >= 0; span -= dt) {
29899 segment += 'L' + p[0] + ',' + p[1];
29902 segment += 'L' + b[0] + ',' + b[1];
29903 segments.push({id: entity.id, index: i, d: segment});
29918 RelationMemberTags: function(graph) {
29919 return function(entity) {
29920 var tags = entity.tags;
29921 graph.parentRelations(entity).forEach(function(relation) {
29922 var type = relation.tags.type;
29923 if (type === 'multipolygon' || type === 'boundary') {
29924 tags = _.extend({}, relation.tags, tags);
29931 iD.svg.Areas = function(projection) {
29932 // Patterns only work in Firefox when set directly on element.
29933 // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
29935 wetland: 'wetland',
29938 construction: 'construction',
29939 military: 'construction',
29940 cemetery: 'cemetery',
29941 grave_yard: 'cemetery',
29944 farmland: 'farmland',
29948 var patternKeys = ['landuse', 'natural', 'amenity'];
29950 function setPattern(d) {
29951 for (var i = 0; i < patternKeys.length; i++) {
29952 if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
29953 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
29957 this.style.fill = this.style.stroke = '';
29960 return function drawAreas(surface, graph, entities, filter) {
29961 var path = iD.svg.Path(projection, graph, true),
29965 for (var i = 0; i < entities.length; i++) {
29966 var entity = entities[i];
29967 if (entity.geometry(graph) !== 'area') continue;
29969 multipolygon = iD.geo.isSimpleMultipolygonOuterMember(entity, graph);
29970 if (multipolygon) {
29971 areas[multipolygon.id] = {
29972 entity: multipolygon.mergeTags(entity.tags),
29973 area: Math.abs(entity.area(graph))
29975 } else if (!areas[entity.id]) {
29976 areas[entity.id] = {
29978 area: Math.abs(entity.area(graph))
29983 areas = d3.values(areas).filter(function hasPath(a) { return path(a.entity); });
29984 areas.sort(function areaSort(a, b) { return b.area - a.area; });
29985 areas = _.pluck(areas, 'entity');
29987 var strokes = areas.filter(function(area) {
29988 return area.type === 'way';
29998 var clipPaths = surface.selectAll('defs').selectAll('.clipPath')
30000 .data(data.clip, iD.Entity.key);
30003 .append('clipPath')
30004 .attr('class', 'clipPath')
30005 .attr('id', function(entity) { return entity.id + '-clippath'; })
30008 clipPaths.selectAll('path')
30014 var areagroup = surface
30015 .selectAll('.layer-areas')
30016 .selectAll('g.areagroup')
30017 .data(['fill', 'shadow', 'stroke']);
30021 .attr('class', function(d) { return 'layer areagroup area-' + d; });
30023 var paths = areagroup
30026 .data(function(layer) { return data[layer]; }, iD.Entity.key);
30028 // Remove exiting areas first, so they aren't included in the `fills`
30029 // array used for sorting below (https://github.com/openstreetmap/iD/issues/1903).
30033 var fills = surface.selectAll('.area-fill path.area')[0];
30035 var bisect = d3.bisector(function(node) {
30036 return -node.__data__.area(graph);
30039 function sortedByArea(entity) {
30040 if (this.__data__ === 'fill') {
30041 return fills[bisect(fills, -entity.area(graph))];
30046 .insert('path', sortedByArea)
30047 .each(function(entity) {
30048 var layer = this.parentNode.__data__;
30050 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
30052 if (layer === 'fill') {
30053 this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
30054 setPattern.apply(this, arguments);
30057 .call(iD.svg.TagClasses());
30064 A standalone SVG element that contains only a `defs` sub-element. To be
30065 used once globally, since defs IDs must be unique within a document.
30067 iD.svg.Defs = function(context) {
30069 function SVGSpriteDefinition(id, href) {
30070 return function(defs) {
30071 d3.xml(href, 'image/svg+xml', function(err, svg) {
30073 defs.node().appendChild(
30074 d3.select(svg.documentElement).attr('id', id).node()
30080 return function drawDefs(selection) {
30081 var defs = selection.append('defs');
30084 defs.append('marker')
30086 id: 'oneway-marker',
30087 viewBox: '0 0 10 10',
30092 markerUnits: 'strokeWidth',
30096 .attr('class', 'oneway')
30097 .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')
30098 .attr('stroke', 'none')
30099 .attr('fill', '#000')
30100 .attr('opacity', '0.5');
30103 var patterns = defs.selectAll('pattern')
30105 // pattern name, pattern image name
30106 ['wetland', 'wetland'],
30107 ['construction', 'construction'],
30108 ['cemetery', 'cemetery'],
30109 ['orchard', 'orchard'],
30110 ['farmland', 'farmland'],
30119 return 'pattern-' + d[0];
30123 patternUnits: 'userSpaceOnUse'
30126 patterns.append('rect')
30132 'class': function (d) {
30133 return 'pattern-color-' + d[0];
30137 patterns.append('image')
30144 .attr('xlink:href', function (d) {
30145 return context.imagePath('pattern/' + d[1] + '.png');
30150 .data([12, 18, 20, 32, 45])
30151 .enter().append('clipPath')
30152 .attr('id', function (d) {
30153 return 'clip-square-' + d;
30158 .attr('width', function (d) {
30161 .attr('height', function (d) {
30165 defs.call(SVGSpriteDefinition(
30167 context.imagePath('iD-sprite.svg')));
30169 defs.call(SVGSpriteDefinition(
30171 context.imagePath('maki-sprite.svg')));
30174 iD.svg.Gpx = function(projection, context) {
30175 var showLabels = true,
30179 if (iD.svg.Gpx.initialized) return; // run once
30181 iD.svg.Gpx.geojson = {};
30182 iD.svg.Gpx.enabled = true;
30185 d3.event.stopPropagation();
30186 d3.event.preventDefault();
30187 d3.event.dataTransfer.dropEffect = 'copy';
30191 .attr('dropzone', 'copy')
30192 .on('drop.localgpx', function() {
30193 d3.event.stopPropagation();
30194 d3.event.preventDefault();
30195 if (!iD.detect().filedrop) return;
30196 drawGpx.files(d3.event.dataTransfer.files);
30198 .on('dragenter.localgpx', over)
30199 .on('dragexit.localgpx', over)
30200 .on('dragover.localgpx', over);
30202 iD.svg.Gpx.initialized = true;
30206 function drawGpx(surface) {
30207 var geojson = iD.svg.Gpx.geojson,
30208 enabled = iD.svg.Gpx.enabled;
30210 layer = surface.selectAll('.layer-gpx')
30211 .data(enabled ? [0] : []);
30215 .attr('class', 'layer-gpx');
30227 .attr('class', 'gpx');
30232 var path = d3.geo.path()
30233 .projection(projection);
30239 var labels = layer.selectAll('text')
30240 .data(showLabels && geojson.features ? geojson.features : []);
30244 .attr('class', 'gpx')
30245 .text(function(d) {
30246 return d.properties.desc || d.properties.name;
30253 .attr('x', function(d) {
30254 var centroid = path.centroid(d);
30255 return centroid[0] + 7;
30257 .attr('y', function(d) {
30258 var centroid = path.centroid(d);
30259 return centroid[1];
30264 function toDom(x) {
30265 return (new DOMParser()).parseFromString(x, 'text/xml');
30268 function redraw() {
30269 context.pan([0,0]);
30272 drawGpx.showLabels = function(_) {
30273 if (!arguments.length) return showLabels;
30278 drawGpx.enabled = function(_) {
30279 if (!arguments.length) return iD.svg.Gpx.enabled;
30280 iD.svg.Gpx.enabled = _;
30284 drawGpx.hasGpx = function() {
30285 var geojson = iD.svg.Gpx.geojson;
30286 return (!(_.isEmpty(geojson) || _.isEmpty(geojson.features)));
30289 drawGpx.geojson = function(gj) {
30290 if (!arguments.length) return iD.svg.Gpx.geojson;
30291 if (_.isEmpty(gj) || _.isEmpty(gj.features)) return this;
30292 iD.svg.Gpx.geojson = gj;
30296 drawGpx.url = function(url) {
30297 d3.text(url, function(err, data) {
30299 drawGpx.geojson(toGeoJSON.gpx(toDom(data)));
30306 drawGpx.files = function(fileList) {
30307 var f = fileList[0],
30308 reader = new FileReader();
30310 reader.onload = function(e) {
30311 drawGpx.geojson(toGeoJSON.gpx(toDom(e.target.result))).fitZoom();
30315 reader.readAsText(f);
30319 drawGpx.fitZoom = function() {
30320 if (!this.hasGpx()) return this;
30321 var geojson = iD.svg.Gpx.geojson;
30323 var map = context.map(),
30324 viewport = map.trimmedExtent().polygon(),
30325 coords = _.reduce(geojson.features, function(coords, feature) {
30326 var c = feature.geometry.coordinates;
30327 return _.union(coords, feature.geometry.type === 'Point' ? [c] : c);
30330 if (!iD.geo.polygonIntersectsPolygon(viewport, coords, true)) {
30331 var extent = iD.geo.Extent(d3.geo.bounds(geojson));
30332 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
30341 iD.svg.Icon = function(name, svgklass, useklass) {
30342 return function drawIcon(selection) {
30343 selection.selectAll('svg')
30347 .attr('class', 'icon ' + (svgklass || ''))
30349 .attr('xlink:href', name)
30350 .attr('class', useklass);
30353 iD.svg.Labels = function(projection, context) {
30354 var path = d3.geo.path().projection(projection);
30356 // Replace with dict and iterate over entities tags instead?
30357 var label_stack = [
30358 ['line', 'aeroway'],
30359 ['line', 'highway'],
30360 ['line', 'railway'],
30361 ['line', 'waterway'],
30362 ['area', 'aeroway'],
30363 ['area', 'amenity'],
30364 ['area', 'building'],
30365 ['area', 'historic'],
30366 ['area', 'leisure'],
30367 ['area', 'man_made'],
30368 ['area', 'natural'],
30370 ['area', 'tourism'],
30371 ['point', 'aeroway'],
30372 ['point', 'amenity'],
30373 ['point', 'building'],
30374 ['point', 'historic'],
30375 ['point', 'leisure'],
30376 ['point', 'man_made'],
30377 ['point', 'natural'],
30379 ['point', 'tourism'],
30385 var default_size = 12;
30387 var font_sizes = label_stack.map(function(d) {
30388 var style = iD.util.getStyle('text.' + d[0] + '.tag-' + d[1]),
30389 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
30390 if (m) return parseInt(m[1], 10);
30392 style = iD.util.getStyle('text.' + d[0]);
30393 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
30394 if (m) return parseInt(m[1], 10);
30396 return default_size;
30401 var pointOffsets = [
30402 [15, -11, 'start'], // right
30403 [10, -11, 'start'], // unused right now
30407 var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25,
30408 75, 20, 80, 15, 95, 10, 90, 5, 95];
30411 var noIcons = ['building', 'landuse', 'natural'];
30412 function blacklisted(preset) {
30413 return _.any(noIcons, function(s) {
30414 return preset.id.indexOf(s) >= 0;
30418 function get(array, prop) {
30419 return function(d, i) { return array[i][prop]; };
30422 var textWidthCache = {};
30424 function textWidth(text, size, elem) {
30425 var c = textWidthCache[size];
30426 if (!c) c = textWidthCache[size] = {};
30432 c[text] = elem.getComputedTextLength();
30436 var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
30437 if (str === null) {
30438 return size / 3 * 2 * text.length;
30440 return size / 3 * (2 * text.length + str.length);
30445 function drawLineLabels(group, entities, filter, classes, labels) {
30446 var texts = group.selectAll('text.' + classes)
30448 .data(entities, iD.Entity.key);
30452 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
30453 .append('textPath')
30454 .attr('class', 'textpath');
30457 texts.selectAll('.textpath')
30459 .data(entities, iD.Entity.key)
30461 'startOffset': '50%',
30462 'xlink:href': function(d) { return '#labelpath-' + d.id; }
30464 .text(iD.util.displayName);
30466 texts.exit().remove();
30469 function drawLinePaths(group, entities, filter, classes, labels) {
30470 var halos = group.selectAll('path')
30472 .data(entities, iD.Entity.key);
30476 .style('stroke-width', get(labels, 'font-size'))
30477 .attr('id', function(d) { return 'labelpath-' + d.id; })
30478 .attr('class', classes);
30480 halos.attr('d', get(labels, 'lineString'));
30482 halos.exit().remove();
30485 function drawPointLabels(group, entities, filter, classes, labels) {
30486 var texts = group.selectAll('text.' + classes)
30488 .data(entities, iD.Entity.key);
30492 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; });
30494 texts.attr('x', get(labels, 'x'))
30495 .attr('y', get(labels, 'y'))
30496 .style('text-anchor', get(labels, 'textAnchor'))
30497 .text(iD.util.displayName)
30498 .each(function(d, i) { textWidth(iD.util.displayName(d), labels[i].height, this); });
30500 texts.exit().remove();
30504 function drawAreaLabels(group, entities, filter, classes, labels) {
30505 entities = entities.filter(hasText);
30506 labels = labels.filter(hasText);
30507 return drawPointLabels(group, entities, filter, classes, labels);
30509 function hasText(d, i) {
30510 return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
30514 function drawAreaIcons(group, entities, filter, classes, labels) {
30515 var icons = group.selectAll('use')
30517 .data(entities, iD.Entity.key);
30521 .attr('class', 'icon areaicon')
30522 .attr('width', '18px')
30523 .attr('height', '18px');
30525 icons.attr('transform', get(labels, 'transform'))
30526 .attr('xlink:href', function(d) {
30527 var icon = context.presets().match(d, context.graph()).icon;
30528 return '#' + icon + (icon === 'hairdresser' ? '-24': '-18'); // workaround: maki hairdresser-18 broken?
30532 icons.exit().remove();
30535 function reverse(p) {
30536 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
30537 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
30540 function lineString(nodes) {
30541 return 'M' + nodes.join('L');
30544 function subpath(nodes, from, to) {
30545 function segmentLength(i) {
30546 var dx = nodes[i][0] - nodes[i + 1][0];
30547 var dy = nodes[i][1] - nodes[i + 1][1];
30548 return Math.sqrt(dx * dx + dy * dy);
30552 start, end, i0, i1;
30553 for (var i = 0; i < nodes.length - 1; i++) {
30554 var current = segmentLength(i);
30556 if (!start && sofar + current >= from) {
30557 portion = (from - sofar) / current;
30559 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
30560 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
30564 if (!end && sofar + current >= to) {
30565 portion = (to - sofar) / current;
30567 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
30568 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
30575 var ret = nodes.slice(i0, i1);
30576 ret.unshift(start);
30582 function hideOnMouseover() {
30583 var layers = d3.select(this)
30584 .selectAll('.layer-label, .layer-halo');
30586 layers.selectAll('.proximate')
30587 .classed('proximate', false);
30589 var mouse = context.mouse(),
30591 rect = [mouse[0] - pad, mouse[1] - pad, mouse[0] + pad, mouse[1] + pad],
30592 ids = _.pluck(rtree.search(rect), 'id');
30594 if (!ids.length) return;
30595 layers.selectAll('.' + ids.join(', .'))
30596 .classed('proximate', true);
30599 var rtree = rbush(),
30602 function drawLabels(surface, graph, entities, filter, dimensions, fullRedraw) {
30603 var hidePoints = !surface.selectAll('.node.point').node();
30605 var labelable = [], i, k, entity;
30606 for (i = 0; i < label_stack.length; i++) labelable.push([]);
30612 for (i = 0; i < entities.length; i++) {
30613 rtree.remove(rectangles[entities[i].id]);
30617 // Split entities into groups specified by label_stack
30618 for (i = 0; i < entities.length; i++) {
30619 entity = entities[i];
30620 var geometry = entity.geometry(graph);
30622 if (geometry === 'vertex')
30624 if (hidePoints && geometry === 'point')
30627 var preset = geometry === 'area' && context.presets().match(entity, graph),
30628 icon = preset && !blacklisted(preset) && preset.icon;
30630 if (!icon && !iD.util.displayName(entity))
30633 for (k = 0; k < label_stack.length; k++) {
30634 if (geometry === label_stack[k][0] && entity.tags[label_stack[k][1]]) {
30635 labelable[k].push(entity);
30653 // Try and find a valid label for labellable entities
30654 for (k = 0; k < labelable.length; k++) {
30655 var font_size = font_sizes[k];
30656 for (i = 0; i < labelable[k].length; i++) {
30657 entity = labelable[k][i];
30658 var name = iD.util.displayName(entity),
30659 width = name && textWidth(name, font_size),
30661 if (entity.geometry(graph) === 'point') {
30662 p = getPointLabel(entity, width, font_size);
30663 } else if (entity.geometry(graph) === 'line') {
30664 p = getLineLabel(entity, width, font_size);
30665 } else if (entity.geometry(graph) === 'area') {
30666 p = getAreaLabel(entity, width, font_size);
30669 p.classes = entity.geometry(graph) + ' tag-' + label_stack[k][1];
30670 positions[entity.geometry(graph)].push(p);
30671 labelled[entity.geometry(graph)].push(entity);
30676 function getPointLabel(entity, width, height) {
30677 var coord = projection(entity.loc),
30679 offset = pointOffsets[0],
30683 x: coord[0] + offset[0],
30684 y: coord[1] + offset[1],
30685 textAnchor: offset[2]
30687 var rect = [p.x - m, p.y - m, p.x + width + m, p.y + height + m];
30688 if (tryInsert(rect, entity.id)) return p;
30692 function getLineLabel(entity, width, height) {
30693 var nodes = _.pluck(graph.childNodes(entity), 'loc').map(projection),
30694 length = iD.geo.pathLength(nodes);
30695 if (length < width + 20) return;
30697 for (var i = 0; i < lineOffsets.length; i++) {
30698 var offset = lineOffsets[i],
30699 middle = offset / 100 * length,
30700 start = middle - width/2;
30701 if (start < 0 || start + width > length) continue;
30702 var sub = subpath(nodes, start, start + width),
30703 rev = reverse(sub),
30705 Math.min(sub[0][0], sub[sub.length - 1][0]) - 10,
30706 Math.min(sub[0][1], sub[sub.length - 1][1]) - 10,
30707 Math.max(sub[0][0], sub[sub.length - 1][0]) + 20,
30708 Math.max(sub[0][1], sub[sub.length - 1][1]) + 30
30710 if (rev) sub = sub.reverse();
30711 if (tryInsert(rect, entity.id)) return {
30712 'font-size': height + 2,
30713 lineString: lineString(sub),
30714 startOffset: offset + '%'
30719 function getAreaLabel(entity, width, height) {
30720 var centroid = path.centroid(entity.asGeoJSON(graph, true)),
30721 extent = entity.extent(graph),
30722 entitywidth = projection(extent[1])[0] - projection(extent[0])[0],
30725 if (isNaN(centroid[0]) || entitywidth < 20) return;
30727 var iconX = centroid[0] - (iconSize/2),
30728 iconY = centroid[1] - (iconSize/2),
30729 textOffset = iconSize + 5;
30732 transform: 'translate(' + iconX + ',' + iconY + ')'
30735 if (width && entitywidth >= width + 20) {
30737 p.y = centroid[1] + textOffset;
30738 p.textAnchor = 'middle';
30740 rect = [p.x - width/2, p.y, p.x + width/2, p.y + height + textOffset];
30742 rect = [iconX, iconY, iconX + iconSize, iconY + iconSize];
30745 if (tryInsert(rect, entity.id)) return p;
30749 function tryInsert(rect, id) {
30750 // Check that label is visible
30751 if (rect[0] < 0 || rect[1] < 0 || rect[2] > dimensions[0] ||
30752 rect[3] > dimensions[1]) return false;
30753 var v = rtree.search(rect).length === 0;
30756 rtree.insert(rect);
30757 rectangles[id] = rect;
30762 var label = surface.selectAll('.layer-label'),
30763 halo = surface.selectAll('.layer-halo');
30766 drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
30767 drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
30770 drawLinePaths(halo, labelled.line, filter, '', positions.line);
30771 drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
30772 drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
30775 drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
30776 drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
30777 drawAreaIcons(label, labelled.area, filter, 'arealabel-icon', positions.area);
30780 drawLabels.supersurface = function(supersurface) {
30782 .on('mousemove.hidelabels', hideOnMouseover)
30783 .on('mousedown.hidelabels', function () {
30784 supersurface.on('mousemove.hidelabels', null);
30786 .on('mouseup.hidelabels', function () {
30787 supersurface.on('mousemove.hidelabels', hideOnMouseover);
30793 iD.svg.Layers = function(projection, context) {
30794 var svg = d3.select(null),
30796 { id: 'osm', layer: iD.svg.Osm(projection, context) },
30797 { id: 'gpx', layer: iD.svg.Gpx(projection, context) },
30798 { id: 'mapillary-images', layer: iD.svg.MapillaryImages(projection, context) },
30799 { id: 'mapillary-signs', layer: iD.svg.MapillarySigns(projection, context) }
30803 function drawLayers(selection) {
30804 svg = selection.selectAll('.surface')
30809 .attr('class', 'surface')
30812 var groups = svg.selectAll('.data-layer')
30817 .attr('class', function(d) { return 'data-layer data-layer-' + d.id; });
30820 .each(function(d) { d3.select(this).call(d.layer); });
30826 drawLayers.all = function() {
30830 drawLayers.layer = function(id) {
30831 var obj = _.find(layers, 'id', id);
30832 return obj && obj.layer;
30835 drawLayers.only = function(what) {
30836 var arr = [].concat(what);
30837 drawLayers.remove(_.difference(_.pluck(layers, 'id'), arr));
30841 drawLayers.remove = function(what) {
30842 var arr = [].concat(what);
30843 arr.forEach(function(id) {
30844 layers = _.reject(layers, 'id', id);
30849 drawLayers.add = function(what) {
30850 var arr = [].concat(what);
30851 arr.forEach(function(obj) {
30852 if ('id' in obj && 'layer' in obj) {
30859 drawLayers.dimensions = function(_) {
30860 if (!arguments.length) return svg.dimensions();
30862 layers.forEach(function(obj) {
30863 if (obj.layer.dimensions) {
30864 obj.layer.dimensions(_);
30873 iD.svg.Lines = function(projection) {
30875 var highway_stack = {
30890 function waystack(a, b) {
30891 var as = 0, bs = 0;
30893 if (a.tags.highway) { as -= highway_stack[a.tags.highway]; }
30894 if (b.tags.highway) { bs -= highway_stack[b.tags.highway]; }
30898 return function drawLines(surface, graph, entities, filter) {
30899 var ways = [], pathdata = {}, onewaydata = {},
30900 getPath = iD.svg.Path(projection, graph);
30902 for (var i = 0; i < entities.length; i++) {
30903 var entity = entities[i],
30904 outer = iD.geo.simpleMultipolygonOuterMember(entity, graph);
30906 ways.push(entity.mergeTags(outer.tags));
30907 } else if (entity.geometry(graph) === 'line') {
30912 ways = ways.filter(getPath);
30914 pathdata = _.groupBy(ways, function(way) { return way.layer(); });
30916 _.forOwn(pathdata, function(v, k) {
30917 onewaydata[k] = _(v)
30918 .filter(function(d) { return d.isOneWay(); })
30919 .map(iD.svg.OneWaySegments(projection, graph, 35))
30924 var layergroup = surface
30925 .selectAll('.layer-lines')
30926 .selectAll('g.layergroup')
30927 .data(d3.range(-10, 11));
30931 .attr('class', function(d) { return 'layer layergroup layer' + String(d); });
30934 var linegroup = layergroup
30935 .selectAll('g.linegroup')
30936 .data(['shadow', 'casing', 'stroke']);
30940 .attr('class', function(d) { return 'layer linegroup line-' + d; });
30943 var lines = linegroup
30947 function() { return pathdata[this.parentNode.parentNode.__data__] || []; },
30951 // Optimization: call simple TagClasses only on enter selection. This
30952 // works because iD.Entity.key is defined to include the entity v attribute.
30955 .attr('class', function(d) { return 'way line ' + this.parentNode.__data__ + ' ' + d.id; })
30956 .call(iD.svg.TagClasses());
30960 .attr('d', getPath)
30961 .call(iD.svg.TagClasses().tags(iD.svg.RelationMemberTags(graph)));
30967 var onewaygroup = layergroup
30968 .selectAll('g.onewaygroup')
30971 onewaygroup.enter()
30973 .attr('class', 'layer onewaygroup');
30976 var oneways = onewaygroup
30980 function() { return onewaydata[this.parentNode.parentNode.__data__] || []; },
30981 function(d) { return [d.id, d.index]; }
30986 .attr('class', 'oneway')
30987 .attr('marker-mid', 'url(#oneway-marker)');
30990 .attr('d', function(d) { return d.d; });
30992 if (iD.detect().ie) {
30993 oneways.each(function() { this.parentNode.insertBefore(this, this); });
31001 iD.svg.MapillaryImages = function(projection, context) {
31002 var debouncedRedraw = _.debounce(function () { context.pan([0,0]); }, 1000),
31004 layer = d3.select(null),
31009 if (iD.svg.MapillaryImages.initialized) return; // run once
31010 iD.svg.MapillaryImages.enabled = false;
31011 iD.svg.MapillaryImages.initialized = true;
31014 function getMapillary() {
31015 if (iD.services.mapillary && !_mapillary) {
31016 _mapillary = iD.services.mapillary().on('loadedImages', debouncedRedraw);
31017 } else if (!iD.services.mapillary && _mapillary) {
31023 function showThumbnail(image) {
31024 var mapillary = getMapillary();
31025 if (!mapillary) return;
31027 var thumb = mapillary.selectedThumbnail(),
31028 posX = projection(image.loc)[0],
31029 width = layer.dimensions()[0],
31030 position = (posX < width / 2) ? 'right' : 'left';
31033 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31034 .classed('selected', function(d) { return d.key === thumb.key; });
31037 mapillary.showThumbnail(image.key, position);
31040 function hideThumbnail() {
31041 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31042 .classed('selected', false);
31044 var mapillary = getMapillary();
31046 mapillary.hideThumbnail();
31050 function showLayer() {
31053 .style('opacity', 0)
31056 .style('opacity', 1)
31057 .each('end', debouncedRedraw);
31060 function hideLayer() {
31061 debouncedRedraw.cancel();
31066 .style('opacity', 0)
31067 .each('end', editOff);
31070 function editOn() {
31071 layer.style('display', 'block');
31074 function editOff() {
31075 layer.selectAll('.viewfield-group').remove();
31076 layer.style('display', 'none');
31079 function transform(d) {
31080 var t = iD.svg.PointTransform(projection)(d);
31081 if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
31085 function update() {
31086 var mapillary = getMapillary(),
31087 data = (mapillary ? mapillary.images(projection, layer.dimensions()) : []);
31089 var markers = layer.selectAll('.viewfield-group')
31090 .data(data, function(d) { return d.key; });
31093 var enter = markers.enter()
31095 .attr('class', 'viewfield-group');
31097 enter.append('path')
31098 .attr('class', 'viewfield')
31099 .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
31100 .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');
31102 enter.append('circle')
31113 .attr('transform', transform);
31116 function drawImages(selection) {
31117 var enabled = iD.svg.MapillaryImages.enabled,
31118 mapillary = getMapillary();
31120 layer = selection.selectAll('.layer-mapillary-images')
31121 .data(mapillary ? [0] : []);
31125 .attr('class', 'layer-mapillary-images')
31126 .style('display', enabled ? 'block' : 'none')
31127 .on('click', function() { // deselect/select
31128 var mapillary = getMapillary();
31129 if (!mapillary) return;
31130 var d = d3.event.target.__data__,
31131 thumb = mapillary.selectedThumbnail();
31132 if (thumb && thumb.key === d.key) {
31135 mapillary.selectedThumbnail(d);
31136 context.map().centerEase(d.loc);
31140 .on('mouseover', function() {
31141 var mapillary = getMapillary();
31142 if (!mapillary) return;
31143 showThumbnail(d3.event.target.__data__);
31145 .on('mouseout', function() {
31146 var mapillary = getMapillary();
31147 if (!mapillary) return;
31148 var thumb = mapillary.selectedThumbnail();
31150 showThumbnail(thumb);
31160 if (mapillary && ~~context.map().zoom() >= minZoom) {
31163 mapillary.loadImages(projection, layer.dimensions());
31170 drawImages.enabled = function(_) {
31171 if (!arguments.length) return iD.svg.MapillaryImages.enabled;
31172 iD.svg.MapillaryImages.enabled = _;
31173 if (iD.svg.MapillaryImages.enabled) {
31181 drawImages.supported = function() {
31182 return !!getMapillary();
31185 drawImages.dimensions = function(_) {
31186 if (!arguments.length) return layer.dimensions();
31187 layer.dimensions(_);
31194 iD.svg.MapillarySigns = function(projection, context) {
31195 var debouncedRedraw = _.debounce(function () { context.pan([0,0]); }, 1000),
31197 layer = d3.select(null),
31202 if (iD.svg.MapillarySigns.initialized) return; // run once
31203 iD.svg.MapillarySigns.enabled = false;
31204 iD.svg.MapillarySigns.initialized = true;
31207 function getMapillary() {
31208 if (iD.services.mapillary && !_mapillary) {
31209 _mapillary = iD.services.mapillary().on('loadedSigns', debouncedRedraw);
31210 } else if (!iD.services.mapillary && _mapillary) {
31216 function showThumbnail(image) {
31217 var mapillary = getMapillary();
31218 if (!mapillary) return;
31220 var thumb = mapillary.selectedThumbnail(),
31221 posX = projection(image.loc)[0],
31222 width = layer.dimensions()[0],
31223 position = (posX < width / 2) ? 'right' : 'left';
31226 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31227 .classed('selected', function(d) { return d.key === thumb.key; });
31230 mapillary.showThumbnail(image.key, position);
31233 function hideThumbnail() {
31234 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31235 .classed('selected', false);
31237 var mapillary = getMapillary();
31239 mapillary.hideThumbnail();
31243 function showLayer() {
31248 function hideLayer() {
31249 debouncedRedraw.cancel();
31254 function editOn() {
31255 layer.style('display', 'block');
31258 function editOff() {
31259 layer.selectAll('.icon-sign').remove();
31260 layer.style('display', 'none');
31263 function update() {
31264 var mapillary = getMapillary(),
31265 data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []);
31267 var signs = layer.selectAll('.icon-sign')
31268 .data(data, function(d) { return d.key; });
31271 var enter = signs.enter()
31272 .append('foreignObject')
31273 .attr('class', 'icon-sign')
31274 .attr('width', '32px') // for Firefox
31275 .attr('height', '32px'); // for Firefox
31278 .append('xhtml:body')
31279 .html(mapillary.signHTML);
31282 .on('click', function(d) { // deselect/select
31283 var mapillary = getMapillary();
31284 if (!mapillary) return;
31285 var thumb = mapillary.selectedThumbnail();
31286 if (thumb && thumb.key === d.key) {
31289 mapillary.selectedThumbnail(d);
31290 context.map().centerEase(d.loc);
31294 .on('mouseover', showThumbnail)
31295 .on('mouseout', function() {
31296 var mapillary = getMapillary();
31297 if (!mapillary) return;
31298 var thumb = mapillary.selectedThumbnail();
31300 showThumbnail(thumb);
31312 .attr('transform', iD.svg.PointTransform(projection));
31315 function drawSigns(selection) {
31316 var enabled = iD.svg.MapillarySigns.enabled,
31317 mapillary = getMapillary();
31319 layer = selection.selectAll('.layer-mapillary-signs')
31320 .data(mapillary ? [0] : []);
31324 .attr('class', 'layer-mapillary-signs')
31325 .style('display', enabled ? 'block' : 'none')
31326 .attr('transform', 'translate(-16, -16)'); // center signs on loc
31332 if (mapillary && ~~context.map().zoom() >= minZoom) {
31335 mapillary.loadSigns(context, projection, layer.dimensions());
31342 drawSigns.enabled = function(_) {
31343 if (!arguments.length) return iD.svg.MapillarySigns.enabled;
31344 iD.svg.MapillarySigns.enabled = _;
31345 if (iD.svg.MapillarySigns.enabled) {
31353 drawSigns.supported = function() {
31354 var mapillary = getMapillary();
31355 return (mapillary && mapillary.signsSupported());
31358 drawSigns.dimensions = function(_) {
31359 if (!arguments.length) return layer.dimensions();
31360 layer.dimensions(_);
31367 iD.svg.Midpoints = function(projection, context) {
31368 return function drawMidpoints(surface, graph, entities, filter, extent) {
31369 var poly = extent.polygon(),
31372 for (var i = 0; i < entities.length; i++) {
31373 var entity = entities[i];
31375 if (entity.type !== 'way')
31377 if (!filter(entity))
31379 if (context.selectedIDs().indexOf(entity.id) < 0)
31382 var nodes = graph.childNodes(entity);
31383 for (var j = 0; j < nodes.length - 1; j++) {
31387 id = [a.id, b.id].sort().join('-');
31389 if (midpoints[id]) {
31390 midpoints[id].parents.push(entity);
31392 if (iD.geo.euclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
31393 var point = iD.geo.interp(a.loc, b.loc, 0.5),
31396 if (extent.intersects(point)) {
31399 for (var k = 0; k < 4; k++) {
31400 point = iD.geo.lineIntersection([a.loc, b.loc], [poly[k], poly[k+1]]);
31402 iD.geo.euclideanDistance(projection(a.loc), projection(point)) > 20 &&
31403 iD.geo.euclideanDistance(projection(b.loc), projection(point)) > 20)
31416 edge: [a.id, b.id],
31425 function midpointFilter(d) {
31426 if (midpoints[d.id])
31429 for (var i = 0; i < d.parents.length; i++)
31430 if (filter(d.parents[i]))
31436 var groups = surface.selectAll('.layer-hit').selectAll('g.midpoint')
31437 .filter(midpointFilter)
31438 .data(_.values(midpoints), function(d) { return d.id; });
31440 var enter = groups.enter()
31441 .insert('g', ':first-child')
31442 .attr('class', 'midpoint');
31444 enter.append('polygon')
31445 .attr('points', '-6,8 10,0 -6,-8')
31446 .attr('class', 'shadow');
31448 enter.append('polygon')
31449 .attr('points', '-3,4 5,0 -3,-4')
31450 .attr('class', 'fill');
31453 .attr('transform', function(d) {
31454 var translate = iD.svg.PointTransform(projection),
31455 a = context.entity(d.edge[0]),
31456 b = context.entity(d.edge[1]),
31457 angle = Math.round(iD.geo.angle(a, b, projection) * (180 / Math.PI));
31458 return translate(d) + ' rotate(' + angle + ')';
31460 .call(iD.svg.TagClasses().tags(
31461 function(d) { return d.parents[0].tags; }
31464 // Propagate data bindings.
31465 groups.select('polygon.shadow');
31466 groups.select('polygon.fill');
31472 iD.svg.Osm = function() {
31473 return function drawOsm(selection) {
31474 var layers = selection.selectAll('.layer-osm')
31475 .data(['areas', 'lines', 'hit', 'halo', 'label']);
31477 layers.enter().append('g')
31478 .attr('class', function(d) { return 'layer-osm layer-' + d; });
31481 iD.svg.Points = function(projection, context) {
31482 function markerPath(selection, klass) {
31484 .attr('class', klass)
31485 .attr('transform', 'translate(-8, -23)')
31486 .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');
31489 function sortY(a, b) {
31490 return b.loc[1] - a.loc[1];
31493 return function drawPoints(surface, graph, entities, filter) {
31494 var wireframe = surface.classed('fill-wireframe'),
31495 points = wireframe ? [] : _.filter(entities, function(e) {
31496 return e.geometry(graph) === 'point';
31499 points.sort(sortY);
31501 var groups = surface.selectAll('.layer-hit').selectAll('g.point')
31503 .data(points, iD.Entity.key);
31505 var group = groups.enter()
31507 .attr('class', function(d) { return 'node point ' + d.id; })
31510 group.append('path')
31511 .call(markerPath, 'shadow');
31513 group.append('path')
31514 .call(markerPath, 'stroke');
31516 group.append('use')
31517 .attr('transform', 'translate(-6, -20)')
31518 .attr('class', 'icon')
31519 .attr('width', '12px')
31520 .attr('height', '12px');
31522 groups.attr('transform', iD.svg.PointTransform(projection))
31523 .call(iD.svg.TagClasses());
31525 // Selecting the following implicitly
31526 // sets the data (point entity) on the element
31527 groups.select('.shadow');
31528 groups.select('.stroke');
31529 groups.select('.icon')
31530 .attr('xlink:href', function(entity) {
31531 var preset = context.presets().match(entity, graph);
31532 return preset.icon ? '#' + preset.icon + '-12' : '';
31539 iD.svg.TagClasses = function() {
31541 'building', 'highway', 'railway', 'waterway', 'aeroway',
31542 'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
31546 'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
31547 'razed', 'demolished', 'obliterated'
31550 'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
31551 'surface', 'tracktype', 'crossing'
31553 tagClassRe = /^tag-/,
31554 tags = function(entity) { return entity.tags; };
31557 var tagClasses = function(selection) {
31558 selection.each(function tagClassesEach(entity) {
31559 var value = this.className,
31560 classes, primary, status;
31562 if (value.baseVal !== undefined) value = value.baseVal;
31564 classes = value.trim().split(/\s+/).filter(function(name) {
31565 return name.length && !tagClassRe.test(name);
31568 var t = tags(entity), i, k, v;
31570 // pick at most one primary classification tag..
31571 for (i = 0; i < primaries.length; i++) {
31574 if (!v || v === 'no') continue;
31577 if (statuses.indexOf(v) !== -1) { // e.g. `railway=abandoned`
31579 classes += ' tag-' + k;
31581 classes += ' tag-' + k + ' tag-' + k + '-' + v;
31587 // add at most one status tag, only if relates to primary tag..
31589 for (i = 0; i < statuses.length; i++) {
31592 if (!v || v === 'no') continue;
31594 if (v === 'yes') { // e.g. `railway=rail + abandoned=yes`
31597 else if (primary && primary === v) { // e.g. `railway=rail + abandoned=railway`
31599 } else if (!primary && primaries.indexOf(v) !== -1) { // e.g. `abandoned=railway`
31602 classes += ' tag-' + v;
31603 } // else ignore e.g. `highway=path + abandoned=railway`
31610 classes += ' tag-status tag-status-' + status;
31613 // add any secondary (structure) tags
31614 for (i = 0; i < secondaries.length; i++) {
31615 k = secondaries[i];
31617 if (!v || v === 'no') continue;
31618 classes += ' tag-' + k + ' tag-' + k + '-' + v;
31621 // For highways, look for surface tagging..
31622 if (primary === 'highway') {
31623 var paved = (t.highway !== 'track');
31626 if (k in iD.pavedTags) {
31627 paved = !!iD.pavedTags[k][v];
31632 classes += ' tag-unpaved';
31636 classes = classes.trim();
31638 if (classes !== value) {
31639 d3.select(this).attr('class', classes);
31644 tagClasses.tags = function(_) {
31645 if (!arguments.length) return tags;
31652 iD.svg.Turns = function(projection) {
31653 return function drawTurns(surface, graph, turns) {
31654 function key(turn) {
31655 return [turn.from.node + turn.via.node + turn.to.node].join('-');
31658 function icon(turn) {
31659 var u = turn.u ? '-u' : '';
31660 if (!turn.restriction)
31661 return '#turn-yes' + u;
31662 var restriction = graph.entity(turn.restriction).tags.restriction;
31664 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
31667 var groups = surface.selectAll('.layer-hit').selectAll('g.turn')
31671 var enter = groups.enter().append('g')
31672 .attr('class', 'turn');
31674 var nEnter = enter.filter(function (turn) { return !turn.u; });
31676 nEnter.append('rect')
31677 .attr('transform', 'translate(-22, -12)')
31678 .attr('width', '44')
31679 .attr('height', '24');
31681 nEnter.append('use')
31682 .attr('transform', 'translate(-22, -12)')
31683 .attr('width', '44')
31684 .attr('height', '24');
31687 var uEnter = enter.filter(function (turn) { return turn.u; });
31689 uEnter.append('circle')
31692 uEnter.append('use')
31693 .attr('transform', 'translate(-16, -16)')
31694 .attr('width', '32')
31695 .attr('height', '32');
31700 .attr('transform', function (turn) {
31701 var v = graph.entity(turn.via.node),
31702 t = graph.entity(turn.to.node),
31703 a = iD.geo.angle(v, t, projection),
31704 p = projection(v.loc),
31705 r = turn.u ? 0 : 60;
31707 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
31708 'rotate(' + a * 180 / Math.PI + ')';
31711 groups.select('use')
31712 .attr('xlink:href', icon);
31714 groups.select('rect');
31715 groups.select('circle');
31725 iD.svg.Vertices = function(projection, context) {
31727 // z16-, z17, z18+, tagged
31728 shadow: [6, 7.5, 7.5, 11.5],
31729 stroke: [2.5, 3.5, 3.5, 7],
31730 fill: [1, 1.5, 1.5, 1.5]
31735 function siblingAndChildVertices(ids, graph, extent) {
31738 function addChildVertices(entity) {
31739 if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
31741 if (entity.type === 'way') {
31742 for (i = 0; i < entity.nodes.length; i++) {
31743 addChildVertices(graph.entity(entity.nodes[i]));
31745 } else if (entity.type === 'relation') {
31746 for (i = 0; i < entity.members.length; i++) {
31747 var member = context.hasEntity(entity.members[i].id);
31749 addChildVertices(member);
31752 } else if (entity.intersects(extent, graph)) {
31753 vertices[entity.id] = entity;
31758 ids.forEach(function(id) {
31759 var entity = context.hasEntity(id);
31760 if (entity && entity.type === 'node') {
31761 vertices[entity.id] = entity;
31762 context.graph().parentWays(entity).forEach(function(entity) {
31763 addChildVertices(entity);
31765 } else if (entity) {
31766 addChildVertices(entity);
31773 function draw(selection, vertices, klass, graph, zoom) {
31775 z = (zoom < 17 ? 0 : zoom < 18 ? 1 : 2);
31777 var groups = selection
31778 .data(vertices, iD.Entity.key);
31780 function icon(entity) {
31781 if (entity.id in icons) return icons[entity.id];
31783 entity.hasInterestingTags() &&
31784 context.presets().match(entity, graph).icon;
31785 return icons[entity.id];
31788 function setClass(klass) {
31789 return function(entity) {
31790 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
31794 function setAttributes(selection) {
31795 ['shadow','stroke','fill'].forEach(function(klass) {
31796 var rads = radiuses[klass];
31797 selection.selectAll('.' + klass)
31798 .each(function(entity) {
31799 var i = z && icon(entity),
31801 r = rads[i ? 3 : z];
31802 this.setAttribute('cx', c);
31803 this.setAttribute('cy', -c);
31804 this.setAttribute('r', r);
31805 if (i && klass === 'fill') {
31806 this.setAttribute('visibility', 'hidden');
31808 this.removeAttribute('visibility');
31813 selection.selectAll('use')
31816 this.removeAttribute('visibility');
31818 this.setAttribute('visibility', 'hidden');
31823 var enter = groups.enter()
31825 .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
31827 enter.append('circle')
31828 .each(setClass('shadow'));
31830 enter.append('circle')
31831 .each(setClass('stroke'));
31833 // Vertices with icons get a `use`.
31834 enter.filter(function(d) { return icon(d); })
31836 .attr('transform', 'translate(-6, -6)')
31837 .attr('xlink:href', function(d) { return '#' + icon(d) + '-12'; })
31838 .attr('width', '12px')
31839 .attr('height', '12px')
31840 .each(setClass('icon'));
31842 // Vertices with tags get a fill.
31843 enter.filter(function(d) { return d.hasInterestingTags(); })
31845 .each(setClass('fill'));
31848 .attr('transform', iD.svg.PointTransform(projection))
31849 .classed('shared', function(entity) { return graph.isShared(entity); })
31850 .call(setAttributes);
31856 function drawVertices(surface, graph, entities, filter, extent, zoom) {
31857 var selected = siblingAndChildVertices(context.selectedIDs(), graph, extent),
31858 wireframe = surface.classed('fill-wireframe'),
31861 for (var i = 0; i < entities.length; i++) {
31862 var entity = entities[i],
31863 geometry = entity.geometry(graph);
31865 if (wireframe && geometry === 'point') {
31866 vertices.push(entity);
31870 if (geometry !== 'vertex')
31873 if (entity.id in selected ||
31874 entity.hasInterestingTags() ||
31875 entity.isIntersection(graph)) {
31876 vertices.push(entity);
31880 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-persistent')
31882 .call(draw, vertices, 'vertex-persistent', graph, zoom);
31884 drawHover(surface, graph, extent, zoom);
31887 function drawHover(surface, graph, extent, zoom) {
31888 var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent) : {};
31890 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-hover')
31891 .call(draw, d3.values(hovered), 'vertex-hover', graph, zoom);
31894 drawVertices.drawHover = function(surface, graph, target, extent, zoom) {
31895 if (target === hover) return;
31897 drawHover(surface, graph, extent, zoom);
31900 return drawVertices;
31902 iD.ui = function(context) {
31903 function render(container) {
31904 var map = context.map();
31906 if (iD.detect().opera) container.classed('opera', true);
31908 var hash = iD.behavior.Hash(context);
31912 if (!hash.hadHash) {
31913 map.centerZoom([0, 0], 2);
31916 container.append('svg')
31917 .attr('id', 'defs')
31918 .call(iD.svg.Defs(context));
31920 container.append('div')
31921 .attr('id', 'sidebar')
31922 .attr('class', 'col4')
31925 var content = container.append('div')
31926 .attr('id', 'content');
31928 var bar = content.append('div')
31930 .attr('class', 'fillD');
31932 content.append('div')
31937 .call(iD.ui.MapInMap(context));
31939 content.append('div')
31940 .call(iD.ui.Info(context));
31943 .attr('class', 'spacer col4');
31945 var limiter = bar.append('div')
31946 .attr('class', 'limiter');
31948 limiter.append('div')
31949 .attr('class', 'button-wrap joined col3')
31950 .call(iD.ui.Modes(context), limiter);
31952 limiter.append('div')
31953 .attr('class', 'button-wrap joined col1')
31954 .call(iD.ui.UndoRedo(context));
31956 limiter.append('div')
31957 .attr('class', 'button-wrap col1')
31958 .call(iD.ui.Save(context));
31961 .attr('class', 'full-screen')
31962 .call(iD.ui.FullScreen(context));
31965 .attr('class', 'spinner')
31966 .call(iD.ui.Spinner(context));
31968 var controls = bar.append('div')
31969 .attr('class', 'map-controls');
31971 controls.append('div')
31972 .attr('class', 'map-control zoombuttons')
31973 .call(iD.ui.Zoom(context));
31975 controls.append('div')
31976 .attr('class', 'map-control geolocate-control')
31977 .call(iD.ui.Geolocate(map));
31979 controls.append('div')
31980 .attr('class', 'map-control background-control')
31981 .call(iD.ui.Background(context));
31983 controls.append('div')
31984 .attr('class', 'map-control map-data-control')
31985 .call(iD.ui.MapData(context));
31987 controls.append('div')
31988 .attr('class', 'map-control help-control')
31989 .call(iD.ui.Help(context));
31991 var about = content.append('div')
31992 .attr('id', 'about');
31994 about.append('div')
31995 .attr('id', 'attrib')
31996 .call(iD.ui.Attribution(context));
31998 var footer = about.append('div')
31999 .attr('id', 'footer')
32000 .attr('class', 'fillD');
32002 footer.append('div')
32003 .attr('class', 'api-status')
32004 .call(iD.ui.Status(context));
32006 footer.append('div')
32007 .attr('id', 'scale-block')
32008 .call(iD.ui.Scale(context));
32010 var aboutList = footer.append('div')
32011 .attr('id', 'info-block')
32013 .attr('id', 'about-list');
32015 if (!context.embed()) {
32016 aboutList.call(iD.ui.Account(context));
32019 aboutList.append('li')
32021 .attr('target', '_blank')
32022 .attr('tabindex', -1)
32023 .attr('href', 'https://github.com/openstreetmap/iD')
32026 var issueLinks = aboutList.append('li');
32028 issueLinks.append('a')
32029 .attr('target', '_blank')
32030 .attr('tabindex', -1)
32031 .attr('href', 'https://github.com/openstreetmap/iD/issues')
32032 .call(iD.svg.Icon('#icon-bug', 'light'))
32033 .call(bootstrap.tooltip()
32034 .title(t('report_a_bug'))
32038 issueLinks.append('a')
32039 .attr('target', '_blank')
32040 .attr('tabindex', -1)
32041 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
32042 .call(iD.svg.Icon('#icon-translate', 'light'))
32043 .call(bootstrap.tooltip()
32044 .title(t('help_translate'))
32048 aboutList.append('li')
32049 .attr('class', 'feature-warning')
32050 .attr('tabindex', -1)
32051 .call(iD.ui.FeatureInfo(context));
32053 aboutList.append('li')
32054 .attr('class', 'user-list')
32055 .attr('tabindex', -1)
32056 .call(iD.ui.Contributors(context));
32058 window.onbeforeunload = function() {
32059 return context.save();
32062 window.onunload = function() {
32063 context.history().unlock();
32066 var mapDimensions = map.dimensions();
32068 d3.select(window).on('resize.editor', function() {
32069 mapDimensions = content.dimensions(null);
32070 map.dimensions(mapDimensions);
32074 return function() {
32075 d3.event.preventDefault();
32076 if (!context.inIntro()) context.pan(d);
32083 var keybinding = d3.keybinding('main')
32084 .on('⌫', function() { d3.event.preventDefault(); })
32085 .on('←', pan([pa, 0]))
32086 .on('↑', pan([0, pa]))
32087 .on('→', pan([-pa, 0]))
32088 .on('↓', pan([0, -pa]))
32089 .on('⇧←', pan([mapDimensions[0], 0]))
32090 .on('⇧↑', pan([0, mapDimensions[1]]))
32091 .on('⇧→', pan([-mapDimensions[0], 0]))
32092 .on('⇧↓', pan([0, -mapDimensions[1]]))
32093 .on(iD.ui.cmd('⌘←'), pan([mapDimensions[0], 0]))
32094 .on(iD.ui.cmd('⌘↑'), pan([0, mapDimensions[1]]))
32095 .on(iD.ui.cmd('⌘→'), pan([-mapDimensions[0], 0]))
32096 .on(iD.ui.cmd('⌘↓'), pan([0, -mapDimensions[1]]));
32098 d3.select(document)
32101 context.enter(iD.modes.Browse(context));
32103 context.container()
32104 .call(iD.ui.Splash(context))
32105 .call(iD.ui.Restore(context));
32107 var authenticating = iD.ui.Loading(context)
32108 .message(t('loading_auth'));
32110 context.connection()
32111 .on('authenticating.ui', function() {
32112 context.container()
32113 .call(authenticating);
32115 .on('authenticated.ui', function() {
32116 authenticating.close();
32120 function ui(container) {
32121 context.container(container);
32122 context.loadLocale(function() {
32127 ui.sidebar = iD.ui.Sidebar(context);
32132 iD.ui.tooltipHtml = function(text, key) {
32133 var s = '<span>' + text + '</span>';
32135 s += '<div class="keyhint-wrap">' +
32136 '<span> ' + (t('tooltip_keyhint')) + ' </span>' +
32137 '<span class="keyhint"> ' + key + '</span></div>';
32141 iD.ui.Account = function(context) {
32142 var connection = context.connection();
32144 function update(selection) {
32145 if (!connection.authenticated()) {
32146 selection.selectAll('#userLink, #logoutLink')
32147 .classed('hide', true);
32151 connection.userDetails(function(err, details) {
32152 var userLink = selection.select('#userLink'),
32153 logoutLink = selection.select('#logoutLink');
32156 logoutLink.html('');
32160 selection.selectAll('#userLink, #logoutLink')
32161 .classed('hide', false);
32164 userLink.append('a')
32165 .attr('href', connection.userURL(details.display_name))
32166 .attr('target', '_blank');
32168 // Add thumbnail or dont
32169 if (details.image_url) {
32170 userLink.append('img')
32171 .attr('class', 'icon pre-text user-icon')
32172 .attr('src', details.image_url);
32175 .call(iD.svg.Icon('#icon-avatar', 'pre-text light'));
32179 userLink.append('span')
32180 .attr('class', 'label')
32181 .text(details.display_name);
32183 logoutLink.append('a')
32184 .attr('class', 'logout')
32187 .on('click.logout', function() {
32188 d3.event.preventDefault();
32189 connection.logout();
32194 return function(selection) {
32195 selection.append('li')
32196 .attr('id', 'logoutLink')
32197 .classed('hide', true);
32199 selection.append('li')
32200 .attr('id', 'userLink')
32201 .classed('hide', true);
32203 connection.on('auth.account', function() { update(selection); });
32207 iD.ui.Attribution = function(context) {
32210 function attribution(data, klass) {
32211 var div = selection.selectAll('.' + klass)
32216 .attr('class', klass);
32218 var background = div.selectAll('.attribution')
32219 .data(data, function(d) { return d.name(); });
32223 .attr('class', 'attribution')
32224 .each(function(d) {
32225 if (d.terms_html) {
32227 .html(d.terms_html);
32231 var source = d.terms_text || d.id || d.name();
32234 source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
32240 .attr('href', d.terms_url)
32241 .attr('target', '_blank')
32252 var copyright = background.selectAll('.copyright-notice')
32253 .data(function(d) {
32254 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
32255 return notice ? [notice] : [];
32260 .attr('class', 'copyright-notice');
32262 copyright.text(String);
32268 function update() {
32269 attribution([context.background().baseLayerSource()], 'base-layer-attribution');
32270 attribution(context.background().overlayLayerSources().filter(function (s) {
32271 return s.validZoom(context.map().zoom());
32272 }), 'overlay-layer-attribution');
32275 return function(select) {
32276 selection = select;
32278 context.background()
32279 .on('change.attribution', update);
32282 .on('move.attribution', _.throttle(update, 400, {leading: false}));
32287 iD.ui.Background = function(context) {
32289 opacities = [1, 0.75, 0.5, 0.25],
32293 ['right', [-1, 0]],
32294 ['bottom', [0, 1]]],
32295 opacityDefault = (context.storage('background-opacity') !== null) ?
32296 (+context.storage('background-opacity')) : 1.0,
32297 customTemplate = context.storage('background-custom-template') || '';
32299 // Can be 0 from <1.3.0 use or due to issue #1923.
32300 if (opacityDefault === 0) opacityDefault = 1.0;
32302 function background(selection) {
32304 function sortSources(a, b) {
32305 return a.best() ? -1
32307 : a.id === 'none' ? 1
32308 : b.id === 'none' ? -1
32309 : d3.ascending(a, b);
32312 function setOpacity(d) {
32313 var bg = context.container().selectAll('.layer-background')
32315 .style('opacity', d)
32316 .attr('data-opacity', d);
32318 if (!iD.detect().opera) {
32319 iD.util.setTransform(bg, 0, 0);
32322 opacityList.selectAll('li')
32323 .classed('active', function(_) { return _ === d; });
32325 context.storage('background-opacity', d);
32328 function selectLayer() {
32329 function active(d) {
32330 return context.background().showsLayer(d);
32333 content.selectAll('.layer, .custom_layer')
32334 .classed('active', active)
32335 .selectAll('input')
32336 .property('checked', active);
32339 function clickSetSource(d) {
32340 d3.event.preventDefault();
32341 context.background().baseLayerSource(d);
32345 function editCustom() {
32346 d3.event.preventDefault();
32347 var template = window.prompt(t('background.custom_prompt'), customTemplate);
32349 template.indexOf('google.com') !== -1 ||
32350 template.indexOf('googleapis.com') !== -1 ||
32351 template.indexOf('google.ru') !== -1) {
32355 setCustom(template);
32358 function setCustom(template) {
32359 context.background().baseLayerSource(iD.BackgroundSource.Custom(template));
32361 context.storage('background-custom-template', template);
32364 function clickSetOverlay(d) {
32365 d3.event.preventDefault();
32366 context.background().toggleOverlayLayer(d);
32370 function drawList(layerList, type, change, filter) {
32371 var sources = context.background()
32372 .sources(context.map().extent())
32375 var layerLinks = layerList.selectAll('li.layer')
32376 .data(sources, function(d) { return d.name(); })
32377 .sort(sortSources);
32379 var enter = layerLinks.enter()
32380 .insert('li', '.custom_layer')
32381 .attr('class', 'layer')
32382 .classed('best', function(d) { return d.best(); });
32384 // only set tooltips for layers with tooltips
32385 enter.filter(function(d) { return d.description; })
32386 .call(bootstrap.tooltip()
32387 .title(function(d) { return d.description; })
32388 .placement('top'));
32390 enter.filter(function(d) { return d.best(); })
32392 .attr('class', 'best')
32393 .call(bootstrap.tooltip()
32394 .title(t('background.best_imagery'))
32395 .placement('left'))
32399 var label = enter.append('label');
32401 label.append('input')
32402 .attr('type', type)
32403 .attr('name', 'layers')
32404 .on('change', change);
32406 label.append('span')
32407 .text(function(d) { return d.name(); });
32412 layerList.style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
32415 function update() {
32416 backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
32417 overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
32421 var source = context.background().baseLayerSource();
32422 if (source.id === 'custom') {
32423 customTemplate = source.template;
32427 function clickNudge(d) {
32428 var timeout = window.setTimeout(function() {
32429 interval = window.setInterval(nudge, 100);
32433 d3.select(this).on('mouseup', function() {
32434 window.clearInterval(interval);
32435 window.clearTimeout(timeout);
32440 var offset = context.background()
32441 .nudge(d[1], context.map().zoom())
32443 resetButton.classed('disabled', offset[0] === 0 && offset[1] === 0);
32447 function hide() { setVisible(false); }
32449 function toggle() {
32450 if (d3.event) d3.event.preventDefault();
32451 tooltip.hide(button);
32452 setVisible(!button.classed('active'));
32455 function setVisible(show) {
32456 if (show !== shown) {
32457 button.classed('active', show);
32461 selection.on('mousedown.background-inside', function() {
32462 return d3.event.stopPropagation();
32464 content.style('display', 'block')
32465 .style('right', '-300px')
32468 .style('right', '0px');
32470 content.style('display', 'block')
32471 .style('right', '0px')
32474 .style('right', '-300px')
32475 .each('end', function() {
32476 d3.select(this).style('display', 'none');
32478 selection.on('mousedown.background-inside', null);
32484 var content = selection.append('div')
32485 .attr('class', 'fillL map-overlay col3 content hide'),
32486 tooltip = bootstrap.tooltip()
32489 .title(iD.ui.tooltipHtml(t('background.description'), key)),
32490 button = selection.append('button')
32491 .attr('tabindex', -1)
32492 .on('click', toggle)
32493 .call(iD.svg.Icon('#icon-layers', 'light'))
32497 var opa = content.append('div')
32498 .attr('class', 'opacity-options-wrapper');
32501 .text(t('background.title'));
32503 var opacityList = opa.append('ul')
32504 .attr('class', 'opacity-options');
32506 opacityList.selectAll('div.opacity')
32510 .attr('data-original-title', function(d) {
32511 return t('background.percent_brightness', { opacity: (d * 100) });
32513 .on('click.set-opacity', setOpacity)
32514 .html('<div class="select-box"></div>')
32515 .call(bootstrap.tooltip()
32516 .placement('left'))
32518 .attr('class', 'opacity')
32519 .style('opacity', function(d) { return 1.25 - d; });
32521 var backgroundList = content.append('ul')
32522 .attr('class', 'layer-list');
32524 var custom = backgroundList.append('li')
32525 .attr('class', 'custom_layer')
32526 .datum(iD.BackgroundSource.Custom());
32528 custom.append('button')
32529 .attr('class', 'layer-browse')
32530 .call(bootstrap.tooltip()
32531 .title(t('background.custom_button'))
32532 .placement('left'))
32533 .on('click', editCustom)
32534 .call(iD.svg.Icon('#icon-search'));
32536 var label = custom.append('label');
32538 label.append('input')
32539 .attr('type', 'radio')
32540 .attr('name', 'layers')
32541 .on('change', function () {
32542 if (customTemplate) {
32543 setCustom(customTemplate);
32549 label.append('span')
32550 .text(t('background.custom'));
32552 content.append('div')
32553 .attr('class', 'imagery-faq')
32555 .attr('target', '_blank')
32556 .attr('tabindex', -1)
32557 .call(iD.svg.Icon('#icon-out-link', 'inline'))
32558 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
32560 .text(t('background.imagery_source_faq'));
32562 var overlayList = content.append('ul')
32563 .attr('class', 'layer-list');
32565 var controls = content.append('div')
32566 .attr('class', 'controls-list');
32568 var minimapLabel = controls
32570 .call(bootstrap.tooltip()
32572 .title(iD.ui.tooltipHtml(t('background.minimap.tooltip'), '/'))
32576 minimapLabel.classed('minimap-toggle', true)
32578 .attr('type', 'checkbox')
32579 .on('change', function() {
32580 iD.ui.MapInMap.toggle();
32581 d3.event.preventDefault();
32584 minimapLabel.append('span')
32585 .text(t('background.minimap.description'));
32587 var adjustments = content.append('div')
32588 .attr('class', 'adjustments');
32590 adjustments.append('a')
32591 .text(t('background.fix_misalignment'))
32593 .classed('hide-toggle', true)
32594 .classed('expanded', false)
32595 .on('click', function() {
32596 var exp = d3.select(this).classed('expanded');
32597 nudgeContainer.style('display', exp ? 'none' : 'block');
32598 d3.select(this).classed('expanded', !exp);
32599 d3.event.preventDefault();
32602 var nudgeContainer = adjustments.append('div')
32603 .attr('class', 'nudge-container cf')
32604 .style('display', 'none');
32606 nudgeContainer.selectAll('button')
32607 .data(directions).enter()
32609 .attr('class', function(d) { return d[0] + ' nudge'; })
32610 .on('mousedown', clickNudge);
32612 var resetButton = nudgeContainer
32614 .attr('class', 'reset disabled')
32615 .on('click', function () {
32616 context.background().offset([0, 0]);
32617 resetButton.classed('disabled', true);
32619 .call(iD.svg.Icon('#icon-undo'));
32622 .on('move.background-update', _.debounce(update, 1000));
32624 context.background()
32625 .on('change.background-update', update);
32628 setOpacity(opacityDefault);
32630 var keybinding = d3.keybinding('background')
32635 d3.select(document)
32638 context.surface().on('mousedown.background-outside', hide);
32639 context.container().on('mousedown.background-outside', hide);
32644 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
32645 // For example, ⌘Z -> Ctrl+Z
32646 iD.ui.cmd = function(code) {
32647 if (iD.detect().os === 'mac') {
32651 if (iD.detect().os === 'win') {
32652 if (code === '⌘⇧Z') return 'Ctrl+Y';
32664 for (var i = 0; i < code.length; i++) {
32665 if (code[i] in replacements) {
32666 result += replacements[code[i]] + '+';
32674 iD.ui.Commit = function(context) {
32675 var dispatch = d3.dispatch('cancel', 'save');
32677 function commit(selection) {
32678 var changes = context.history().changes(),
32679 summary = context.history().difference().summary();
32681 function zoomToEntity(change) {
32682 var entity = change.entity;
32683 if (change.changeType !== 'deleted' &&
32684 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
32685 context.map().zoomTo(entity);
32686 context.surface().selectAll(
32687 iD.util.entityOrMemberSelector([entity.id], context.graph()))
32688 .classed('hover', true);
32692 var header = selection.append('div')
32693 .attr('class', 'header fillL');
32695 header.append('h3')
32696 .text(t('commit.title'));
32698 var body = selection.append('div')
32699 .attr('class', 'body');
32703 var commentSection = body.append('div')
32704 .attr('class', 'modal-section form-field commit-form');
32706 commentSection.append('label')
32707 .attr('class', 'form-label')
32708 .text(t('commit.message_label'));
32710 var commentField = commentSection.append('textarea')
32711 .attr('placeholder', t('commit.description_placeholder'))
32712 .attr('maxlength', 255)
32713 .property('value', context.storage('comment') || '')
32714 .on('input.save', enableDisableSaveButton)
32715 .on('change.save', enableDisableSaveButton)
32716 .on('blur.save', function() {
32717 context.storage('comment', this.value);
32720 function enableDisableSaveButton() {
32721 d3.selectAll('.save-section .save-button')
32722 .attr('disabled', (this.value.length ? null : true));
32725 commentField.node().select();
32727 context.connection().userChangesets(function (err, changesets) {
32732 for (var i = 0; i < changesets.length; i++) {
32733 if (changesets[i].tags.comment) {
32735 title: changesets[i].tags.comment,
32736 value: changesets[i].tags.comment
32741 commentField.call(d3.combobox().data(comments));
32744 var changeSetInfo = commentSection.append('div')
32745 .attr('class', 'changeset-info');
32747 changeSetInfo.append('a')
32748 .attr('target', '_blank')
32749 .attr('tabindex', -1)
32750 .call(iD.svg.Icon('#icon-out-link', 'inline'))
32751 .attr('href', t('commit.about_changeset_comments_link'))
32753 .text(t('commit.about_changeset_comments'));
32756 var warnings = body.selectAll('div.warning-section')
32757 .data([context.history().validate(changes)])
32760 .attr('class', 'modal-section warning-section fillL2')
32761 .style('display', function(d) { return _.isEmpty(d) ? 'none' : null; })
32762 .style('background', '#ffb');
32764 warnings.append('h3')
32765 .text(t('commit.warnings'));
32767 var warningLi = warnings.append('ul')
32768 .attr('class', 'changeset-list')
32770 .data(function(d) { return d; })
32774 .on('mouseover', mouseover)
32775 .on('mouseout', mouseout)
32776 .on('click', warningClick);
32779 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
32782 .append('strong').text(function(d) {
32786 warningLi.filter(function(d) { return d.tooltip; })
32787 .call(bootstrap.tooltip()
32788 .title(function(d) { return d.tooltip; })
32793 // Upload Explanation
32794 var saveSection = body.append('div')
32795 .attr('class','modal-section save-section fillL cf');
32797 var prose = saveSection.append('p')
32798 .attr('class', 'commit-info')
32799 .html(t('commit.upload_explanation'));
32801 context.connection().userDetails(function(err, user) {
32804 var userLink = d3.select(document.createElement('div'));
32806 if (user.image_url) {
32807 userLink.append('img')
32808 .attr('src', user.image_url)
32809 .attr('class', 'icon pre-text user-icon');
32812 userLink.append('a')
32813 .attr('class','user-info')
32814 .text(user.display_name)
32815 .attr('href', context.connection().userURL(user.display_name))
32816 .attr('tabindex', -1)
32817 .attr('target', '_blank');
32819 prose.html(t('commit.upload_explanation_with_user', {user: userLink.html()}));
32824 var buttonSection = saveSection.append('div')
32825 .attr('class','buttons fillL cf');
32827 var saveButton = buttonSection.append('button')
32828 .attr('class', 'action col5 button save-button')
32829 .attr('disabled', function() {
32830 var n = d3.select('.commit-form textarea').node();
32831 return (n && n.value.length) ? null : true;
32833 .on('click.save', function() {
32835 comment: commentField.node().value
32839 saveButton.append('span')
32840 .attr('class', 'label')
32841 .text(t('commit.save'));
32843 var cancelButton = buttonSection.append('button')
32844 .attr('class', 'action col5 button cancel-button')
32845 .on('click.cancel', function() { dispatch.cancel(); });
32847 cancelButton.append('span')
32848 .attr('class', 'label')
32849 .text(t('commit.cancel'));
32853 var changeSection = body.selectAll('div.commit-section')
32857 .attr('class', 'commit-section modal-section fillL2');
32859 changeSection.append('h3')
32860 .text(t('commit.changes', {count: summary.length}));
32862 var li = changeSection.append('ul')
32863 .attr('class', 'changeset-list')
32868 .on('mouseover', mouseover)
32869 .on('mouseout', mouseout)
32870 .on('click', zoomToEntity);
32872 li.each(function(d) {
32874 .call(iD.svg.Icon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
32878 .attr('class', 'change-type')
32879 .text(function(d) {
32880 return t('commit.' + d.changeType) + ' ';
32883 li.append('strong')
32884 .attr('class', 'entity-type')
32885 .text(function(d) {
32886 return context.presets().match(d.entity, d.graph).name();
32890 .attr('class', 'entity-name')
32891 .text(function(d) {
32892 var name = iD.util.displayName(d.entity) || '',
32894 if (name !== '') string += ':';
32895 return string += ' ' + name;
32898 li.style('opacity', 0)
32900 .style('opacity', 1);
32902 li.style('opacity', 0)
32904 .style('opacity', 1);
32906 function mouseover(d) {
32908 context.surface().selectAll(
32909 iD.util.entityOrMemberSelector([d.entity.id], context.graph())
32910 ).classed('hover', true);
32914 function mouseout() {
32915 context.surface().selectAll('.hover')
32916 .classed('hover', false);
32919 function warningClick(d) {
32921 context.map().zoomTo(d.entity);
32923 iD.modes.Select(context, [d.entity.id])
32924 .suppressMenu(true));
32929 return d3.rebind(commit, dispatch, 'on');
32931 iD.ui.confirm = function(selection) {
32932 var modal = iD.ui.modal(selection);
32934 modal.select('.modal')
32935 .classed('modal-alert', true);
32937 var section = modal.select('.content');
32939 section.append('div')
32940 .attr('class', 'modal-section header');
32942 section.append('div')
32943 .attr('class', 'modal-section message-text');
32945 var buttons = section.append('div')
32946 .attr('class', 'modal-section buttons cf');
32948 modal.okButton = function() {
32951 .attr('class', 'action col4')
32952 .on('click.confirm', function() {
32955 .text(t('confirm.okay'));
32962 iD.ui.Conflicts = function(context) {
32963 var dispatch = d3.dispatch('download', 'cancel', 'save'),
32966 function conflicts(selection) {
32967 var header = selection
32969 .attr('class', 'header fillL');
32973 .attr('class', 'fr')
32974 .on('click', function() { dispatch.cancel(); })
32975 .call(iD.svg.Icon('#icon-close'));
32979 .text(t('save.conflict.header'));
32981 var body = selection
32983 .attr('class', 'body fillL');
32987 .attr('class', 'conflicts-help')
32988 .text(t('save.conflict.help'))
32990 .attr('class', 'conflicts-download')
32991 .text(t('save.conflict.download_changes'))
32992 .on('click.download', function() { dispatch.download(); });
32996 .attr('class', 'conflict-container fillL3')
32997 .call(showConflict, 0);
33001 .attr('class', 'conflicts-done')
33002 .attr('opacity', 0)
33003 .style('display', 'none')
33004 .text(t('save.conflict.done'));
33008 .attr('class','buttons col12 joined conflicts-buttons');
33012 .attr('disabled', list.length > 1)
33013 .attr('class', 'action conflicts-button col6')
33014 .text(t('save.title'))
33015 .on('click.try_again', function() { dispatch.save(); });
33019 .attr('class', 'secondary-action conflicts-button col6')
33020 .text(t('confirm.cancel'))
33021 .on('click.cancel', function() { dispatch.cancel(); });
33025 function showConflict(selection, index) {
33026 if (index < 0 || index >= list.length) return;
33028 var parent = d3.select(selection.node().parentNode);
33030 // enable save button if this is the last conflict being reviewed..
33031 if (index === list.length - 1) {
33032 window.setTimeout(function() {
33033 parent.select('.conflicts-button')
33034 .attr('disabled', null);
33036 parent.select('.conflicts-done')
33038 .attr('opacity', 1)
33039 .style('display', 'block');
33043 var item = selection
33044 .selectAll('.conflict')
33045 .data([list[index]]);
33047 var enter = item.enter()
33049 .attr('class', 'conflict');
33053 .attr('class', 'conflict-count')
33054 .text(t('save.conflict.count', { num: index + 1, total: list.length }));
33058 .attr('class', 'conflict-description')
33060 .text(function(d) { return d.name; })
33061 .on('click', function(d) {
33062 zoomToEntity(d.id);
33063 d3.event.preventDefault();
33066 var details = enter
33068 .attr('class', 'conflict-detail-container');
33072 .attr('class', 'conflict-detail-list')
33074 .data(function(d) { return d.details || []; })
33077 .attr('class', 'conflict-detail-item')
33078 .html(function(d) { return d; });
33082 .attr('class', 'conflict-choices')
33087 .attr('class', 'conflict-nav-buttons joined cf')
33088 .selectAll('button')
33089 .data(['previous', 'next'])
33092 .text(function(d) { return t('save.conflict.' + d); })
33093 .attr('class', 'conflict-nav-button action col6')
33094 .attr('disabled', function(d, i) {
33095 return (i === 0 && index === 0) ||
33096 (i === 1 && index === list.length - 1) || null;
33098 .on('click', function(d, i) {
33099 var container = parent.select('.conflict-container'),
33100 sign = (i === 0 ? -1 : 1);
33103 .selectAll('.conflict')
33107 .call(showConflict, index + sign);
33109 d3.event.preventDefault();
33117 function addChoices(selection) {
33118 var choices = selection
33120 .attr('class', 'layer-list')
33122 .data(function(d) { return d.choices || []; });
33124 var enter = choices.enter()
33126 .attr('class', 'layer');
33133 .attr('type', 'radio')
33134 .attr('name', function(d) { return d.id; })
33135 .on('change', function(d, i) {
33136 var ul = this.parentNode.parentNode.parentNode;
33137 ul.__data__.chosen = i;
33143 .text(function(d) { return d.text; });
33146 .each(function(d, i) {
33147 var ul = this.parentNode;
33148 if (ul.__data__.chosen === i) choose(ul, d);
33152 function choose(ul, datum) {
33153 if (d3.event) d3.event.preventDefault();
33157 .classed('active', function(d) { return d === datum; })
33158 .selectAll('input')
33159 .property('checked', function(d) { return d === datum; });
33161 var extent = iD.geo.Extent(),
33164 entity = context.graph().hasEntity(datum.id);
33165 if (entity) extent._extend(entity.extent(context.graph()));
33169 entity = context.graph().hasEntity(datum.id);
33170 if (entity) extent._extend(entity.extent(context.graph()));
33172 zoomToEntity(datum.id, extent);
33175 function zoomToEntity(id, extent) {
33176 context.surface().selectAll('.hover')
33177 .classed('hover', false);
33179 var entity = context.graph().hasEntity(id);
33182 context.map().trimmedExtent(extent);
33184 context.map().zoomTo(entity);
33186 context.surface().selectAll(
33187 iD.util.entityOrMemberSelector([entity.id], context.graph()))
33188 .classed('hover', true);
33193 // The conflict list should be an array of objects like:
33196 // name: entityName(local),
33197 // details: merge.conflicts(),
33200 // choice(id, keepMine, forceLocal),
33201 // choice(id, keepTheirs, forceRemote)
33204 conflicts.list = function(_) {
33205 if (!arguments.length) return list;
33210 return d3.rebind(conflicts, dispatch, 'on');
33212 iD.ui.Contributors = function(context) {
33213 var debouncedUpdate = _.debounce(function() { update(); }, 1000),
33216 wrap = d3.select(null);
33218 function update() {
33220 entities = context.intersects(context.map().extent());
33222 entities.forEach(function(entity) {
33223 if (entity && entity.user) users[entity.user] = true;
33226 var u = Object.keys(users),
33227 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
33230 .call(iD.svg.Icon('#icon-nearby', 'pre-text light'));
33232 var userList = d3.select(document.createElement('span'));
33234 userList.selectAll()
33238 .attr('class', 'user-link')
33239 .attr('href', function(d) { return context.connection().userURL(d); })
33240 .attr('target', '_blank')
33241 .attr('tabindex', -1)
33244 if (u.length > limit) {
33245 var count = d3.select(document.createElement('span'));
33248 .attr('target', '_blank')
33249 .attr('tabindex', -1)
33250 .attr('href', function() {
33251 return context.connection().changesetsURL(context.map().center(), context.map().zoom());
33253 .text(u.length - limit + 1);
33255 wrap.append('span')
33256 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
33259 wrap.append('span')
33260 .html(t('contributors.list', { users: userList.html() }));
33267 .style('opacity', 0);
33269 } else if (hidden) {
33272 .style('opacity', 1);
33276 return function(selection) {
33280 context.connection().on('loaded.contributors', debouncedUpdate);
33281 context.map().on('move.contributors', debouncedUpdate);
33284 iD.ui.Disclosure = function() {
33285 var dispatch = d3.dispatch('toggled'),
33288 content = function () {};
33290 var disclosure = function(selection) {
33291 var $link = selection.selectAll('.hide-toggle')
33294 $link.enter().append('a')
33296 .attr('class', 'hide-toggle');
33299 .on('click', toggle)
33300 .classed('expanded', expanded);
33302 var $body = selection.selectAll('div')
33305 $body.enter().append('div');
33307 $body.classed('hide', !expanded)
33310 function toggle() {
33311 expanded = !expanded;
33312 $link.classed('expanded', expanded);
33313 $body.call(iD.ui.Toggle(expanded));
33314 dispatch.toggled(expanded);
33318 disclosure.title = function(_) {
33319 if (!arguments.length) return title;
33324 disclosure.expanded = function(_) {
33325 if (!arguments.length) return expanded;
33330 disclosure.content = function(_) {
33331 if (!arguments.length) return content;
33336 return d3.rebind(disclosure, dispatch, 'on');
33338 iD.ui.EntityEditor = function(context) {
33339 var dispatch = d3.dispatch('choose'),
33341 coalesceChanges = false,
33348 var presetEditor = iD.ui.preset(context)
33349 .on('change', changeTags);
33350 var rawTagEditor = iD.ui.RawTagEditor(context)
33351 .on('change', changeTags);
33353 function entityEditor(selection) {
33354 var entity = context.entity(id),
33355 tags = _.clone(entity.tags);
33357 var $header = selection.selectAll('.header')
33361 var $enter = $header.enter().append('div')
33362 .attr('class', 'header fillL cf');
33364 $enter.append('button')
33365 .attr('class', 'fl preset-reset preset-choose')
33369 $enter.append('button')
33370 .attr('class', 'fr preset-close')
33371 .call(iD.svg.Icon(modified ? '#icon-apply' : '#icon-close'));
33373 $enter.append('h3');
33376 $header.select('h3')
33377 .text(t('inspector.edit'));
33379 $header.select('.preset-close')
33380 .on('click', function() {
33381 context.enter(iD.modes.Browse(context));
33384 var $body = selection.selectAll('.inspector-body')
33388 $enter = $body.enter().append('div')
33389 .attr('class', 'inspector-body');
33391 $enter.append('div')
33392 .attr('class', 'preset-list-item inspector-inner')
33394 .attr('class', 'preset-list-button-wrap')
33396 .attr('class', 'preset-list-button preset-reset')
33397 .call(bootstrap.tooltip()
33398 .title(t('inspector.back_tooltip'))
33399 .placement('bottom'))
33401 .attr('class', 'label');
33403 $body.select('.preset-list-button-wrap')
33404 .call(reference.button);
33406 $body.select('.preset-list-item')
33407 .call(reference.body);
33409 $enter.append('div')
33410 .attr('class', 'inspector-border inspector-preset');
33412 $enter.append('div')
33413 .attr('class', 'inspector-border raw-tag-editor inspector-inner');
33415 $enter.append('div')
33416 .attr('class', 'inspector-border raw-member-editor inspector-inner');
33418 $enter.append('div')
33419 .attr('class', 'raw-membership-editor inspector-inner');
33421 selection.selectAll('.preset-reset')
33422 .on('click', function() {
33423 dispatch.choose(preset);
33427 $body.select('.preset-list-item button')
33428 .call(iD.ui.PresetIcon()
33429 .geometry(context.geometry(id))
33432 $body.select('.preset-list-item .label')
33433 .text(preset.name());
33435 $body.select('.inspector-preset')
33442 $body.select('.raw-tag-editor')
33449 if (entity.type === 'relation') {
33450 $body.select('.raw-member-editor')
33451 .style('display', 'block')
33452 .call(iD.ui.RawMemberEditor(context)
33455 $body.select('.raw-member-editor')
33456 .style('display', 'none');
33459 $body.select('.raw-membership-editor')
33460 .call(iD.ui.RawMembershipEditor(context)
33463 function historyChanged() {
33464 if (state === 'hide') return;
33466 var entity = context.hasEntity(id),
33467 graph = context.graph();
33468 if (!entity) return;
33470 entityEditor.preset(context.presets().match(entity, graph));
33471 entityEditor.modified(base !== graph);
33472 entityEditor(selection);
33476 .on('change.entity-editor', historyChanged);
33479 function clean(o) {
33481 function cleanVal(k, v) {
33482 function keepSpaces(k) {
33483 var whitelist = ['opening_hours', 'service_times', 'collection_times',
33484 'operating_times', 'smoking_hours', 'happy_hours'];
33485 return _.any(whitelist, function(s) { return k.indexOf(s) !== -1; });
33488 var blacklist = ['description', 'note', 'fixme'];
33489 if (_.any(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
33491 var cleaned = v.split(';')
33492 .map(function(s) { return s.trim(); })
33493 .join(keepSpaces(k) ? '; ' : ';');
33495 // The code below is not intended to validate websites and emails.
33496 // It is only intended to prevent obvious copy-paste errors. (#2323)
33498 // clean website- and email-like tags
33499 if (k.indexOf('website') !== -1 ||
33500 k.indexOf('email') !== -1 ||
33501 cleaned.indexOf('http') === 0) {
33503 .replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
33510 var out = {}, k, v;
33512 if (k && (v = o[k]) !== undefined) {
33513 out[k] = cleanVal(k, v);
33519 // Tag changes that fire on input can all get coalesced into a single
33520 // history operation when the user leaves the field. #2342
33521 function changeTags(changed, onInput) {
33522 var entity = context.entity(id),
33523 annotation = t('operations.change_tags.annotation'),
33524 tags = clean(_.extend({}, entity.tags, changed));
33526 if (!_.isEqual(entity.tags, tags)) {
33527 if (coalesceChanges) {
33528 context.overwrite(iD.actions.ChangeTags(id, tags), annotation);
33530 context.perform(iD.actions.ChangeTags(id, tags), annotation);
33534 coalesceChanges = !!onInput;
33537 entityEditor.modified = function(_) {
33538 if (!arguments.length) return modified;
33540 d3.selectAll('button.preset-close use')
33541 .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
33544 entityEditor.state = function(_) {
33545 if (!arguments.length) return state;
33547 return entityEditor;
33550 entityEditor.entityID = function(_) {
33551 if (!arguments.length) return id;
33553 base = context.graph();
33554 entityEditor.preset(context.presets().match(context.entity(id), base));
33555 entityEditor.modified(false);
33556 coalesceChanges = false;
33557 return entityEditor;
33560 entityEditor.preset = function(_) {
33561 if (!arguments.length) return preset;
33562 if (_ !== preset) {
33564 reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context)
33567 return entityEditor;
33570 return d3.rebind(entityEditor, dispatch, 'on');
33572 iD.ui.FeatureInfo = function(context) {
33573 function update(selection) {
33574 var features = context.features(),
33575 stats = features.stats(),
33577 hiddenList = _.compact(_.map(features.hidden(), function(k) {
33580 return String(stats[k]) + ' ' + t('feature.' + k + '.description');
33584 selection.html('');
33586 if (hiddenList.length) {
33587 var tooltip = bootstrap.tooltip()
33590 .title(function() {
33591 return iD.ui.tooltipHtml(hiddenList.join('<br/>'));
33594 var warning = selection.append('a')
33596 .attr('tabindex', -1)
33597 .html(t('feature_info.hidden_warning', { count: count }))
33599 .on('click', function() {
33600 tooltip.hide(warning);
33601 // open map data panel?
33602 d3.event.preventDefault();
33607 .classed('hide', !hiddenList.length);
33610 return function(selection) {
33613 context.features().on('change.feature_info', function() {
33618 iD.ui.FeatureList = function(context) {
33619 var geocodeResults;
33621 function featureList(selection) {
33622 var header = selection.append('div')
33623 .attr('class', 'header fillL cf');
33625 header.append('h3')
33626 .text(t('inspector.feature_list'));
33628 function keypress() {
33629 var q = search.property('value'),
33630 items = list.selectAll('.feature-list-item');
33631 if (d3.event.keyCode === 13 && q.length && items.size()) {
33632 click(items.datum());
33636 function inputevent() {
33637 geocodeResults = undefined;
33641 var searchWrap = selection.append('div')
33642 .attr('class', 'search-header');
33644 var search = searchWrap.append('input')
33645 .attr('placeholder', t('inspector.search'))
33646 .attr('type', 'search')
33647 .on('keypress', keypress)
33648 .on('input', inputevent);
33651 .call(iD.svg.Icon('#icon-search', 'pre-text'));
33653 var listWrap = selection.append('div')
33654 .attr('class', 'inspector-body');
33656 var list = listWrap.append('div')
33657 .attr('class', 'feature-list cf');
33660 .on('exit.feature-list', clearSearch);
33662 .on('drawn.feature-list', mapDrawn);
33664 function clearSearch() {
33665 search.property('value', '');
33669 function mapDrawn(e) {
33675 function features() {
33678 graph = context.graph(),
33679 q = search.property('value').toLowerCase();
33681 if (!q) return result;
33683 var idMatch = q.match(/^([nwr])([0-9]+)$/);
33688 geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
33689 type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
33694 var locationMatch = sexagesimal.pair(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
33696 if (locationMatch) {
33697 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
33701 type: t('inspector.location'),
33702 name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
33707 function addEntity(entity) {
33708 if (entity.id in entities || result.length > 200)
33711 entities[entity.id] = true;
33713 var name = iD.util.displayName(entity) || '';
33714 if (name.toLowerCase().indexOf(q) >= 0) {
33718 geometry: context.geometry(entity.id),
33719 type: context.presets().match(entity, graph).name(),
33724 graph.parentRelations(entity).forEach(function(parent) {
33729 var visible = context.surface().selectAll('.point, .line, .area')[0];
33730 for (var i = 0; i < visible.length && result.length <= 200; i++) {
33731 addEntity(visible[i].__data__);
33734 (geocodeResults || []).forEach(function(d) {
33735 // https://github.com/openstreetmap/iD/issues/1890
33736 if (d.osm_type && d.osm_id) {
33738 id: iD.Entity.id.fromOSM(d.osm_type, d.osm_id),
33739 geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
33740 type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
33741 : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
33742 name: d.display_name,
33743 extent: new iD.geo.Extent(
33744 [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
33745 [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
33753 function drawList() {
33754 var value = search.property('value'),
33755 results = features();
33757 list.classed('filtered', value.length);
33759 var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
33761 var resultsIndicator = list.selectAll('.no-results-item')
33763 .enter().append('button')
33764 .property('disabled', true)
33765 .attr('class', 'no-results-item')
33766 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
33768 resultsIndicator.append('span')
33769 .attr('class', 'entity-name');
33771 list.selectAll('.no-results-item .entity-name')
33772 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
33774 list.selectAll('.geocode-item')
33776 .enter().append('button')
33777 .attr('class', 'geocode-item')
33778 .on('click', geocode)
33780 .attr('class', 'label')
33782 .attr('class', 'entity-name')
33783 .text(t('geocoder.search'));
33785 list.selectAll('.no-results-item')
33786 .style('display', (value.length && !results.length) ? 'block' : 'none');
33788 list.selectAll('.geocode-item')
33789 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
33791 list.selectAll('.feature-list-item')
33795 var items = list.selectAll('.feature-list-item')
33796 .data(results, function(d) { return d.id; });
33798 var enter = items.enter()
33799 .insert('button', '.geocode-item')
33800 .attr('class', 'feature-list-item')
33801 .on('mouseover', mouseover)
33802 .on('mouseout', mouseout)
33803 .on('click', click);
33807 .attr('class', 'label');
33809 label.each(function(d) {
33811 .call(iD.svg.Icon('#icon-' + d.geometry, 'pre-text'));
33814 label.append('span')
33815 .attr('class', 'entity-type')
33816 .text(function(d) { return d.type; });
33818 label.append('span')
33819 .attr('class', 'entity-name')
33820 .text(function(d) { return d.name; });
33822 enter.style('opacity', 0)
33824 .style('opacity', 1);
33832 function mouseover(d) {
33833 if (d.id === -1) return;
33835 context.surface().selectAll(iD.util.entityOrMemberSelector([d.id], context.graph()))
33836 .classed('hover', true);
33839 function mouseout() {
33840 context.surface().selectAll('.hover')
33841 .classed('hover', false);
33844 function click(d) {
33845 d3.event.preventDefault();
33847 context.map().centerZoom([d.location[1], d.location[0]], 20);
33849 else if (d.entity) {
33850 if (d.entity.type === 'node') {
33851 context.map().center(d.entity.loc);
33852 } else if (d.entity.type === 'way') {
33853 var center = context.projection(context.map().center()),
33854 edge = iD.geo.chooseEdge(context.childNodes(d.entity), center, context.projection);
33855 context.map().center(edge.loc);
33857 context.enter(iD.modes.Select(context, [d.entity.id]).suppressMenu(true));
33859 context.zoomToEntity(d.id);
33863 function geocode() {
33864 var searchVal = encodeURIComponent(search.property('value'));
33865 d3.json('https://nominatim.openstreetmap.org/search/' + searchVal + '?limit=10&format=json', function(err, resp) {
33866 geocodeResults = resp || [];
33872 return featureList;
33874 iD.ui.flash = function(selection) {
33875 var modal = iD.ui.modal(selection);
33877 modal.select('.modal').classed('modal-flash', true);
33879 modal.select('.content')
33880 .classed('modal-section', true)
33882 .attr('class', 'description');
33884 modal.on('click.flash', function() { modal.remove(); });
33886 setTimeout(function() {
33893 iD.ui.FullScreen = function(context) {
33894 var element = context.container().node(),
33895 keybinding = d3.keybinding('full-screen');
33898 function getFullScreenFn() {
33899 if (element.requestFullscreen) {
33900 return element.requestFullscreen;
33901 } else if (element.msRequestFullscreen) {
33902 return element.msRequestFullscreen;
33903 } else if (element.mozRequestFullScreen) {
33904 return element.mozRequestFullScreen;
33905 } else if (element.webkitRequestFullscreen) {
33906 return element.webkitRequestFullscreen;
33910 function getExitFullScreenFn() {
33911 if (document.exitFullscreen) {
33912 return document.exitFullscreen;
33913 } else if (document.msExitFullscreen) {
33914 return document.msExitFullscreen;
33915 } else if (document.mozCancelFullScreen) {
33916 return document.mozCancelFullScreen;
33917 } else if (document.webkitExitFullscreen) {
33918 return document.webkitExitFullscreen;
33922 function isFullScreen() {
33923 return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement ||
33924 document.msFullscreenElement;
33927 function isSupported() {
33928 return !!getFullScreenFn();
33931 function fullScreen() {
33932 d3.event.preventDefault();
33933 if (!isFullScreen()) {
33934 // button.classed('active', true);
33935 getFullScreenFn().apply(element);
33937 // button.classed('active', false);
33938 getExitFullScreenFn().apply(document);
33942 return function() { // selection) {
33943 if (!isSupported())
33946 // var tooltip = bootstrap.tooltip()
33947 // .placement('left');
33949 // button = selection.append('button')
33950 // .attr('title', t('full_screen'))
33951 // .attr('tabindex', -1)
33952 // .on('click', fullScreen)
33955 // button.append('span')
33956 // .attr('class', 'icon full-screen');
33959 .on('f11', fullScreen)
33960 .on(iD.ui.cmd('⌘⇧F'), fullScreen);
33962 d3.select(document)
33966 iD.ui.Geolocate = function(map) {
33968 navigator.geolocation.getCurrentPosition(
33972 function success(position) {
33973 var extent = iD.geo.Extent([position.coords.longitude, position.coords.latitude])
33974 .padByMeters(position.coords.accuracy);
33976 map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
33979 function error() { }
33981 return function(selection) {
33982 if (!navigator.geolocation) return;
33984 selection.append('button')
33985 .attr('tabindex', -1)
33986 .attr('title', t('geolocate.title'))
33987 .on('click', click)
33988 .call(iD.svg.Icon('#icon-geolocate', 'light'))
33989 .call(bootstrap.tooltip()
33990 .placement('left'));
33993 iD.ui.Help = function(context) {
33998 'help.editing_saving',
34007 var docs = docKeys.map(function(key) {
34010 title: text.split('\n')[0].replace('#', '').trim(),
34011 html: marked(text.split('\n').slice(1).join('\n'))
34015 function help(selection) {
34021 function toggle() {
34022 if (d3.event) d3.event.preventDefault();
34023 tooltip.hide(button);
34024 setVisible(!button.classed('active'));
34027 function setVisible(show) {
34028 if (show !== shown) {
34029 button.classed('active', show);
34033 selection.on('mousedown.help-inside', function() {
34034 return d3.event.stopPropagation();
34036 pane.style('display', 'block')
34037 .style('right', '-500px')
34040 .style('right', '0px');
34042 pane.style('right', '0px')
34045 .style('right', '-500px')
34046 .each('end', function() {
34047 d3.select(this).style('display', 'none');
34049 selection.on('mousedown.help-inside', null);
34054 function clickHelp(d, i) {
34055 pane.property('scrollTop', 0);
34056 doctitle.html(d.title);
34058 body.selectAll('a')
34059 .attr('target', '_blank');
34060 menuItems.classed('selected', function(m) {
34061 return m.title === d.title;
34067 var prevLink = nav.append('a')
34068 .attr('class', 'previous')
34069 .on('click', function() {
34070 clickHelp(docs[i - 1], i - 1);
34072 prevLink.append('span').html('◄ ' + docs[i - 1].title);
34074 if (i < docs.length - 1) {
34075 var nextLink = nav.append('a')
34076 .attr('class', 'next')
34077 .on('click', function() {
34078 clickHelp(docs[i + 1], i + 1);
34080 nextLink.append('span').html(docs[i + 1].title + ' ►');
34084 function clickWalkthrough() {
34085 d3.select(document.body).call(iD.ui.intro(context));
34090 var pane = selection.append('div')
34091 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
34092 tooltip = bootstrap.tooltip()
34095 .title(iD.ui.tooltipHtml(t('help.title'), key)),
34096 button = selection.append('button')
34097 .attr('tabindex', -1)
34098 .on('click', toggle)
34099 .call(iD.svg.Icon('#icon-help', 'light'))
34104 var toc = pane.append('ul')
34105 .attr('class', 'toc');
34107 var menuItems = toc.selectAll('li')
34112 .html(function(d) { return d.title; })
34113 .on('click', clickHelp);
34116 .attr('class','walkthrough')
34118 .text(t('splash.walkthrough'))
34119 .on('click', clickWalkthrough);
34121 var content = pane.append('div')
34122 .attr('class', 'left-content');
34124 var doctitle = content.append('h2')
34125 .text(t('help.title'));
34127 var body = content.append('div')
34128 .attr('class', 'body');
34130 var nav = content.append('div')
34131 .attr('class', 'nav');
34133 clickHelp(docs[0], 0);
34135 var keybinding = d3.keybinding('help')
34140 d3.select(document)
34143 context.surface().on('mousedown.help-outside', hide);
34144 context.container().on('mousedown.help-outside', hide);
34149 iD.ui.Info = function(context) {
34150 var key = iD.ui.cmd('⌘I'),
34151 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
34154 function info(selection) {
34155 function radiansToMeters(r) {
34156 // using WGS84 authalic radius (6371007.1809 m)
34157 return r * 6371007.1809;
34160 function steradiansToSqmeters(r) {
34161 // http://gis.stackexchange.com/a/124857/40446
34162 return r / 12.56637 * 510065621724000;
34165 function toLineString(feature) {
34166 if (feature.type === 'LineString') return feature;
34168 var result = { type: 'LineString', coordinates: [] };
34169 if (feature.type === 'Polygon') {
34170 result.coordinates = feature.coordinates[0];
34171 } else if (feature.type === 'MultiPolygon') {
34172 result.coordinates = feature.coordinates[0][0];
34178 function displayLength(m) {
34179 var d = m * (imperial ? 3.28084 : 1),
34198 // drop unnecessary precision
34199 p = d > 1000 ? 0 : d > 100 ? 1 : 2;
34201 return String(d.toFixed(p)) + ' ' + unit;
34204 function displayArea(m2) {
34205 var d = m2 * (imperial ? 10.7639111056 : 1),
34206 d1, d2, p1, p2, unit1, unit2;
34209 if (d >= 6969600) { // > 0.25mi² show mi²
34217 if (d > 4356 && d < 43560000) { // 0.1 - 1000 acres
34223 if (d >= 250000) { // > 0.25km² show km²
34231 if (d > 1000 && d < 10000000) { // 0.1 - 1000 hectares
34237 // drop unnecessary precision
34238 p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
34239 p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
34241 return String(d1.toFixed(p1)) + ' ' + unit1 +
34242 (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
34246 function redraw() {
34247 if (hidden) return;
34249 var resolver = context.graph(),
34250 selected = _.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
34251 singular = selected.length === 1 ? selected[0] : null,
34252 extent = iD.geo.Extent(),
34257 .attr('class', 'infobox-heading fillD')
34258 .text(singular || t('infobox.selected', { n: selected.length }));
34260 if (!selected.length) return;
34263 for (var i = 0; i < selected.length; i++) {
34264 entity = context.entity(selected[i]);
34265 extent._extend(entity.extent(resolver));
34267 center = extent.center();
34270 var list = wrap.append('ul');
34272 // multiple wrap, just display extent center..
34275 .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
34279 // single wrap, display details..
34280 if (!entity) return;
34281 var geometry = entity.geometry(resolver);
34283 if (geometry === 'line' || geometry === 'area') {
34284 var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
34285 feature = entity.asGeoJSON(resolver),
34286 length = radiansToMeters(d3.geo.length(toLineString(feature))),
34287 lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')),
34288 centroid = d3.geo.centroid(feature);
34291 .text(t('infobox.geometry') + ': ' +
34292 (closed ? t('infobox.closed') + ' ' : '') + t('geometry.' + geometry) );
34295 var area = steradiansToSqmeters(entity.area(resolver));
34297 .text(t('infobox.area') + ': ' + displayArea(area));
34301 .text(lengthLabel + ': ' + displayLength(length));
34304 .text(t('infobox.centroid') + ': ' + centroid[0].toFixed(5) + ', ' + centroid[1].toFixed(5));
34307 var toggle = imperial ? 'imperial' : 'metric';
34309 .text(t('infobox.' + toggle))
34311 .attr('class', 'button')
34312 .on('click', function() {
34313 d3.event.preventDefault();
34314 imperial = !imperial;
34319 var centerLabel = t('infobox.' + (entity.type === 'node' ? 'location' : 'center'));
34322 .text(t('infobox.geometry') + ': ' + t('geometry.' + geometry));
34325 .text(centerLabel + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
34330 function toggle() {
34331 if (d3.event) d3.event.preventDefault();
34337 .style('display', 'block')
34338 .style('opacity', 1)
34341 .style('opacity', 0)
34342 .each('end', function() {
34343 d3.select(this).style('display', 'none');
34347 .style('display', 'block')
34348 .style('opacity', 0)
34351 .style('opacity', 1);
34358 var wrap = selection.selectAll('.infobox')
34363 .attr('class', 'infobox fillD2')
34364 .style('display', (hidden ? 'none' : 'block'));
34367 .on('drawn.info', redraw);
34371 var keybinding = d3.keybinding('info')
34374 d3.select(document)
34380 iD.ui.Inspector = function(context) {
34381 var presetList = iD.ui.PresetList(context),
34382 entityEditor = iD.ui.EntityEditor(context),
34385 newFeature = false;
34387 function inspector(selection) {
34389 .entityID(entityID)
34390 .autofocus(newFeature)
34391 .on('choose', setPreset);
34395 .entityID(entityID)
34396 .on('choose', showList);
34398 var $wrap = selection.selectAll('.panewrap')
34401 var $enter = $wrap.enter().append('div')
34402 .attr('class', 'panewrap');
34404 $enter.append('div')
34405 .attr('class', 'preset-list-pane pane');
34407 $enter.append('div')
34408 .attr('class', 'entity-editor-pane pane');
34410 var $presetPane = $wrap.select('.preset-list-pane');
34411 var $editorPane = $wrap.select('.entity-editor-pane');
34413 var graph = context.graph(),
34414 entity = context.entity(entityID),
34415 showEditor = state === 'hover' ||
34416 entity.isUsed(graph) ||
34417 entity.isHighwayIntersection(graph);
34420 $wrap.style('right', '0%');
34421 $editorPane.call(entityEditor);
34423 $wrap.style('right', '-100%');
34424 $presetPane.call(presetList);
34427 var $footer = selection.selectAll('.footer')
34430 $footer.enter().append('div')
34431 .attr('class', 'footer');
34433 selection.select('.footer')
34434 .call(iD.ui.ViewOnOSM(context)
34435 .entityID(entityID));
34437 function showList(preset) {
34439 .styleTween('right', function() { return d3.interpolate('0%', '-100%'); });
34441 $presetPane.call(presetList
34446 function setPreset(preset) {
34448 .styleTween('right', function() { return d3.interpolate('-100%', '0%'); });
34450 $editorPane.call(entityEditor
34455 inspector.state = function(_) {
34456 if (!arguments.length) return state;
34458 entityEditor.state(state);
34462 inspector.entityID = function(_) {
34463 if (!arguments.length) return entityID;
34468 inspector.newFeature = function(_) {
34469 if (!arguments.length) return newFeature;
34476 iD.ui.intro = function(context) {
34479 function intro(selection) {
34481 function localizedName(id) {
34483 n2140018997: 'city_hall',
34484 n367813436: 'fire_department',
34485 w203988286: 'memory_isle_park',
34486 w203972937: 'riverwalk_trail',
34487 w203972938: 'riverwalk_trail',
34488 w203972940: 'riverwalk_trail',
34489 w41785752: 'w_michigan_ave',
34490 w134150789: 'w_michigan_ave',
34491 w134150795: 'w_michigan_ave',
34492 w134150800: 'w_michigan_ave',
34493 w134150811: 'w_michigan_ave',
34494 w134150802: 'e_michigan_ave',
34495 w134150836: 'e_michigan_ave',
34496 w41074896: 'e_michigan_ave',
34497 w17965834: 'spring_st',
34498 w203986457: 'scidmore_park',
34499 w203049587: 'petting_zoo',
34500 w17967397: 'n_andrews_st',
34501 w17967315: 's_andrews_st',
34502 w17967326: 'n_constantine_st',
34503 w17966400: 's_constantine_st',
34504 w170848823: 'rocky_river',
34505 w170848824: 'rocky_river',
34506 w170848331: 'rocky_river',
34507 w17967752: 'railroad_dr',
34508 w17965998: 'conrail_rr',
34509 w134150845: 'conrail_rr',
34510 w170989131: 'st_joseph_river',
34511 w143497377: 'n_main_st',
34512 w134150801: 's_main_st',
34513 w134150830: 's_main_st',
34514 w17966462: 's_main_st',
34515 w17967734: 'water_st',
34516 w17964996: 'foster_st',
34517 w170848330: 'portage_river',
34518 w17965351: 'flower_st',
34519 w17965502: 'elm_st',
34520 w17965402: 'walnut_st',
34521 w17964793: 'morris_ave',
34522 w17967444: 'east_st',
34523 w17966984: 'portage_ave'
34525 return features[id] && t('intro.graph.' + features[id]);
34528 context.enter(iD.modes.Browse(context));
34530 // Save current map state
34531 var history = context.history().toJSON(),
34532 hash = window.location.hash,
34533 center = context.map().center(),
34534 zoom = context.map().zoom(),
34535 background = context.background().baseLayerSource(),
34536 opacity = d3.selectAll('#map .layer-background').style('opacity'),
34537 loadedTiles = context.connection().loadedTiles(),
34538 baseEntities = context.history().graph().base().entities,
34542 context.inIntro(true);
34544 // Load semi-real data used in intro
34545 context.connection().toggle(false).flush();
34546 context.history().reset();
34548 introGraph = JSON.parse(iD.introGraph);
34549 for (var key in introGraph) {
34550 introGraph[key] = iD.Entity(introGraph[key]);
34551 name = localizedName(key);
34553 introGraph[key].tags.name = name;
34556 context.history().merge(d3.values(iD.Graph().load(introGraph).entities));
34557 context.background().bing();
34559 d3.selectAll('#map .layer-background').style('opacity', 1);
34561 var curtain = d3.curtain();
34562 selection.call(curtain);
34564 function reveal(box, text, options) {
34565 options = options || {};
34566 if (text) curtain.reveal(box, text, options.tooltipClass, options.duration);
34567 else curtain.reveal(box, '', '', options.duration);
34570 var steps = ['navigation', 'point', 'area', 'line', 'startEditing'].map(function(step, i) {
34571 var s = iD.ui.intro[step](context, reveal)
34572 .on('done', function() {
34573 entered.filter(function(d) {
34574 return d.title === s.title;
34575 }).classed('finished', true);
34576 enter(steps[i + 1]);
34581 steps[steps.length - 1].on('startEditing', function() {
34584 d3.selectAll('#map .layer-background').style('opacity', opacity);
34585 context.connection().toggle(true).flush().loadedTiles(loadedTiles);
34586 context.history().reset().merge(d3.values(baseEntities));
34587 context.background().baseLayerSource(background);
34588 if (history) context.history().fromJSON(history, false);
34589 context.map().centerZoom(center, zoom);
34590 window.location.replace(hash);
34591 context.inIntro(false);
34594 var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
34596 var buttonwrap = navwrap.append('div')
34597 .attr('class', 'joined')
34598 .selectAll('button.step');
34600 var entered = buttonwrap
34604 .attr('class', 'step')
34605 .on('click', enter);
34608 .call(iD.svg.Icon('#icon-apply', 'pre-text'));
34612 .text(function(d) { return t(d.title); });
34616 function enter (newStep) {
34617 if (step) { step.exit(); }
34619 context.enter(iD.modes.Browse(context));
34624 entered.classed('active', function(d) {
34625 return d.title === step.title;
34633 iD.ui.intro.pointBox = function(point, context) {
34634 var rect = context.surfaceRect();
34635 point = context.projection(point);
34637 left: point[0] + rect.left - 30,
34638 top: point[1] + rect.top - 50,
34644 iD.ui.intro.pad = function(box, padding, context) {
34645 if (box instanceof Array) {
34646 var rect = context.surfaceRect();
34647 box = context.projection(box);
34649 left: box[0] + rect.left,
34650 top: box[1] + rect.top
34654 left: box.left - padding,
34655 top: box.top - padding,
34656 width: (box.width || 0) + 2 * padding,
34657 height: (box.width || 0) + 2 * padding
34661 iD.ui.intro.icon = function(name, svgklass) {
34662 return '<svg class="icon ' + (svgklass || '') + '">' +
34663 '<use xlink:href="' + name + '"></use></svg>';
34665 iD.ui.Lasso = function(context) {
34671 function lasso(selection) {
34673 context.container().classed('lasso', true);
34675 group = selection.append('g')
34676 .attr('class', 'lasso hide');
34678 box = group.append('rect')
34679 .attr('class', 'lasso-box');
34681 group.call(iD.ui.Toggle(true));
34686 function topLeft(d) {
34687 return 'translate(' + Math.min(d[0][0], d[1][0]) + ',' + Math.min(d[0][1], d[1][1]) + ')';
34690 function width(d) { return Math.abs(d[0][0] - d[1][0]); }
34691 function height(d) { return Math.abs(d[0][1] - d[1][1]); }
34696 .attr('transform', topLeft)
34697 .attr('width', width)
34698 .attr('height', height);
34702 lasso.a = function(_) {
34703 if (!arguments.length) return a;
34709 lasso.b = function(_) {
34710 if (!arguments.length) return b;
34716 lasso.close = function() {
34718 group.call(iD.ui.Toggle(false, function() {
34719 d3.select(this).remove();
34722 context.container().classed('lasso', false);
34727 iD.ui.Loading = function(context) {
34732 var loading = function(selection) {
34733 modal = iD.ui.modal(selection, blocking);
34735 var loadertext = modal.select('.content')
34736 .classed('loading-modal', true)
34738 .attr('class', 'modal-section fillL');
34740 loadertext.append('img')
34741 .attr('class', 'loader')
34742 .attr('src', context.imagePath('loader-white.gif'));
34744 loadertext.append('h3')
34747 modal.select('button.close')
34748 .attr('class', 'hide');
34753 loading.message = function(_) {
34754 if (!arguments.length) return message;
34759 loading.blocking = function(_) {
34760 if (!arguments.length) return blocking;
34765 loading.close = function() {
34771 iD.ui.MapData = function(context) {
34773 features = context.features().keys(),
34774 layers = context.layers(),
34775 fills = ['wireframe', 'partial', 'full'],
34776 fillDefault = context.storage('area-fill') || 'partial',
34777 fillSelected = fillDefault;
34780 function map_data(selection) {
34782 function showsFeature(d) {
34783 return context.features().enabled(d);
34786 function autoHiddenFeature(d) {
34787 return context.features().autoHidden(d);
34790 function clickFeature(d) {
34791 context.features().toggle(d);
34795 function showsFill(d) {
34796 return fillSelected === d;
34799 function setFill(d) {
34800 _.each(fills, function(opt) {
34801 context.surface().classed('fill-' + opt, Boolean(opt === d));
34805 if (d !== 'wireframe') {
34807 context.storage('area-fill', d);
34812 function toggleLayer(which) {
34813 var layer = layers.layer(which);
34815 layer.enabled(!layer.enabled());
34820 function clickGpx() {
34821 toggleLayer('gpx');
34824 function clickMapillaryImages() {
34825 toggleLayer('mapillary-images');
34828 function clickMapillarySigns() {
34829 toggleLayer('mapillary-signs');
34833 function drawMapillaryItems(selection) {
34834 var mapillaryImages = layers.layer('mapillary-images'),
34835 mapillarySigns = layers.layer('mapillary-signs'),
34836 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
34837 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
34838 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
34839 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
34841 var mapillaryList = selection
34842 .selectAll('.layer-list-mapillary')
34849 .attr('class', 'layer-list layer-list-mapillary');
34851 var mapillaryImageLayerItem = mapillaryList
34852 .selectAll('.list-item-mapillary-images')
34853 .data(supportsMapillaryImages ? [0] : []);
34855 var enterImages = mapillaryImageLayerItem.enter()
34857 .attr('class', 'list-item-mapillary-images');
34859 var labelImages = enterImages.append('label')
34860 .call(bootstrap.tooltip()
34861 .title(t('mapillary_images.tooltip'))
34862 .placement('top'));
34864 labelImages.append('input')
34865 .attr('type', 'checkbox')
34866 .on('change', clickMapillaryImages);
34868 labelImages.append('span')
34869 .text(t('mapillary_images.title'));
34872 var mapillarySignLayerItem = mapillaryList
34873 .selectAll('.list-item-mapillary-signs')
34874 .data(supportsMapillarySigns ? [0] : []);
34876 var enterSigns = mapillarySignLayerItem.enter()
34878 .attr('class', 'list-item-mapillary-signs');
34880 var labelSigns = enterSigns.append('label')
34881 .call(bootstrap.tooltip()
34882 .title(t('mapillary_signs.tooltip'))
34883 .placement('top'));
34885 labelSigns.append('input')
34886 .attr('type', 'checkbox')
34887 .on('change', clickMapillarySigns);
34889 labelSigns.append('span')
34890 .text(t('mapillary_signs.title'));
34893 mapillaryImageLayerItem
34894 .classed('active', showsMapillaryImages)
34895 .selectAll('input')
34896 .property('checked', showsMapillaryImages);
34898 mapillarySignLayerItem
34899 .classed('active', showsMapillarySigns)
34900 .selectAll('input')
34901 .property('checked', showsMapillarySigns);
34904 mapillaryImageLayerItem.exit()
34906 mapillarySignLayerItem.exit()
34911 function drawGpxItem(selection) {
34912 var gpx = layers.layer('gpx'),
34913 hasGpx = gpx && gpx.hasGpx(),
34914 showsGpx = hasGpx && gpx.enabled();
34916 var gpxLayerItem = selection
34917 .selectAll('.layer-list-gpx')
34918 .data(gpx ? [0] : []);
34921 var enter = gpxLayerItem.enter()
34923 .attr('class', 'layer-list layer-list-gpx')
34925 .classed('list-item-gpx', true);
34927 enter.append('button')
34928 .attr('class', 'list-item-gpx-extent')
34929 .call(bootstrap.tooltip()
34930 .title(t('gpx.zoom'))
34931 .placement('left'))
34932 .on('click', function() {
34933 d3.event.preventDefault();
34934 d3.event.stopPropagation();
34937 .call(iD.svg.Icon('#icon-search'));
34939 enter.append('button')
34940 .attr('class', 'list-item-gpx-browse')
34941 .call(bootstrap.tooltip()
34942 .title(t('gpx.browse'))
34943 .placement('left'))
34944 .on('click', function() {
34945 d3.select(document.createElement('input'))
34946 .attr('type', 'file')
34947 .on('change', function() {
34948 gpx.files(d3.event.target.files);
34952 .call(iD.svg.Icon('#icon-geolocate'));
34954 var labelGpx = enter.append('label')
34955 .call(bootstrap.tooltip()
34956 .title(t('gpx.drag_drop'))
34957 .placement('top'));
34959 labelGpx.append('input')
34960 .attr('type', 'checkbox')
34961 .on('change', clickGpx);
34963 labelGpx.append('span')
34964 .text(t('gpx.local_layer'));
34968 .classed('active', showsGpx)
34969 .selectAll('input')
34970 .property('disabled', !hasGpx)
34971 .property('checked', showsGpx);
34974 gpxLayerItem.exit()
34979 function drawList(selection, data, type, name, change, active) {
34980 var items = selection.selectAll('li')
34984 var enter = items.enter()
34986 .attr('class', 'layer')
34987 .call(bootstrap.tooltip()
34989 .title(function(d) {
34990 var tip = t(name + '.' + d + '.tooltip'),
34991 key = (d === 'wireframe' ? 'W' : null);
34993 if (name === 'feature' && autoHiddenFeature(d)) {
34994 tip += '<div>' + t('map_data.autohidden') + '</div>';
34996 return iD.ui.tooltipHtml(tip, key);
35001 var label = enter.append('label');
35003 label.append('input')
35004 .attr('type', type)
35005 .attr('name', name)
35006 .on('change', change);
35008 label.append('span')
35009 .text(function(d) { return t(name + '.' + d + '.description'); });
35013 .classed('active', active)
35014 .selectAll('input')
35015 .property('checked', active)
35016 .property('indeterminate', function(d) {
35017 return (name === 'feature' && autoHiddenFeature(d));
35026 function update() {
35027 dataLayerContainer.call(drawMapillaryItems);
35028 dataLayerContainer.call(drawGpxItem);
35030 fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
35032 featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
35035 function hidePanel() {
35039 function togglePanel() {
35040 if (d3.event) d3.event.preventDefault();
35041 tooltip.hide(button);
35042 setVisible(!button.classed('active'));
35045 function toggleWireframe() {
35047 d3.event.preventDefault();
35048 d3.event.stopPropagation();
35050 setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
35051 context.map().pan([0,0]); // trigger a redraw
35054 function setVisible(show) {
35055 if (show !== shown) {
35056 button.classed('active', show);
35061 selection.on('mousedown.map_data-inside', function() {
35062 return d3.event.stopPropagation();
35064 content.style('display', 'block')
35065 .style('right', '-300px')
35068 .style('right', '0px');
35070 content.style('display', 'block')
35071 .style('right', '0px')
35074 .style('right', '-300px')
35075 .each('end', function() {
35076 d3.select(this).style('display', 'none');
35078 selection.on('mousedown.map_data-inside', null);
35084 var content = selection.append('div')
35085 .attr('class', 'fillL map-overlay col3 content hide'),
35086 tooltip = bootstrap.tooltip()
35089 .title(iD.ui.tooltipHtml(t('map_data.description'), key)),
35090 button = selection.append('button')
35091 .attr('tabindex', -1)
35092 .on('click', togglePanel)
35093 .call(iD.svg.Icon('#icon-data', 'light'))
35097 content.append('h4')
35098 .text(t('map_data.title'));
35102 content.append('a')
35103 .text(t('map_data.data_layers'))
35105 .classed('hide-toggle', true)
35106 .classed('expanded', true)
35107 .on('click', function() {
35108 var exp = d3.select(this).classed('expanded');
35109 dataLayerContainer.style('display', exp ? 'none' : 'block');
35110 d3.select(this).classed('expanded', !exp);
35111 d3.event.preventDefault();
35114 var dataLayerContainer = content.append('div')
35115 .attr('class', 'data-data-layers')
35116 .style('display', 'block');
35120 content.append('a')
35121 .text(t('map_data.fill_area'))
35123 .classed('hide-toggle', true)
35124 .classed('expanded', false)
35125 .on('click', function() {
35126 var exp = d3.select(this).classed('expanded');
35127 fillContainer.style('display', exp ? 'none' : 'block');
35128 d3.select(this).classed('expanded', !exp);
35129 d3.event.preventDefault();
35132 var fillContainer = content.append('div')
35133 .attr('class', 'data-area-fills')
35134 .style('display', 'none');
35136 var fillList = fillContainer.append('ul')
35137 .attr('class', 'layer-list layer-fill-list');
35141 content.append('a')
35142 .text(t('map_data.map_features'))
35144 .classed('hide-toggle', true)
35145 .classed('expanded', false)
35146 .on('click', function() {
35147 var exp = d3.select(this).classed('expanded');
35148 featureContainer.style('display', exp ? 'none' : 'block');
35149 d3.select(this).classed('expanded', !exp);
35150 d3.event.preventDefault();
35153 var featureContainer = content.append('div')
35154 .attr('class', 'data-feature-filters')
35155 .style('display', 'none');
35157 var featureList = featureContainer.append('ul')
35158 .attr('class', 'layer-list layer-feature-list');
35162 .on('change.map_data-update', update);
35164 setFill(fillDefault);
35166 var keybinding = d3.keybinding('features')
35167 .on(key, togglePanel)
35168 .on('W', toggleWireframe)
35169 .on('B', hidePanel)
35170 .on('H', hidePanel);
35172 d3.select(document)
35175 context.surface().on('mousedown.map_data-outside', hidePanel);
35176 context.container().on('mousedown.map_data-outside', hidePanel);
35181 iD.ui.MapInMap = function(context) {
35184 function map_in_map(selection) {
35185 var backgroundLayer = iD.TileLayer(),
35186 overlayLayers = {},
35187 projection = iD.geo.RawMercator(),
35188 gpxLayer = iD.svg.Gpx(projection, context).showLabels(false),
35189 zoom = d3.behavior.zoom()
35190 .scaleExtent([ztok(0.5), ztok(24)])
35191 .on('zoom', zoomPan),
35192 transformed = false,
35195 zDiff = 6, // by default, minimap renders at (main zoom - 6)
35196 tStart, tLast, tCurr, kLast, kCurr, tiles, svg, timeoutId;
35198 function ztok(z) { return 256 * Math.pow(2, z); }
35199 function ktoz(k) { return Math.log(k) / Math.LN2 - 8; }
35202 function startMouse() {
35203 context.surface().on('mouseup.map-in-map-outside', endMouse);
35204 context.container().on('mouseup.map-in-map-outside', endMouse);
35206 tStart = tLast = tCurr = projection.translate();
35211 function zoomPan() {
35212 var e = d3.event.sourceEvent,
35213 t = d3.event.translate,
35214 k = d3.event.scale,
35215 zMain = ktoz(context.projection.scale() * 2 * Math.PI),
35218 // restrict minimap zoom to < (main zoom - 3)
35219 if (zMini > zMain - 3) {
35221 zoom.scale(kCurr).translate(tCurr); // restore last good values
35227 zDiff = zMain - zMini;
35229 var scale = kCurr / kLast,
35230 tX = (tCurr[0] / scale - tLast[0]) * scale,
35231 tY = (tCurr[1] / scale - tLast[1]) * scale;
35233 iD.util.setTransform(tiles, tX, tY, scale);
35234 iD.util.setTransform(svg, 0, 0, scale);
35235 transformed = true;
35239 e.preventDefault();
35240 e.stopPropagation();
35244 function endMouse() {
35245 context.surface().on('mouseup.map-in-map-outside', null);
35246 context.container().on('mouseup.map-in-map-outside', null);
35248 updateProjection();
35251 if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) {
35252 var dMini = wrap.dimensions(),
35253 cMini = [ dMini[0] / 2, dMini[1] / 2 ];
35255 context.map().center(projection.invert(cMini));
35260 function updateProjection() {
35261 var loc = context.map().center(),
35262 dMini = wrap.dimensions(),
35263 cMini = [ dMini[0] / 2, dMini[1] / 2 ],
35264 tMain = context.projection.translate(),
35265 kMain = context.projection.scale(),
35266 zMain = ktoz(kMain * 2 * Math.PI),
35267 zMini = Math.max(zMain - zDiff, 0.5),
35268 kMini = ztok(zMini);
35272 .scale(kMini / (2 * Math.PI));
35274 var s = projection(loc),
35275 mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0],
35277 cMini[0] - s[0] + tMain[0] + mouse[0],
35278 cMini[1] - s[1] + tMain[1] + mouse[1]
35283 .clipExtent([[0, 0], dMini]);
35290 tLast = tCurr = tMini;
35291 kLast = kCurr = kMini;
35294 iD.util.setTransform(tiles, 0, 0);
35295 iD.util.setTransform(svg, 0, 0);
35296 transformed = false;
35301 function redraw() {
35302 if (hidden) return;
35304 updateProjection();
35306 var dMini = wrap.dimensions(),
35307 zMini = ktoz(projection.scale() * 2 * Math.PI);
35309 // setup tile container
35311 .selectAll('.map-in-map-tiles')
35317 .attr('class', 'map-in-map-tiles');
35319 // redraw background
35321 .source(context.background().baseLayerSource())
35322 .projection(projection)
35323 .dimensions(dMini);
35325 var background = tiles
35326 .selectAll('.map-in-map-background')
35331 .attr('class', 'map-in-map-background');
35334 .call(backgroundLayer);
35338 var overlaySources = context.background().overlayLayerSources();
35339 var activeOverlayLayers = [];
35340 for (var i = 0; i < overlaySources.length; i++) {
35341 if (overlaySources[i].validZoom(zMini)) {
35342 if (!overlayLayers[i]) overlayLayers[i] = iD.TileLayer();
35343 activeOverlayLayers.push(overlayLayers[i]
35344 .source(overlaySources[i])
35345 .projection(projection)
35346 .dimensions(dMini));
35350 var overlay = tiles
35351 .selectAll('.map-in-map-overlay')
35356 .attr('class', 'map-in-map-overlay');
35358 var overlays = overlay
35360 .data(activeOverlayLayers, function(d) { return d.source().name(); });
35362 overlays.enter().append('div');
35363 overlays.each(function(layer) {
35364 d3.select(this).call(layer);
35372 .selectAll('.map-in-map-gpx')
35373 .data(gpxLayer.enabled() ? [0] : []);
35377 .attr('class', 'map-in-map-gpx');
35382 gpx.call(gpxLayer);
35385 // redraw bounding box
35387 var getPath = d3.geo.path().projection(projection),
35388 bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
35390 svg = wrap.selectAll('.map-in-map-svg')
35395 .attr('class', 'map-in-map-svg');
35397 var path = svg.selectAll('.map-in-map-bbox')
35402 .attr('class', 'map-in-map-bbox');
35405 .attr('d', getPath)
35406 .classed('thick', function(d) { return getPath.area(d) < 30; });
35411 function queueRedraw() {
35412 clearTimeout(timeoutId);
35413 timeoutId = setTimeout(function() { redraw(); }, 300);
35417 function toggle() {
35418 if (d3.event) d3.event.preventDefault();
35422 var label = d3.select('.minimap-toggle');
35423 label.classed('active', !hidden)
35424 .select('input').property('checked', !hidden);
35428 .style('display', 'block')
35429 .style('opacity', 1)
35432 .style('opacity', 0)
35433 .each('end', function() {
35434 d3.select(this).style('display', 'none');
35438 .style('display', 'block')
35439 .style('opacity', 0)
35442 .style('opacity', 1);
35448 iD.ui.MapInMap.toggle = toggle;
35450 var wrap = selection.selectAll('.map-in-map')
35455 .attr('class', 'map-in-map')
35456 .style('display', (hidden ? 'none' : 'block'))
35457 .on('mousedown.map-in-map', startMouse)
35458 .on('mouseup.map-in-map', endMouse)
35460 .on('dblclick.zoom', null);
35463 .on('drawn.map-in-map', function(drawn) {
35464 if (drawn.full === true) redraw();
35469 var keybinding = d3.keybinding('map-in-map')
35472 d3.select(document)
35478 iD.ui.modal = function(selection, blocking) {
35480 var previous = selection.select('div.modal');
35481 var animate = previous.empty();
35483 previous.transition()
35485 .style('opacity', 0)
35488 var shaded = selection
35490 .attr('class', 'shaded')
35491 .style('opacity', 0);
35493 shaded.close = function() {
35497 .style('opacity',0)
35502 .style('top','0px');
35506 var keybinding = d3.keybinding('modal')
35507 .on('⌫', shaded.close)
35508 .on('⎋', shaded.close);
35510 d3.select(document).call(keybinding);
35512 var modal = shaded.append('div')
35513 .attr('class', 'modal fillL col6');
35515 shaded.on('click.remove-modal', function() {
35516 if (d3.event.target === this && !blocking) shaded.close();
35519 modal.append('button')
35520 .attr('class', 'close')
35521 .on('click', function() {
35522 if (!blocking) shaded.close();
35525 .attr('class','icon close');
35527 modal.append('div')
35528 .attr('class', 'content');
35531 shaded.transition().style('opacity', 1);
35533 shaded.style('opacity', 1);
35538 iD.ui.Modes = function(context) {
35540 iD.modes.AddPoint(context),
35541 iD.modes.AddLine(context),
35542 iD.modes.AddArea(context)];
35544 function editable() {
35545 return context.editable() && context.mode().id !== 'save';
35548 return function(selection) {
35549 var buttons = selection.selectAll('button.add-button')
35552 buttons.enter().append('button')
35553 .attr('tabindex', -1)
35554 .attr('class', function(mode) { return mode.id + ' add-button col4'; })
35555 .on('click.mode-buttons', function(mode) {
35556 if (mode.id === context.mode().id) {
35557 context.enter(iD.modes.Browse(context));
35559 context.enter(mode);
35562 .call(bootstrap.tooltip()
35563 .placement('bottom')
35565 .title(function(mode) {
35566 return iD.ui.tooltipHtml(mode.description, mode.key);
35570 .on('move.modes', _.debounce(update, 500));
35573 .on('enter.modes', update);
35575 buttons.each(function(d) {
35577 .call(iD.svg.Icon('#icon-' + d.button, 'pre-text'));
35580 buttons.append('span')
35581 .attr('class', 'label')
35582 .text(function(mode) { return mode.title; });
35584 context.on('enter.editor', function(entered) {
35585 buttons.classed('active', function(mode) { return entered.button === mode.button; });
35586 context.container()
35587 .classed('mode-' + entered.id, true);
35590 context.on('exit.editor', function(exited) {
35591 context.container()
35592 .classed('mode-' + exited.id, false);
35595 var keybinding = d3.keybinding('mode-buttons');
35597 modes.forEach(function(m) {
35598 keybinding.on(m.key, function() { if (editable()) context.enter(m); });
35601 d3.select(document)
35604 function update() {
35605 buttons.property('disabled', !editable());
35609 iD.ui.Notice = function(context) {
35610 return function(selection) {
35611 var div = selection.append('div')
35612 .attr('class', 'notice');
35614 var button = div.append('button')
35615 .attr('class', 'zoom-to notice')
35616 .on('click', function() { context.map().zoom(context.minEditableZoom()); });
35619 .call(iD.svg.Icon('#icon-plus', 'pre-text'))
35621 .attr('class', 'label')
35622 .text(t('zoom_in_edit'));
35624 function disableTooHigh() {
35625 div.style('display', context.editable() ? 'none' : 'block');
35629 .on('move.notice', _.debounce(disableTooHigh, 500));
35634 iD.ui.PresetIcon = function() {
35635 var preset, geometry;
35637 function presetIcon(selection) {
35638 selection.each(render);
35641 function render() {
35642 var selection = d3.select(this),
35643 p = preset.apply(this, arguments),
35644 geom = geometry.apply(this, arguments),
35645 icon = p.icon || (geom === 'line' ? 'other-line' : 'marker-stroked'),
35646 maki = iD.data.featureIcons.hasOwnProperty(icon + '-24');
35648 if (icon === 'dentist') maki = true; // workaround for dentist icon missing in `maki-sprite.json`
35650 function tag_classes(p) {
35652 for (var i in p.tags) {
35654 if (p.tags[i] !== '*') {
35655 s += ' tag-' + i + '-' + p.tags[i];
35661 var $fill = selection.selectAll('.preset-icon-fill')
35664 $fill.enter().append('div');
35666 $fill.attr('class', function() {
35667 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
35670 var $frame = selection.selectAll('.preset-icon-frame')
35675 .call(iD.svg.Icon('#preset-icon-frame'));
35677 $frame.attr('class', function() {
35678 return 'preset-icon-frame ' + (geom === 'area' ? '' : 'hide');
35682 var $icon = selection.selectAll('.preset-icon')
35687 .attr('class', 'preset-icon')
35688 .call(iD.svg.Icon(''));
35691 .attr('class', 'preset-icon preset-icon-' + (maki ? '32' : (geom === 'area' ? '44' : '60')));
35693 $icon.selectAll('svg')
35694 .attr('class', function() {
35695 return 'icon ' + icon + tag_classes(p);
35698 $icon.selectAll('use') // workaround: maki parking-24 broken?
35699 .attr('href', '#' + icon + (maki ? ( icon === 'parking' ? '-18' : '-24') : ''));
35702 presetIcon.preset = function(_) {
35703 if (!arguments.length) return preset;
35704 preset = d3.functor(_);
35708 presetIcon.geometry = function(_) {
35709 if (!arguments.length) return geometry;
35710 geometry = d3.functor(_);
35716 iD.ui.preset = function(context) {
35717 var event = d3.dispatch('change'),
35724 function UIField(field, entity, show) {
35725 field = _.clone(field);
35727 field.input = iD.ui.preset[field.type](field, context)
35728 .on('change', event.change);
35730 if (field.input.entity) field.input.entity(entity);
35732 field.keys = field.keys || [field.key];
35736 field.shown = function() {
35737 return field.id === 'name' || field.show || _.any(field.keys, function(key) { return !!tags[key]; });
35740 field.modified = function() {
35741 var original = context.graph().base().entities[entity.id];
35742 return _.any(field.keys, function(key) {
35743 return original ? tags[key] !== original.tags[key] : tags[key];
35747 field.revert = function() {
35748 var original = context.graph().base().entities[entity.id],
35750 field.keys.forEach(function(key) {
35751 t[key] = original ? original.tags[key] : undefined;
35756 field.present = function() {
35757 return _.any(field.keys, function(key) {
35762 field.remove = function() {
35764 field.keys.forEach(function(key) {
35765 t[key] = undefined;
35773 function fieldKey(field) {
35777 function presets(selection) {
35778 selection.call(iD.ui.Disclosure()
35779 .title(t('inspector.all_fields'))
35780 .expanded(context.storage('preset_fields.expanded') !== 'false')
35781 .on('toggled', toggled)
35782 .content(content));
35784 function toggled(expanded) {
35785 context.storage('preset_fields.expanded', expanded);
35789 function content(selection) {
35791 var entity = context.entity(id),
35792 geometry = context.geometry(id);
35794 fields = [UIField(context.presets().field('name'), entity)];
35796 preset.fields.forEach(function(field) {
35797 if (field.matchGeometry(geometry)) {
35798 fields.push(UIField(field, entity, true));
35802 if (entity.isHighwayIntersection(context.graph())) {
35803 fields.push(UIField(context.presets().field('restrictions'), entity, true));
35806 context.presets().universal().forEach(function(field) {
35807 if (preset.fields.indexOf(field) < 0) {
35808 fields.push(UIField(field, entity));
35813 var shown = fields.filter(function(field) { return field.shown(); }),
35814 notShown = fields.filter(function(field) { return !field.shown(); });
35816 var $form = selection.selectAll('.preset-form')
35819 $form.enter().append('div')
35820 .attr('class', 'preset-form inspector-inner fillL3');
35822 var $fields = $form.selectAll('.form-field')
35823 .data(shown, fieldKey);
35827 var $enter = $fields.enter()
35829 .attr('class', function(field) {
35830 return 'form-field form-field-' + field.id;
35833 var $label = $enter.append('label')
35834 .attr('class', 'form-label')
35835 .attr('for', function(field) { return 'preset-input-' + field.id; })
35836 .text(function(field) { return field.label(); });
35838 var wrap = $label.append('div')
35839 .attr('class', 'form-label-button-wrap');
35841 wrap.append('button')
35842 .attr('class', 'remove-icon')
35843 .call(iD.svg.Icon('#operation-delete'));
35845 wrap.append('button')
35846 .attr('class', 'modified-icon')
35847 .attr('tabindex', -1)
35848 .call(iD.svg.Icon('#icon-undo'));
35852 $fields.select('.form-label-button-wrap .remove-icon')
35853 .on('click', remove);
35855 $fields.select('.modified-icon')
35856 .on('click', revert);
35860 .classed('modified', function(field) {
35861 return field.modified();
35863 .classed('present', function(field) {
35864 return field.present();
35866 .each(function(field) {
35867 var reference = iD.ui.TagReference(field.reference || {key: field.key}, context);
35869 if (state === 'hover') {
35870 reference.showing(false);
35875 .selectAll('input')
35876 .on('keydown', function() {
35877 if (d3.event.keyCode === 13) { // enter
35878 context.enter(iD.modes.Browse(context));
35881 .call(reference.body)
35882 .select('.form-label-button-wrap')
35883 .call(reference.button);
35885 field.input.tags(tags);
35891 notShown = notShown.map(function(field) {
35893 title: field.label(),
35894 value: field.label(),
35899 var $more = selection.selectAll('.more-fields')
35900 .data((notShown.length > 0) ? [0] : []);
35902 $more.enter().append('div')
35903 .attr('class', 'more-fields')
35905 .text(t('inspector.add_fields'));
35907 var $input = $more.selectAll('.value')
35910 $input.enter().append('input')
35911 .attr('class', 'value')
35912 .attr('type', 'text');
35915 .attr('placeholder', function() {
35916 var placeholder = [];
35917 for (var field in notShown) {
35918 placeholder.push(notShown[field].title);
35920 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
35922 .call(d3.combobox().data(notShown)
35924 .on('accept', show));
35932 function show(field) {
35933 field = field.field;
35935 content(selection);
35936 field.input.focus();
35939 function revert(field) {
35940 d3.event.stopPropagation();
35941 d3.event.preventDefault();
35942 event.change(field.revert());
35945 function remove(field) {
35946 d3.event.stopPropagation();
35947 d3.event.preventDefault();
35948 event.change(field.remove());
35952 presets.preset = function(_) {
35953 if (!arguments.length) return preset;
35954 if (preset && preset.id === _.id) return presets;
35960 presets.state = function(_) {
35961 if (!arguments.length) return state;
35966 presets.tags = function(_) {
35967 if (!arguments.length) return tags;
35969 // Don't reset fields here.
35973 presets.entityID = function(_) {
35974 if (!arguments.length) return id;
35975 if (id === _) return presets;
35981 return d3.rebind(presets, event, 'on');
35983 iD.ui.PresetList = function(context) {
35984 var event = d3.dispatch('choose'),
35989 function presetList(selection) {
35990 var geometry = context.geometry(id),
35991 presets = context.presets().matchGeometry(geometry);
35993 selection.html('');
35995 var messagewrap = selection.append('div')
35996 .attr('class', 'header fillL cf');
35998 var message = messagewrap.append('h3')
35999 .text(t('inspector.choose'));
36001 if (context.entity(id).isUsed(context.graph())) {
36002 messagewrap.append('button')
36003 .attr('class', 'preset-choose')
36004 .on('click', function() { event.choose(currentPreset); })
36008 messagewrap.append('button')
36009 .attr('class', 'close')
36010 .on('click', function() {
36011 context.enter(iD.modes.Browse(context));
36013 .call(iD.svg.Icon('#icon-close'));
36016 function keydown() {
36017 // hack to let delete shortcut work when search is autofocused
36018 if (search.property('value').length === 0 &&
36019 (d3.event.keyCode === d3.keybinding.keyCodes['⌫'] ||
36020 d3.event.keyCode === d3.keybinding.keyCodes['⌦'])) {
36021 d3.event.preventDefault();
36022 d3.event.stopPropagation();
36023 iD.operations.Delete([id], context)();
36024 } else if (search.property('value').length === 0 &&
36025 (d3.event.ctrlKey || d3.event.metaKey) &&
36026 d3.event.keyCode === d3.keybinding.keyCodes.z) {
36027 d3.event.preventDefault();
36028 d3.event.stopPropagation();
36030 } else if (!d3.event.ctrlKey && !d3.event.metaKey) {
36031 d3.select(this).on('keydown', null);
36035 function keypress() {
36037 var value = search.property('value');
36038 if (d3.event.keyCode === 13 && value.length) {
36039 list.selectAll('.preset-list-item:first-child').datum().choose();
36043 function inputevent() {
36044 var value = search.property('value');
36045 list.classed('filtered', value.length);
36046 if (value.length) {
36047 var results = presets.search(value, geometry);
36048 message.text(t('inspector.results', {
36049 n: results.collection.length,
36052 list.call(drawList, results);
36054 list.call(drawList, context.presets().defaults(geometry, 36));
36055 message.text(t('inspector.choose'));
36059 var searchWrap = selection.append('div')
36060 .attr('class', 'search-header');
36062 var search = searchWrap.append('input')
36063 .attr('class', 'preset-search-input')
36064 .attr('placeholder', t('inspector.search'))
36065 .attr('type', 'search')
36066 .on('keydown', keydown)
36067 .on('keypress', keypress)
36068 .on('input', inputevent);
36071 .call(iD.svg.Icon('#icon-search', 'pre-text'));
36074 search.node().focus();
36077 var listWrap = selection.append('div')
36078 .attr('class', 'inspector-body');
36080 var list = listWrap.append('div')
36081 .attr('class', 'preset-list fillL cf')
36082 .call(drawList, context.presets().defaults(geometry, 36));
36085 function drawList(list, presets) {
36086 var collection = presets.collection.map(function(preset) {
36087 return preset.members ? CategoryItem(preset) : PresetItem(preset);
36090 var items = list.selectAll('.preset-list-item')
36091 .data(collection, function(d) { return d.preset.id; });
36093 items.enter().append('div')
36094 .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
36095 .classed('current', function(item) { return item.preset === currentPreset; })
36096 .each(function(item) {
36097 d3.select(this).call(item);
36099 .style('opacity', 0)
36101 .style('opacity', 1);
36109 function CategoryItem(preset) {
36110 var box, sublist, shown = false;
36112 function item(selection) {
36113 var wrap = selection.append('div')
36114 .attr('class', 'preset-list-button-wrap category col12');
36116 wrap.append('button')
36117 .attr('class', 'preset-list-button')
36118 .classed('expanded', false)
36119 .call(iD.ui.PresetIcon()
36120 .geometry(context.geometry(id))
36122 .on('click', function() {
36123 var isExpanded = d3.select(this).classed('expanded');
36124 var triangle = isExpanded ? '▶ ' : '▼ ';
36125 d3.select(this).classed('expanded', !isExpanded);
36126 d3.select(this).selectAll('.label').text(triangle + preset.name());
36130 .attr('class', 'label')
36132 return '▶ ' + preset.name();
36135 box = selection.append('div')
36136 .attr('class', 'subgrid col12')
36137 .style('max-height', '0px')
36138 .style('opacity', 0);
36141 .attr('class', 'arrow');
36143 sublist = box.append('div')
36144 .attr('class', 'preset-list fillL3 cf fl');
36147 item.choose = function() {
36148 if (!box || !sublist) return;
36154 .style('opacity', '0')
36155 .style('max-height', '0px')
36156 .style('padding-bottom', '0px');
36159 sublist.call(drawList, preset.members);
36162 .style('opacity', '1')
36163 .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
36164 .style('padding-bottom', '20px');
36168 item.preset = preset;
36173 function PresetItem(preset) {
36174 function item(selection) {
36175 var wrap = selection.append('div')
36176 .attr('class', 'preset-list-button-wrap col12');
36178 wrap.append('button')
36179 .attr('class', 'preset-list-button')
36180 .call(iD.ui.PresetIcon()
36181 .geometry(context.geometry(id))
36183 .on('click', item.choose)
36185 .attr('class', 'label')
36186 .text(preset.name());
36188 wrap.call(item.reference.button);
36189 selection.call(item.reference.body);
36192 item.choose = function() {
36193 context.presets().choose(preset);
36196 iD.actions.ChangePreset(id, currentPreset, preset),
36197 t('operations.change_tags.annotation'));
36199 event.choose(preset);
36202 item.help = function() {
36203 d3.event.stopPropagation();
36204 item.reference.toggle();
36207 item.preset = preset;
36208 item.reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context);
36213 presetList.autofocus = function(_) {
36214 if (!arguments.length) return autofocus;
36219 presetList.entityID = function(_) {
36220 if (!arguments.length) return id;
36222 presetList.preset(context.presets().match(context.entity(id), context.graph()));
36226 presetList.preset = function(_) {
36227 if (!arguments.length) return currentPreset;
36232 return d3.rebind(presetList, event, 'on');
36234 iD.ui.RadialMenu = function(context, operations) {
36239 var radialMenu = function(selection) {
36240 if (!operations.length)
36243 selection.node().parentNode.focus();
36245 function click(operation) {
36246 d3.event.stopPropagation();
36247 if (operation.disabled())
36250 radialMenu.close();
36253 menu = selection.append('g')
36254 .attr('class', 'radial-menu')
36255 .attr('transform', 'translate(' + center + ')')
36256 .attr('opacity', 0);
36259 .attr('opacity', 1);
36264 a1 = a0 + (operations.length - 1) * a;
36266 menu.append('path')
36267 .attr('class', 'radial-menu-background')
36268 .attr('d', 'M' + r * Math.sin(a0) + ',' +
36270 ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
36271 (r * Math.sin(a1) + 1e-3) + ',' +
36272 (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
36273 .attr('stroke-width', 50)
36274 .attr('stroke-linecap', 'round');
36276 var button = menu.selectAll()
36280 .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
36281 .classed('disabled', function(d) { return d.disabled(); })
36282 .attr('transform', function(d, i) {
36283 return 'translate(' + iD.geo.roundCoords([
36284 r * Math.sin(a0 + i * a),
36285 r * Math.cos(a0 + i * a)]).join(',') + ')';
36288 button.append('circle')
36290 .on('click', click)
36291 .on('mousedown', mousedown)
36292 .on('mouseover', mouseover)
36293 .on('mouseout', mouseout);
36295 button.append('use')
36296 .attr('transform', 'translate(-10,-10)')
36297 .attr('width', '20')
36298 .attr('height', '20')
36299 .attr('xlink:href', function(d) { return '#operation-' + d.id; });
36301 tooltip = d3.select(document.body)
36303 .attr('class', 'tooltip-inner radial-menu-tooltip');
36305 function mousedown() {
36306 d3.event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
36309 function mouseover(d, i) {
36310 var rect = context.surfaceRect(),
36311 angle = a0 + i * a,
36312 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
36313 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
36314 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
36315 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
36318 .style('top', null)
36319 .style('left', null)
36320 .style('bottom', null)
36321 .style('right', null)
36322 .style('display', 'block')
36323 .html(iD.ui.tooltipHtml(d.tooltip(), d.keys[0]));
36327 .style('right', right)
36328 .style('top', top);
36329 } else if (i >= 4) {
36331 .style('left', left)
36332 .style('bottom', bottom);
36335 .style('left', left)
36336 .style('top', top);
36340 function mouseout() {
36341 tooltip.style('display', 'none');
36345 radialMenu.close = function() {
36348 .style('pointer-events', 'none')
36350 .attr('opacity', 0)
36359 radialMenu.center = function(_) {
36360 if (!arguments.length) return center;
36367 iD.ui.RawMemberEditor = function(context) {
36370 function selectMember(d) {
36371 d3.event.preventDefault();
36372 context.enter(iD.modes.Select(context, [d.id]));
36375 function changeRole(d) {
36376 var role = d3.select(this).property('value');
36378 iD.actions.ChangeMember(d.relation.id, _.extend({}, d.id, {role: role}), d.index),
36379 t('operations.change_role.annotation'));
36382 function deleteMember(d) {
36384 iD.actions.DeleteMember(d.relation.id, d.index),
36385 t('operations.delete_member.annotation'));
36387 if (!context.hasEntity(d.relation.id)) {
36388 context.enter(iD.modes.Browse(context));
36392 function rawMemberEditor(selection) {
36393 var entity = context.entity(id),
36396 entity.members.forEach(function(member, index) {
36402 member: context.hasEntity(member.id)
36406 selection.call(iD.ui.Disclosure()
36407 .title(t('inspector.all_members') + ' (' + memberships.length + ')')
36409 .on('toggled', toggled)
36410 .content(content));
36412 function toggled(expanded) {
36414 selection.node().parentNode.scrollTop += 200;
36418 function content($wrap) {
36419 var $list = $wrap.selectAll('.member-list')
36422 $list.enter().append('ul')
36423 .attr('class', 'member-list');
36425 var $items = $list.selectAll('li')
36426 .data(memberships, function(d) {
36427 return iD.Entity.key(d.relation) + ',' + d.index + ',' +
36428 (d.member ? iD.Entity.key(d.member) : 'incomplete');
36431 var $enter = $items.enter().append('li')
36432 .attr('class', 'member-row form-field')
36433 .classed('member-incomplete', function(d) { return !d.member; });
36435 $enter.each(function(d) {
36437 var $label = d3.select(this).append('label')
36438 .attr('class', 'form-label')
36441 .on('click', selectMember);
36443 $label.append('span')
36444 .attr('class', 'member-entity-type')
36445 .text(function(d) { return context.presets().match(d.member, context.graph()).name(); });
36447 $label.append('span')
36448 .attr('class', 'member-entity-name')
36449 .text(function(d) { return iD.util.displayName(d.member); });
36452 d3.select(this).append('label')
36453 .attr('class', 'form-label')
36454 .text(t('inspector.incomplete'));
36458 $enter.append('input')
36459 .attr('class', 'member-role')
36460 .property('type', 'text')
36461 .attr('maxlength', 255)
36462 .attr('placeholder', t('inspector.role'))
36463 .property('value', function(d) { return d.role; })
36464 .on('change', changeRole);
36466 $enter.append('button')
36467 .attr('tabindex', -1)
36468 .attr('class', 'remove button-input-action member-delete minor')
36469 .on('click', deleteMember)
36470 .call(iD.svg.Icon('#operation-delete'));
36477 rawMemberEditor.entityID = function(_) {
36478 if (!arguments.length) return id;
36480 return rawMemberEditor;
36483 return rawMemberEditor;
36485 iD.ui.RawMembershipEditor = function(context) {
36488 function selectRelation(d) {
36489 d3.event.preventDefault();
36490 context.enter(iD.modes.Select(context, [d.relation.id]));
36493 function changeRole(d) {
36494 var role = d3.select(this).property('value');
36496 iD.actions.ChangeMember(d.relation.id, _.extend({}, d.member, {role: role}), d.index),
36497 t('operations.change_role.annotation'));
36500 function addMembership(d, role) {
36505 iD.actions.AddMember(d.relation.id, {id: id, type: context.entity(id).type, role: role}),
36506 t('operations.add_member.annotation'));
36509 var relation = iD.Relation();
36512 iD.actions.AddEntity(relation),
36513 iD.actions.AddMember(relation.id, {id: id, type: context.entity(id).type, role: role}),
36514 t('operations.add.annotation.relation'));
36516 context.enter(iD.modes.Select(context, [relation.id]));
36520 function deleteMembership(d) {
36522 iD.actions.DeleteMember(d.relation.id, d.index),
36523 t('operations.delete_member.annotation'));
36526 function relations(q) {
36527 var newRelation = {
36529 value: t('inspector.new_relation')
36532 graph = context.graph();
36534 context.intersects(context.extent()).forEach(function(entity) {
36535 if (entity.type !== 'relation' || entity.id === id)
36538 var presetName = context.presets().match(entity, graph).name(),
36539 entityName = iD.util.displayName(entity) || '';
36541 var value = presetName + ' ' + entityName;
36542 if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
36551 result.sort(function(a, b) {
36552 return iD.Relation.creationOrder(a.relation, b.relation);
36554 result.unshift(newRelation);
36559 function rawMembershipEditor(selection) {
36560 var entity = context.entity(id),
36563 context.graph().parentRelations(entity).forEach(function(relation) {
36564 relation.members.forEach(function(member, index) {
36565 if (member.id === entity.id) {
36566 memberships.push({relation: relation, member: member, index: index});
36571 selection.call(iD.ui.Disclosure()
36572 .title(t('inspector.all_relations') + ' (' + memberships.length + ')')
36574 .on('toggled', toggled)
36575 .content(content));
36577 function toggled(expanded) {
36579 selection.node().parentNode.scrollTop += 200;
36583 function content($wrap) {
36584 var $list = $wrap.selectAll('.member-list')
36587 $list.enter().append('ul')
36588 .attr('class', 'member-list');
36590 var $items = $list.selectAll('li.member-row-normal')
36591 .data(memberships, function(d) { return iD.Entity.key(d.relation) + ',' + d.index; });
36593 var $enter = $items.enter().append('li')
36594 .attr('class', 'member-row member-row-normal form-field');
36596 var $label = $enter.append('label')
36597 .attr('class', 'form-label')
36600 .on('click', selectRelation);
36602 $label.append('span')
36603 .attr('class', 'member-entity-type')
36604 .text(function(d) { return context.presets().match(d.relation, context.graph()).name(); });
36606 $label.append('span')
36607 .attr('class', 'member-entity-name')
36608 .text(function(d) { return iD.util.displayName(d.relation); });
36610 $enter.append('input')
36611 .attr('class', 'member-role')
36612 .property('type', 'text')
36613 .attr('maxlength', 255)
36614 .attr('placeholder', t('inspector.role'))
36615 .property('value', function(d) { return d.member.role; })
36616 .on('change', changeRole);
36618 $enter.append('button')
36619 .attr('tabindex', -1)
36620 .attr('class', 'remove button-input-action member-delete minor')
36621 .on('click', deleteMembership)
36622 .call(iD.svg.Icon('#operation-delete'));
36628 var $new = $list.selectAll('.member-row-new')
36631 $enter = $new.enter().append('li')
36632 .attr('class', 'member-row member-row-new form-field');
36634 $enter.append('input')
36635 .attr('type', 'text')
36636 .attr('class', 'member-entity-input')
36637 .call(d3.combobox()
36639 .fetcher(function(value, callback) {
36640 callback(relations(value));
36642 .on('accept', function(d) {
36643 addMembership(d, $new.select('.member-role').property('value'));
36646 $enter.append('input')
36647 .attr('class', 'member-role')
36648 .property('type', 'text')
36649 .attr('maxlength', 255)
36650 .attr('placeholder', t('inspector.role'))
36651 .on('change', changeRole);
36653 $enter.append('button')
36654 .attr('tabindex', -1)
36655 .attr('class', 'remove button-input-action member-delete minor')
36656 .on('click', deleteMembership)
36657 .call(iD.svg.Icon('#operation-delete'));
36660 $list.selectAll('.member-row-new')
36664 var $add = $wrap.selectAll('.add-relation')
36669 .attr('class', 'add-relation')
36670 .call(iD.svg.Icon('#icon-plus', 'light'));
36672 $wrap.selectAll('.add-relation')
36673 .on('click', function() {
36676 $list.selectAll('.member-entity-input').node().focus();
36681 rawMembershipEditor.entityID = function(_) {
36682 if (!arguments.length) return id;
36684 return rawMembershipEditor;
36687 return rawMembershipEditor;
36689 iD.ui.RawTagEditor = function(context) {
36690 var event = d3.dispatch('change'),
36697 function rawTagEditor(selection) {
36698 var count = Object.keys(tags).filter(function(d) { return d; }).length;
36700 selection.call(iD.ui.Disclosure()
36701 .title(t('inspector.all_tags') + ' (' + count + ')')
36702 .expanded(context.storage('raw_tag_editor.expanded') === 'true' || preset.isFallback())
36703 .on('toggled', toggled)
36704 .content(content));
36706 function toggled(expanded) {
36707 context.storage('raw_tag_editor.expanded', expanded);
36709 selection.node().parentNode.scrollTop += 200;
36714 function content($wrap) {
36715 var entries = d3.entries(tags);
36717 if (!entries.length || showBlank) {
36719 entries.push({key: '', value: ''});
36722 var $list = $wrap.selectAll('.tag-list')
36725 $list.enter().append('ul')
36726 .attr('class', 'tag-list');
36728 var $newTag = $wrap.selectAll('.add-tag')
36733 .attr('class', 'add-tag')
36734 .call(iD.svg.Icon('#icon-plus', 'light'));
36736 $newTag.on('click', addTag);
36738 var $items = $list.selectAll('li')
36739 .data(entries, function(d) { return d.key; });
36743 var $enter = $items.enter().append('li')
36744 .attr('class', 'tag-row cf');
36746 $enter.append('div')
36747 .attr('class', 'key-wrap')
36749 .property('type', 'text')
36750 .attr('class', 'key')
36751 .attr('maxlength', 255);
36753 $enter.append('div')
36754 .attr('class', 'input-wrap-position')
36756 .property('type', 'text')
36757 .attr('class', 'value')
36758 .attr('maxlength', 255);
36760 $enter.append('button')
36761 .attr('tabindex', -1)
36762 .attr('class', 'remove minor')
36763 .call(iD.svg.Icon('#operation-delete'));
36765 if (context.taginfo()) {
36766 $enter.each(bindTypeahead);
36773 $items.each(function(tag) {
36774 var isRelation = (context.entity(id).type === 'relation'),
36776 if (isRelation && tag.key === 'type')
36777 reference = iD.ui.TagReference({rtype: tag.value}, context);
36779 reference = iD.ui.TagReference({key: tag.key, value: tag.value}, context);
36781 if (state === 'hover') {
36782 reference.showing(false);
36786 .call(reference.button)
36787 .call(reference.body);
36790 $items.select('input.key')
36791 .value(function(d) { return d.key; })
36792 .on('blur', keyChange)
36793 .on('change', keyChange);
36795 $items.select('input.value')
36796 .value(function(d) { return d.value; })
36797 .on('blur', valueChange)
36798 .on('change', valueChange)
36799 .on('keydown.push-more', pushMore);
36801 $items.select('button.remove')
36802 .on('click', removeTag);
36808 function pushMore() {
36809 if (d3.event.keyCode === 9 && !d3.event.shiftKey &&
36810 $list.selectAll('li:last-child input.value').node() === this) {
36815 function bindTypeahead() {
36816 var row = d3.select(this),
36817 key = row.selectAll('input.key'),
36818 value = row.selectAll('input.value');
36820 function sort(value, data) {
36821 var sameletter = [],
36823 for (var i = 0; i < data.length; i++) {
36824 if (data[i].value.substring(0, value.length) === value) {
36825 sameletter.push(data[i]);
36827 other.push(data[i]);
36830 return sameletter.concat(other);
36833 key.call(d3.combobox()
36834 .fetcher(function(value, callback) {
36835 context.taginfo().keys({
36837 geometry: context.geometry(id),
36839 }, function(err, data) {
36840 if (!err) callback(sort(value, data));
36844 value.call(d3.combobox()
36845 .fetcher(function(value, callback) {
36846 context.taginfo().values({
36849 geometry: context.geometry(id),
36851 }, function(err, data) {
36852 if (!err) callback(sort(value, data));
36857 function unbind() {
36858 var row = d3.select(this);
36860 row.selectAll('input.key')
36861 .call(d3.combobox.off);
36863 row.selectAll('input.value')
36864 .call(d3.combobox.off);
36867 function keyChange(d) {
36869 kNew = this.value.trim(),
36872 if (kNew && kNew !== kOld) {
36873 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
36875 suffix = +(match[2] || 1);
36876 while (tags[kNew]) { // rename key if already in use
36877 kNew = base + '_' + suffix++;
36880 tag[kOld] = undefined;
36881 tag[kNew] = d.value;
36882 d.key = kNew; // Maintain DOM identity through the subsequent update.
36887 function valueChange(d) {
36889 tag[d.key] = this.value;
36893 function removeTag(d) {
36895 tag[d.key] = undefined;
36897 d3.select(this.parentNode).remove();
36900 function addTag() {
36901 // Wrapped in a setTimeout in case it's being called from a blur
36902 // handler. Without the setTimeout, the call to `content` would
36903 // wipe out the pending value change.
36904 setTimeout(function() {
36907 $list.selectAll('li:last-child input.key').node().focus();
36912 rawTagEditor.state = function(_) {
36913 if (!arguments.length) return state;
36915 return rawTagEditor;
36918 rawTagEditor.preset = function(_) {
36919 if (!arguments.length) return preset;
36921 return rawTagEditor;
36924 rawTagEditor.tags = function(_) {
36925 if (!arguments.length) return tags;
36927 return rawTagEditor;
36930 rawTagEditor.entityID = function(_) {
36931 if (!arguments.length) return id;
36933 return rawTagEditor;
36936 return d3.rebind(rawTagEditor, event, 'on');
36938 iD.ui.Restore = function(context) {
36939 return function(selection) {
36940 if (!context.history().lock() || !context.history().restorableChanges())
36943 var modal = iD.ui.modal(selection);
36945 modal.select('.modal')
36946 .attr('class', 'modal fillL col6');
36948 var introModal = modal.select('.content');
36950 introModal.attr('class','cf');
36952 introModal.append('div')
36953 .attr('class', 'modal-section')
36955 .text(t('restore.heading'));
36957 introModal.append('div')
36958 .attr('class','modal-section')
36960 .text(t('restore.description'));
36962 var buttonWrap = introModal.append('div')
36963 .attr('class', 'modal-actions cf');
36965 var restore = buttonWrap.append('button')
36966 .attr('class', 'restore col6')
36967 .text(t('restore.restore'))
36968 .on('click', function() {
36969 context.history().restore();
36973 buttonWrap.append('button')
36974 .attr('class', 'reset col6')
36975 .text(t('restore.reset'))
36976 .on('click', function() {
36977 context.history().clearSaved();
36981 restore.node().focus();
36984 iD.ui.Save = function(context) {
36985 var history = context.history(),
36986 key = iD.ui.cmd('⌘S');
36988 function saving() {
36989 return context.mode().id === 'save';
36993 d3.event.preventDefault();
36994 if (!context.inIntro() && !saving() && history.hasChanges()) {
36995 context.enter(iD.modes.Save(context));
36999 return function(selection) {
37000 var tooltip = bootstrap.tooltip()
37001 .placement('bottom')
37003 .title(iD.ui.tooltipHtml(t('save.no_changes'), key));
37005 var button = selection.append('button')
37006 .attr('class', 'save col12 disabled')
37007 .attr('tabindex', -1)
37011 button.append('span')
37012 .attr('class', 'label')
37013 .text(t('save.title'));
37015 button.append('span')
37016 .attr('class', 'count')
37019 var keybinding = d3.keybinding('undo-redo')
37020 .on(key, save, true);
37022 d3.select(document)
37025 var numChanges = 0;
37027 context.history().on('change.save', function() {
37028 var _ = history.difference().summary().length;
37029 if (_ === numChanges)
37033 tooltip.title(iD.ui.tooltipHtml(t(numChanges > 0 ?
37034 'save.help' : 'save.no_changes'), key));
37037 .classed('disabled', numChanges === 0)
37038 .classed('has-count', numChanges > 0);
37040 button.select('span.count')
37044 context.on('enter.save', function() {
37045 button.property('disabled', saving());
37046 if (saving()) button.call(tooltip.hide);
37050 iD.ui.Scale = function(context) {
37051 var projection = context.projection,
37055 function scaleDefs(loc1, loc2) {
37056 var lat = (loc2[1] + loc1[1]) / 2,
37057 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
37058 conversion = (imperial ? 3.28084 : 1),
37059 dist = iD.geo.lonToMeters(loc2[0] - loc1[0], lat) * conversion,
37060 scale = { dist: 0, px: 0, text: '' },
37061 buckets, i, val, dLon;
37064 buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
37066 buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
37069 // determine a user-friendly endpoint for the scale
37070 for (i = 0; i < buckets.length; i++) {
37073 scale.dist = Math.floor(dist / val) * val;
37078 dLon = iD.geo.metersToLon(scale.dist / conversion, lat);
37079 scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
37082 if (scale.dist >= 5280) {
37083 scale.dist /= 5280;
37084 scale.text = String(scale.dist) + ' mi';
37086 scale.text = String(scale.dist) + ' ft';
37089 if (scale.dist >= 1000) {
37090 scale.dist /= 1000;
37091 scale.text = String(scale.dist) + ' km';
37093 scale.text = String(scale.dist) + ' m';
37100 function update(selection) {
37101 // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
37102 var dims = context.map().dimensions(),
37103 loc1 = projection.invert([0, dims[1]]),
37104 loc2 = projection.invert([maxLength, dims[1]]),
37105 scale = scaleDefs(loc1, loc2);
37107 selection.select('#scalepath')
37108 .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
37110 selection.select('#scaletext')
37111 .attr('x', scale.px + 8)
37112 .attr('y', tickHeight)
37116 return function(selection) {
37117 var g = selection.append('svg')
37118 .attr('id', 'scale')
37120 .attr('transform', 'translate(10,11)');
37122 g.append('path').attr('id', 'scalepath');
37123 g.append('text').attr('id', 'scaletext');
37127 context.map().on('move.scale', function() {
37132 iD.ui.SelectionList = function(context, selectedIDs) {
37134 function selectEntity(entity) {
37135 context.enter(iD.modes.Select(context, [entity.id]).suppressMenu(true));
37139 function selectionList(selection) {
37140 selection.classed('selection-list-pane', true);
37142 var header = selection.append('div')
37143 .attr('class', 'header fillL cf');
37145 header.append('h3')
37146 .text(t('inspector.multiselect'));
37148 var listWrap = selection.append('div')
37149 .attr('class', 'inspector-body');
37151 var list = listWrap.append('div')
37152 .attr('class', 'feature-list cf');
37154 context.history().on('change.selection-list', drawList);
37157 function drawList() {
37158 var entities = selectedIDs
37159 .map(function(id) { return context.hasEntity(id); })
37160 .filter(function(entity) { return entity; });
37162 var items = list.selectAll('.feature-list-item')
37163 .data(entities, iD.Entity.key);
37165 var enter = items.enter().append('button')
37166 .attr('class', 'feature-list-item')
37167 .on('click', selectEntity);
37170 var label = enter.append('div')
37171 .attr('class', 'label')
37172 .call(iD.svg.Icon('', 'pre-text'));
37174 label.append('span')
37175 .attr('class', 'entity-type');
37177 label.append('span')
37178 .attr('class', 'entity-name');
37181 items.selectAll('use')
37182 .attr('href', function() {
37183 var entity = this.parentNode.parentNode.__data__;
37184 return '#icon-' + context.geometry(entity.id);
37187 items.selectAll('.entity-type')
37188 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
37190 items.selectAll('.entity-name')
37191 .text(function(entity) { return iD.util.displayName(entity); });
37199 return selectionList;
37202 iD.ui.Sidebar = function(context) {
37203 var inspector = iD.ui.Inspector(context),
37206 function sidebar(selection) {
37207 var featureListWrap = selection.append('div')
37208 .attr('class', 'feature-list-pane')
37209 .call(iD.ui.FeatureList(context));
37211 selection.call(iD.ui.Notice(context));
37213 var inspectorWrap = selection.append('div')
37214 .attr('class', 'inspector-hidden inspector-wrap fr');
37216 function hover(id) {
37217 if (!current && context.hasEntity(id)) {
37218 featureListWrap.classed('inspector-hidden', true);
37219 inspectorWrap.classed('inspector-hidden', false)
37220 .classed('inspector-hover', true);
37222 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
37227 inspectorWrap.call(inspector);
37229 } else if (!current) {
37230 featureListWrap.classed('inspector-hidden', false);
37231 inspectorWrap.classed('inspector-hidden', true);
37232 inspector.state('hide');
37236 sidebar.hover = _.throttle(hover, 200);
37238 sidebar.select = function(id, newFeature) {
37239 if (!current && id) {
37240 featureListWrap.classed('inspector-hidden', true);
37241 inspectorWrap.classed('inspector-hidden', false)
37242 .classed('inspector-hover', false);
37244 if (inspector.entityID() !== id || inspector.state() !== 'select') {
37248 .newFeature(newFeature);
37250 inspectorWrap.call(inspector);
37252 } else if (!current) {
37253 featureListWrap.classed('inspector-hidden', false);
37254 inspectorWrap.classed('inspector-hidden', true);
37255 inspector.state('hide');
37259 sidebar.show = function(component) {
37260 featureListWrap.classed('inspector-hidden', true);
37261 inspectorWrap.classed('inspector-hidden', true);
37262 if (current) current.remove();
37263 current = selection.append('div')
37264 .attr('class', 'sidebar-component')
37268 sidebar.hide = function() {
37269 featureListWrap.classed('inspector-hidden', false);
37270 inspectorWrap.classed('inspector-hidden', true);
37271 if (current) current.remove();
37276 sidebar.hover = function() {};
37277 sidebar.hover.cancel = function() {};
37278 sidebar.select = function() {};
37279 sidebar.show = function() {};
37280 sidebar.hide = function() {};
37284 iD.ui.SourceSwitch = function(context) {
37288 d3.event.preventDefault();
37290 if (context.history().hasChanges() &&
37291 !window.confirm(t('source_switch.lose_changes'))) return;
37293 var live = d3.select(this)
37296 context.connection()
37297 .switch(live ? keys[1] : keys[0]);
37299 context.enter(iD.modes.Browse(context));
37303 .text(live ? t('source_switch.dev') : t('source_switch.live'))
37304 .classed('live', !live);
37307 var sourceSwitch = function(selection) {
37308 selection.append('a')
37310 .text(t('source_switch.live'))
37311 .classed('live', true)
37312 .attr('tabindex', -1)
37313 .on('click', click);
37316 sourceSwitch.keys = function(_) {
37317 if (!arguments.length) return keys;
37319 return sourceSwitch;
37322 return sourceSwitch;
37324 iD.ui.Spinner = function(context) {
37325 var connection = context.connection();
37327 return function(selection) {
37328 var img = selection.append('img')
37329 .attr('src', context.imagePath('loader-black.gif'))
37330 .style('opacity', 0);
37332 connection.on('loading.spinner', function() {
37334 .style('opacity', 1);
37337 connection.on('loaded.spinner', function() {
37339 .style('opacity', 0);
37343 iD.ui.Splash = function(context) {
37344 return function(selection) {
37345 if (context.storage('sawSplash'))
37348 context.storage('sawSplash', true);
37350 var modal = iD.ui.modal(selection);
37352 modal.select('.modal')
37353 .attr('class', 'modal-splash modal col6');
37355 var introModal = modal.select('.content')
37357 .attr('class', 'fillL');
37359 introModal.append('div')
37360 .attr('class','modal-section cf')
37361 .append('h3').text(t('splash.welcome'));
37363 introModal.append('div')
37364 .attr('class','modal-section')
37366 .html(t('splash.text', {
37367 version: iD.version,
37368 website: '<a href="http://ideditor.com/">ideditor.com</a>',
37369 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
37372 var buttons = introModal.append('div').attr('class', 'modal-actions cf');
37374 buttons.append('button')
37375 .attr('class', 'col6 walkthrough')
37376 .text(t('splash.walkthrough'))
37377 .on('click', function() {
37378 d3.select(document.body).call(iD.ui.intro(context));
37382 buttons.append('button')
37383 .attr('class', 'col6 start')
37384 .text(t('splash.start'))
37385 .on('click', modal.close);
37387 modal.select('button.close').attr('class','hide');
37391 iD.ui.Status = function(context) {
37392 var connection = context.connection(),
37395 return function(selection) {
37397 function update() {
37399 connection.status(function(err, apiStatus) {
37401 selection.html('');
37403 if (err && errCount++ < 2) return;
37406 selection.text(t('status.error'));
37408 } else if (apiStatus === 'readonly') {
37409 selection.text(t('status.readonly'));
37411 } else if (apiStatus === 'offline') {
37412 selection.text(t('status.offline'));
37415 selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
37416 if (!err) errCount = 0;
37421 connection.on('auth', function() { update(selection); });
37422 window.setInterval(update, 90000);
37426 iD.ui.Success = function(context) {
37427 var dispatch = d3.dispatch('cancel'),
37430 function success(selection) {
37431 var message = (changeset.comment || t('success.edited_osm')).substring(0, 130) +
37432 ' ' + context.connection().changesetURL(changeset.id);
37434 var header = selection.append('div')
37435 .attr('class', 'header fillL');
37437 header.append('button')
37438 .attr('class', 'fr')
37439 .on('click', function() { dispatch.cancel(); })
37440 .call(iD.svg.Icon('#icon-close'));
37442 header.append('h3')
37443 .text(t('success.just_edited'));
37445 var body = selection.append('div')
37446 .attr('class', 'body save-success fillL');
37449 .html(t('success.help_html'));
37452 .attr('class', 'details')
37453 .attr('target', '_blank')
37454 .attr('tabindex', -1)
37455 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37456 .attr('href', t('success.help_link_url'))
37458 .text(t('success.help_link_text'));
37460 var changesetURL = context.connection().changesetURL(changeset.id);
37463 .attr('class', 'button col12 osm')
37464 .attr('target', '_blank')
37465 .attr('href', changesetURL)
37466 .text(t('success.view_on_osm'));
37469 facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
37470 twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
37471 google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
37474 body.selectAll('.button.social')
37475 .data(d3.entries(sharing))
37478 .attr('class', 'button social col4')
37479 .attr('target', '_blank')
37480 .attr('href', function(d) { return d.value; })
37481 .call(bootstrap.tooltip()
37482 .title(function(d) { return t('success.' + d.key); })
37483 .placement('bottom'))
37484 .each(function(d) { d3.select(this).call(iD.svg.Icon('#logo-' + d.key, 'social')); });
37487 success.changeset = function(_) {
37488 if (!arguments.length) return changeset;
37493 return d3.rebind(success, dispatch, 'on');
37495 iD.ui.TagReference = function(tag, context) {
37496 var tagReference = {},
37502 function findLocal(data) {
37503 var locale = iD.detect().locale.toLowerCase(),
37506 localized = _.find(data, function(d) {
37507 return d.lang.toLowerCase() === locale;
37509 if (localized) return localized;
37511 // try the non-regional version of a language, like
37512 // 'en' if the language is 'en-US'
37513 if (locale.indexOf('-') !== -1) {
37514 var first = locale.split('-')[0];
37515 localized = _.find(data, function(d) {
37516 return d.lang.toLowerCase() === first;
37518 if (localized) return localized;
37521 // finally fall back to english
37522 return _.find(data, function(d) {
37523 return d.lang.toLowerCase() === 'en';
37527 function load(param) {
37528 button.classed('tag-reference-loading', true);
37530 context.taginfo().docs(param, function show(err, data) {
37532 if (!err && data) {
37533 docs = findLocal(data);
37538 if (!docs || !docs.description) {
37539 if (param.hasOwnProperty('value')) {
37540 load(_.omit(param, 'value')); // retry with key only
37542 body.append('p').text(t('inspector.no_documentation_key'));
37548 if (docs.image && docs.image.thumb_url_prefix) {
37551 .attr('class', 'wiki-image')
37552 .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
37553 .on('load', function() { done(); })
37554 .on('error', function() { d3.select(this).remove(); done(); });
37561 .text(docs.description);
37565 .attr('target', '_blank')
37566 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
37567 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37569 .text(t('inspector.reference'));
37576 button.classed('tag-reference-loading', false);
37580 .style('max-height', '200px')
37581 .style('opacity', '1');
37586 function hide(selection) {
37587 selection = selection || body.transition().duration(200);
37590 .style('max-height', '0px')
37591 .style('opacity', '0');
37596 tagReference.button = function(selection) {
37597 button = selection.selectAll('.tag-reference-button')
37602 .attr('class', 'tag-reference-button')
37603 .attr('tabindex', -1)
37604 .call(iD.svg.Icon('#icon-inspect'));
37606 button.on('click', function () {
37607 d3.event.stopPropagation();
37608 d3.event.preventDefault();
37611 } else if (loaded) {
37614 if (context.taginfo()) {
37621 tagReference.body = function(selection) {
37622 body = selection.selectAll('.tag-reference-body')
37625 body.enter().append('div')
37626 .attr('class', 'tag-reference-body cf')
37627 .style('max-height', '0')
37628 .style('opacity', '0');
37630 if (showing === false) {
37635 tagReference.showing = function(_) {
37636 if (!arguments.length) return showing;
37638 return tagReference;
37641 return tagReference;
37643 // toggles the visibility of ui elements, using a combination of the
37644 // hide class, which sets display=none, and a d3 transition for opacity.
37645 // this will cause blinking when called repeatedly, so check that the
37646 // value actually changes between calls.
37647 iD.ui.Toggle = function(show, callback) {
37648 return function(selection) {
37650 .style('opacity', show ? 0 : 1)
37651 .classed('hide', false)
37653 .style('opacity', show ? 1 : 0)
37654 .each('end', function() {
37656 .classed('hide', !show)
37657 .style('opacity', null);
37658 if (callback) callback.apply(this);
37662 iD.ui.UndoRedo = function(context) {
37665 cmd: iD.ui.cmd('⌘Z'),
37666 action: function() { if (!(context.inIntro() || saving())) context.undo(); },
37667 annotation: function() { return context.history().undoAnnotation(); }
37670 cmd: iD.ui.cmd('⌘⇧Z'),
37671 action: function() {if (!(context.inIntro() || saving())) context.redo(); },
37672 annotation: function() { return context.history().redoAnnotation(); }
37675 function saving() {
37676 return context.mode().id === 'save';
37679 return function(selection) {
37680 var tooltip = bootstrap.tooltip()
37681 .placement('bottom')
37683 .title(function (d) {
37684 return iD.ui.tooltipHtml(d.annotation() ?
37685 t(d.id + '.tooltip', {action: d.annotation()}) :
37686 t(d.id + '.nothing'), d.cmd);
37689 var buttons = selection.selectAll('button')
37691 .enter().append('button')
37692 .attr('class', 'col6 disabled')
37693 .on('click', function(d) { return d.action(); })
37696 buttons.each(function(d) {
37698 .call(iD.svg.Icon('#icon-' + d.id));
37701 var keybinding = d3.keybinding('undo')
37702 .on(commands[0].cmd, function() { d3.event.preventDefault(); commands[0].action(); })
37703 .on(commands[1].cmd, function() { d3.event.preventDefault(); commands[1].action(); });
37705 d3.select(document)
37709 .on('change.undo_redo', update);
37712 .on('enter.undo_redo', update);
37714 function update() {
37716 .property('disabled', saving())
37717 .classed('disabled', function(d) { return !d.annotation(); })
37719 var selection = d3.select(this);
37720 if (selection.property('tooltipVisible')) {
37721 selection.call(tooltip.show);
37727 iD.ui.ViewOnOSM = function(context) {
37730 function viewOnOSM(selection) {
37731 var entity = context.entity(id);
37733 selection.style('display', entity.isNew() ? 'none' : null);
37735 var $link = selection.selectAll('.view-on-osm')
37740 .attr('class', 'view-on-osm')
37741 .attr('target', '_blank')
37742 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37744 .text(t('inspector.view_on_osm'));
37747 .attr('href', context.connection().entityURL(entity));
37750 viewOnOSM.entityID = function(_) {
37751 if (!arguments.length) return id;
37758 iD.ui.Zoom = function(context) {
37762 title: t('zoom.in'),
37763 action: context.zoomIn,
37768 title: t('zoom.out'),
37769 action: context.zoomOut,
37773 function zoomIn() {
37774 d3.event.preventDefault();
37775 if (!context.inIntro()) context.zoomIn();
37778 function zoomOut() {
37779 d3.event.preventDefault();
37780 if (!context.inIntro()) context.zoomOut();
37783 function zoomInFurther() {
37784 d3.event.preventDefault();
37785 if (!context.inIntro()) context.zoomInFurther();
37788 function zoomOutFurther() {
37789 d3.event.preventDefault();
37790 if (!context.inIntro()) context.zoomOutFurther();
37794 return function(selection) {
37795 var button = selection.selectAll('button')
37797 .enter().append('button')
37798 .attr('tabindex', -1)
37799 .attr('class', function(d) { return d.id; })
37800 .on('click.editor', function(d) { d.action(); })
37801 .call(bootstrap.tooltip()
37804 .title(function(d) {
37805 return iD.ui.tooltipHtml(d.title, d.key);
37808 button.each(function(d) {
37810 .call(iD.svg.Icon('#icon-' + d.icon, 'light'));
37813 var keybinding = d3.keybinding('zoom');
37815 _.each(['=','ffequals','plus','ffplus'], function(key) {
37816 keybinding.on(key, zoomIn);
37817 keybinding.on('⇧' + key, zoomIn);
37818 keybinding.on(iD.ui.cmd('⌘' + key), zoomInFurther);
37819 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomInFurther);
37821 _.each(['-','ffminus','_','dash'], function(key) {
37822 keybinding.on(key, zoomOut);
37823 keybinding.on('⇧' + key, zoomOut);
37824 keybinding.on(iD.ui.cmd('⌘' + key), zoomOutFurther);
37825 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomOutFurther);
37828 d3.select(document)
37832 iD.ui.preset.access = function(field) {
37833 var dispatch = d3.dispatch('change'),
37836 function access(selection) {
37837 var wrap = selection.selectAll('.preset-input-wrap')
37840 wrap.enter().append('div')
37841 .attr('class', 'cf preset-input-wrap')
37844 items = wrap.select('ul').selectAll('li')
37849 var enter = items.enter().append('li')
37850 .attr('class', function(d) { return 'cf preset-access-' + d; });
37852 enter.append('span')
37853 .attr('class', 'col6 label preset-label-access')
37854 .attr('for', function(d) { return 'preset-input-access-' + d; })
37855 .text(function(d) { return field.t('types.' + d); });
37857 enter.append('div')
37858 .attr('class', 'col6 preset-input-access-wrap')
37860 .attr('type', 'text')
37861 .attr('class', 'preset-input-access')
37862 .attr('id', function(d) { return 'preset-input-access-' + d; })
37863 .each(function(d) {
37865 .call(d3.combobox()
37866 .data(access.options(d)));
37871 wrap.selectAll('.preset-input-access')
37872 .on('change', change)
37873 .on('blur', change);
37876 function change(d) {
37878 tag[d] = d3.select(this).value() || undefined;
37879 dispatch.change(tag);
37882 access.options = function(type) {
37883 var options = ['no', 'permissive', 'private', 'destination'];
37885 if (type !== 'access') {
37886 options.unshift('yes');
37887 options.push('designated');
37889 if (type === 'bicycle') {
37890 options.push('dismount');
37894 return options.map(function(option) {
37896 title: field.t('options.' + option + '.description'),
37902 var placeholders = {
37904 foot: 'designated',
37905 motor_vehicle: 'no'
37909 motor_vehicle: 'no',
37915 motor_vehicle: 'no'
37918 motor_vehicle: 'no',
37919 bicycle: 'designated'
37922 motor_vehicle: 'no',
37923 horse: 'designated'
37927 motor_vehicle: 'no',
37933 motor_vehicle: 'yes',
37938 motor_vehicle: 'yes'
37942 motor_vehicle: 'yes',
37948 motor_vehicle: 'yes',
37954 motor_vehicle: 'yes',
37960 motor_vehicle: 'yes',
37966 motor_vehicle: 'yes',
37972 motor_vehicle: 'yes',
37978 motor_vehicle: 'yes',
37983 motor_vehicle: 'yes'
37987 motor_vehicle: 'yes',
37993 motor_vehicle: 'yes',
37999 motor_vehicle: 'yes',
38005 access.tags = function(tags) {
38006 items.selectAll('.preset-input-access')
38007 .value(function(d) { return tags[d] || ''; })
38008 .attr('placeholder', function() {
38009 return tags.access ? tags.access : field.placeholder();
38012 // items.selectAll('#preset-input-access-access')
38013 // .attr('placeholder', 'yes');
38015 _.forEach(placeholders[tags.highway], function(v, k) {
38016 items.selectAll('#preset-input-access-' + k)
38017 .attr('placeholder', function() { return (tags.access || v); });
38021 access.focus = function() {
38022 items.selectAll('.preset-input-access')
38026 return d3.rebind(access, dispatch, 'on');
38028 iD.ui.preset.address = function(field, context) {
38029 var dispatch = d3.dispatch('init', 'change'),
38042 function getStreets() {
38043 var extent = entity.extent(context.graph()),
38044 l = extent.center(),
38045 box = iD.geo.Extent(l).padByMeters(200);
38047 return context.intersects(box)
38048 .filter(isAddressable)
38050 var loc = context.projection([
38051 (extent[0][0] + extent[1][0]) / 2,
38052 (extent[0][1] + extent[1][1]) / 2]),
38053 choice = iD.geo.chooseEdge(context.childNodes(d), loc, context.projection);
38055 title: d.tags.name,
38056 value: d.tags.name,
38057 dist: choice.distance
38059 }).sort(function(a, b) {
38060 return a.dist - b.dist;
38063 function isAddressable(d) {
38064 return d.tags.highway && d.tags.name && d.type === 'way';
38068 function getCities() {
38069 var extent = entity.extent(context.graph()),
38070 l = extent.center(),
38071 box = iD.geo.Extent(l).padByMeters(200);
38073 return context.intersects(box)
38074 .filter(isAddressable)
38077 title: d.tags['addr:city'] || d.tags.name,
38078 value: d.tags['addr:city'] || d.tags.name,
38079 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
38081 }).sort(function(a, b) {
38082 return a.dist - b.dist;
38085 function isAddressable(d) {
38087 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
38090 if (d.tags.place && d.tags.name && (
38091 d.tags.place === 'city' ||
38092 d.tags.place === 'town' ||
38093 d.tags.place === 'village'))
38096 if (d.tags['addr:city']) return true;
38102 function getPostCodes() {
38103 var extent = entity.extent(context.graph()),
38104 l = extent.center(),
38105 box = iD.geo.Extent(l).padByMeters(200);
38107 return context.intersects(box)
38108 .filter(isAddressable)
38111 title: d.tags['addr:postcode'],
38112 value: d.tags['addr:postcode'],
38113 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
38115 }).sort(function(a, b) {
38116 return a.dist - b.dist;
38119 function isAddressable(d) {
38120 return d.tags['addr:postcode'];
38124 function address(selection) {
38125 isInitialized = false;
38127 wrap = selection.selectAll('.preset-input-wrap')
38134 .attr('class', 'preset-input-wrap');
38136 var center = entity.extent(context.graph()).center(),
38139 iD.services.nominatim().countryCode(center, function (err, countryCode) {
38140 addressFormat = _.find(iD.data.addressFormats, function (a) {
38141 return a && a.countryCodes && _.contains(a.countryCodes, countryCode);
38142 }) || _.first(iD.data.addressFormats);
38145 // Normalize widths.
38146 var total = _.reduce(r, function(sum, field) {
38147 return sum + (widths[field] || 0.5);
38150 return r.map(function (field) {
38153 width: (widths[field] || 0.5) / total
38158 wrap.selectAll('div')
38159 .data(addressFormat.format)
38162 .attr('class', 'addr-row')
38163 .selectAll('input')
38167 .property('type', 'text')
38168 .attr('placeholder', function (d) { return field.t('placeholders.' + d.id); })
38169 .attr('class', function (d) { return 'addr-' + d.id; })
38170 .style('width', function (d) { return d.width * 100 + '%'; });
38174 wrap.selectAll('.addr-street')
38175 .call(d3.combobox()
38176 .fetcher(function(value, callback) {
38177 callback(getStreets());
38180 wrap.selectAll('.addr-city')
38181 .call(d3.combobox()
38182 .fetcher(function(value, callback) {
38183 callback(getCities());
38186 wrap.selectAll('.addr-postcode')
38187 .call(d3.combobox()
38188 .fetcher(function(value, callback) {
38189 callback(getPostCodes());
38192 wrap.selectAll('input')
38193 .on('blur', change())
38194 .on('change', change());
38196 wrap.selectAll('input:not(.combobox-input)')
38197 .on('input', change(true));
38200 isInitialized = true;
38204 function change(onInput) {
38205 return function() {
38208 wrap.selectAll('input')
38209 .each(function (field) {
38210 tags['addr:' + field.id] = this.value || undefined;
38213 dispatch.change(tags, onInput);
38217 function updateTags(tags) {
38218 wrap.selectAll('input')
38219 .value(function (field) {
38220 return tags['addr:' + field.id] || '';
38224 address.entity = function(_) {
38225 if (!arguments.length) return entity;
38230 address.tags = function(tags) {
38231 if (isInitialized) {
38234 dispatch.on('init', function () {
38240 address.focus = function() {
38241 var node = wrap.selectAll('input').node();
38242 if (node) node.focus();
38245 return d3.rebind(address, dispatch, 'on');
38247 iD.ui.preset.check =
38248 iD.ui.preset.defaultcheck = function(field) {
38249 var dispatch = d3.dispatch('change'),
38250 options = field.strings && field.strings.options,
38253 entity, value, box, text, label;
38256 for (var k in options) {
38257 values.push(k === 'undefined' ? undefined : k);
38258 texts.push(field.t('options.' + k, { 'default': options[k] }));
38261 values = [undefined, 'yes'];
38262 texts = [t('inspector.unknown'), t('inspector.check.yes')];
38263 if (field.type === 'check') {
38265 texts.push(t('inspector.check.no'));
38269 var check = function(selection) {
38270 // hack: pretend oneway field is a oneway_yes field
38271 // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
38272 if (field.id === 'oneway') {
38273 for (var key in entity.tags) {
38274 if (key in iD.oneWayTags && (entity.tags[key] in iD.oneWayTags[key])) {
38275 texts[0] = t('presets.fields.oneway_yes.options.undefined');
38281 selection.classed('checkselect', 'true');
38283 label = selection.selectAll('.preset-input-wrap')
38286 var enter = label.enter().append('label')
38287 .attr('class', 'preset-input-wrap');
38289 enter.append('input')
38290 .property('indeterminate', field.type === 'check')
38291 .attr('type', 'checkbox')
38292 .attr('id', 'preset-input-' + field.id);
38294 enter.append('span')
38296 .attr('class', 'value');
38298 box = label.select('input')
38299 .on('click', function() {
38301 t[field.key] = values[(values.indexOf(value) + 1) % values.length];
38302 dispatch.change(t);
38303 d3.event.stopPropagation();
38306 text = label.select('span.value');
38309 check.entity = function(_) {
38310 if (!arguments.length) return entity;
38315 check.tags = function(tags) {
38316 value = tags[field.key];
38317 box.property('indeterminate', field.type === 'check' && !value);
38318 box.property('checked', value === 'yes');
38319 text.text(texts[values.indexOf(value)]);
38320 label.classed('set', !!value);
38323 check.focus = function() {
38324 box.node().focus();
38327 return d3.rebind(check, dispatch, 'on');
38329 iD.ui.preset.combo =
38330 iD.ui.preset.typeCombo = function(field, context) {
38331 var dispatch = d3.dispatch('change'),
38332 optstrings = field.strings && field.strings.options,
38333 optarray = field.options,
38334 snake_case = (field.snake_case || (field.snake_case === undefined)),
38338 function snake(s) {
38339 return s.replace(/\s+/g, '_');
38342 function unsnake(s) {
38343 return s.replace(/_+/g, ' ');
38346 function clean(s) {
38347 return s.split(';')
38348 .map(function(s) { return s.trim(); })
38352 function optString() {
38353 return _.find(_.keys(strings), function(k) {
38354 return strings[k] === input.value();
38358 function combo(selection) {
38359 var combobox = d3.combobox();
38361 input = selection.selectAll('input')
38364 var enter = input.enter()
38366 .attr('type', 'text')
38367 .attr('id', 'preset-input-' + field.id);
38369 if (optstrings) { enter.attr('readonly', 'readonly'); }
38373 .on('change', change)
38374 .on('blur', change)
38377 _.each(optstrings, function(v, k) {
38378 strings[k] = field.t('options.' + k, { 'default': v });
38381 } else if (optarray) {
38382 _.each(optarray, function(k) {
38383 strings[k] = (snake_case ? unsnake(k) : k);
38386 } else if (context.taginfo()) {
38387 context.taginfo().values({key: field.key}, function(err, data) {
38389 _.each(_.pluck(data, 'value'), function(k) {
38390 strings[k] = (snake_case ? unsnake(k) : k);
38398 function stringsLoaded() {
38399 var keys = _.keys(strings),
38403 combobox.data(keys.map(function(k) {
38404 var s = strings[k],
38406 o.title = o.value = s;
38407 if (s.length < 20) { strs.push(s); }
38411 placeholders = strs.length > 1 ? strs : keys;
38412 input.attr('placeholder', field.placeholder() ||
38413 (placeholders.slice(0, 3).join(', ') + '...'));
38417 function change() {
38418 var value = optString() || clean(input.value());
38421 value = snake(value);
38423 if (field.type === 'typeCombo' && !value) {
38428 t[field.key] = value || undefined;
38429 dispatch.change(t);
38432 combo.tags = function(tags) {
38433 var key = tags[field.key],
38434 optstring = optString(),
38435 value = strings[key] || key || '';
38437 if (field.type === 'typeCombo' && value.toLowerCase() === 'yes') {
38440 if (!optstring && snake_case) {
38441 value = unsnake(value);
38443 input.value(value);
38446 combo.focus = function() {
38447 input.node().focus();
38450 return d3.rebind(combo, dispatch, 'on');
38452 iD.ui.preset.cycleway = function(field) {
38453 var dispatch = d3.dispatch('change'),
38456 function cycleway(selection) {
38457 var wrap = selection.selectAll('.preset-input-wrap')
38460 wrap.enter().append('div')
38461 .attr('class', 'cf preset-input-wrap')
38464 items = wrap.select('ul').selectAll('li')
38469 var enter = items.enter().append('li')
38470 .attr('class', function(d) { return 'cf preset-cycleway-' + d; });
38472 enter.append('span')
38473 .attr('class', 'col6 label preset-label-cycleway')
38474 .attr('for', function(d) { return 'preset-input-cycleway-' + d; })
38475 .text(function(d) { return field.t('types.' + d); });
38477 enter.append('div')
38478 .attr('class', 'col6 preset-input-cycleway-wrap')
38480 .attr('type', 'text')
38481 .attr('class', 'preset-input-cycleway')
38482 .attr('id', function(d) { return 'preset-input-cycleway-' + d; })
38483 .each(function(d) {
38485 .call(d3.combobox()
38486 .data(cycleway.options(d)));
38491 wrap.selectAll('.preset-input-cycleway')
38492 .on('change', change)
38493 .on('blur', change);
38496 function change() {
38497 var inputs = d3.selectAll('.preset-input-cycleway')[0],
38498 left = d3.select(inputs[0]).value(),
38499 right = d3.select(inputs[1]).value(),
38501 if (left === 'none' || left === '') { left = undefined; }
38502 if (right === 'none' || right === '') { right = undefined; }
38504 // Always set both left and right as changing one can affect the other
38506 cycleway: undefined,
38507 'cycleway:left': left,
38508 'cycleway:right': right
38511 // If the left and right tags match, use the cycleway tag to tag both
38512 // sides the same way
38513 if (left === right) {
38516 'cycleway:left': undefined,
38517 'cycleway:right': undefined
38521 dispatch.change(tag);
38524 cycleway.options = function() {
38525 return d3.keys(field.strings.options).map(function(option) {
38527 title: field.t('options.' + option + '.description'),
38533 cycleway.tags = function(tags) {
38534 items.selectAll('.preset-input-cycleway')
38535 .value(function(d) {
38536 // If cycleway is set, always return that
38537 if (tags.cycleway) {
38538 return tags.cycleway;
38540 return tags[d] || '';
38542 .attr('placeholder', field.placeholder());
38545 cycleway.focus = function() {
38546 items.selectAll('.preset-input-cycleway')
38550 return d3.rebind(cycleway, dispatch, 'on');
38552 iD.ui.preset.text =
38553 iD.ui.preset.number =
38555 iD.ui.preset.email =
38556 iD.ui.preset.url = function(field) {
38558 var dispatch = d3.dispatch('change'),
38561 function i(selection) {
38562 input = selection.selectAll('input')
38565 input.enter().append('input')
38566 .attr('type', field.type)
38567 .attr('id', 'preset-input-' + field.id)
38568 .attr('placeholder', field.placeholder() || t('inspector.unknown'));
38571 .on('input', change(true))
38572 .on('blur', change())
38573 .on('change', change());
38575 if (field.type === 'number') {
38576 input.attr('type', 'text');
38578 var spinControl = selection.selectAll('.spin-control')
38581 var enter = spinControl.enter().append('div')
38582 .attr('class', 'spin-control');
38584 enter.append('button')
38586 .attr('class', 'increment');
38588 enter.append('button')
38590 .attr('class', 'decrement');
38592 spinControl.selectAll('button')
38593 .on('click', function(d) {
38594 d3.event.preventDefault();
38595 var num = parseInt(input.node().value || 0, 10);
38596 if (!isNaN(num)) input.node().value = num + d;
38602 function change(onInput) {
38603 return function() {
38605 t[field.key] = input.value() || undefined;
38606 dispatch.change(t, onInput);
38610 i.tags = function(tags) {
38611 input.value(tags[field.key] || '');
38614 i.focus = function() {
38615 input.node().focus();
38618 return d3.rebind(i, dispatch, 'on');
38620 iD.ui.preset.localized = function(field, context) {
38621 var dispatch = d3.dispatch('change', 'input'),
38622 wikipedia = iD.services.wikipedia(),
38623 input, localizedInputs, wikiTitles,
38626 function i(selection) {
38627 input = selection.selectAll('.localized-main')
38630 input.enter().append('input')
38631 .attr('type', 'text')
38632 .attr('id', 'preset-input-' + field.id)
38633 .attr('class', 'localized-main')
38634 .attr('placeholder', field.placeholder());
38636 if (field.id === 'name') {
38637 var preset = context.presets().match(entity, context.graph());
38638 input.call(d3.combobox().fetcher(
38639 iD.util.SuggestNames(preset, iD.data.suggestions)
38644 .on('input', change(true))
38645 .on('blur', change())
38646 .on('change', change());
38648 var translateButton = selection.selectAll('.localized-add')
38651 translateButton.enter()
38653 .attr('class', 'button-input-action localized-add minor')
38654 .call(iD.svg.Icon('#icon-plus'))
38655 .call(bootstrap.tooltip()
38656 .title(t('translate.translate'))
38657 .placement('left'));
38660 .on('click', addNew);
38662 localizedInputs = selection.selectAll('.localized-wrap')
38665 localizedInputs.enter().append('div')
38666 .attr('class', 'localized-wrap');
38669 function addNew() {
38670 d3.event.preventDefault();
38671 var data = localizedInputs.selectAll('div.entry').data();
38672 var defaultLang = iD.detect().locale.toLowerCase().split('-')[0];
38673 var langExists = _.find(data, function(datum) { return datum.lang === defaultLang;});
38674 var isLangEn = defaultLang.indexOf('en') > -1;
38675 if (isLangEn || langExists) {
38678 data.push({ lang: defaultLang, value: '' });
38679 localizedInputs.call(render, data);
38682 function change(onInput) {
38683 return function() {
38685 t[field.key] = d3.select(this).value() || undefined;
38686 dispatch.change(t, onInput);
38690 function key(lang) { return field.key + ':' + lang; }
38692 function changeLang(d) {
38693 var lang = d3.select(this).value(),
38695 language = _.find(iD.data.wikipedia, function(d) {
38696 return d[0].toLowerCase() === lang.toLowerCase() ||
38697 d[1].toLowerCase() === lang.toLowerCase();
38700 if (language) lang = language[2];
38702 if (d.lang && d.lang !== lang) {
38703 t[key(d.lang)] = undefined;
38706 var value = d3.select(this.parentNode)
38707 .selectAll('.localized-value')
38710 if (lang && value) {
38711 t[key(lang)] = value;
38712 } else if (lang && wikiTitles && wikiTitles[d.lang]) {
38713 t[key(lang)] = wikiTitles[d.lang];
38717 dispatch.change(t);
38720 function changeValue(d) {
38721 if (!d.lang) return;
38723 t[key(d.lang)] = d3.select(this).value() || undefined;
38724 dispatch.change(t);
38727 function fetcher(value, cb) {
38728 var v = value.toLowerCase();
38730 cb(iD.data.wikipedia.filter(function(d) {
38731 return d[0].toLowerCase().indexOf(v) >= 0 ||
38732 d[1].toLowerCase().indexOf(v) >= 0 ||
38733 d[2].toLowerCase().indexOf(v) >= 0;
38734 }).map(function(d) {
38735 return { value: d[1] };
38739 function render(selection, data) {
38740 var wraps = selection.selectAll('div.entry').
38741 data(data, function(d) { return d.lang; });
38743 var innerWrap = wraps.enter()
38744 .insert('div', ':first-child');
38746 innerWrap.attr('class', 'entry')
38748 var wrap = d3.select(this);
38749 var langcombo = d3.combobox().fetcher(fetcher);
38751 var label = wrap.append('label')
38752 .attr('class','form-label')
38753 .text(t('translate.localized_translation_label'))
38754 .attr('for','localized-lang');
38756 label.append('button')
38757 .attr('class', 'minor remove')
38758 .on('click', function(d){
38759 d3.event.preventDefault();
38761 t[key(d.lang)] = undefined;
38762 dispatch.change(t);
38763 d3.select(this.parentNode.parentNode)
38765 .style('max-height','240px')
38767 .style('opacity', '0')
38768 .style('max-height','0px')
38771 .call(iD.svg.Icon('#operation-delete'));
38773 wrap.append('input')
38774 .attr('class', 'localized-lang')
38775 .attr('type', 'text')
38776 .attr('placeholder',t('translate.localized_translation_language'))
38777 .on('blur', changeLang)
38778 .on('change', changeLang)
38781 wrap.append('input')
38782 .on('blur', changeValue)
38783 .on('change', changeValue)
38784 .attr('type', 'text')
38785 .attr('placeholder', t('translate.localized_translation_name'))
38786 .attr('class', 'localized-value');
38790 .style('margin-top', '0px')
38791 .style('max-height', '0px')
38792 .style('opacity', '0')
38795 .style('margin-top', '10px')
38796 .style('max-height', '240px')
38797 .style('opacity', '1')
38798 .each('end', function() {
38800 .style('max-height', '')
38801 .style('overflow', 'visible');
38807 .style('max-height','0px')
38808 .style('opacity', '0')
38809 .style('top','-10px')
38812 var entry = selection.selectAll('.entry');
38814 entry.select('.localized-lang')
38815 .value(function(d) {
38816 var lang = _.find(iD.data.wikipedia, function(lang) { return lang[2] === d.lang; });
38817 return lang ? lang[1] : d.lang;
38820 entry.select('.localized-value')
38821 .value(function(d) { return d.value; });
38824 i.tags = function(tags) {
38825 // Fetch translations from wikipedia
38826 if (tags.wikipedia && !wikiTitles) {
38828 var wm = tags.wikipedia.match(/([^:]+):(.+)/);
38829 if (wm && wm[0] && wm[1]) {
38830 wikipedia.translations(wm[1], wm[2], function(d) {
38836 input.value(tags[field.key] || '');
38838 var postfixed = [], k, m;
38840 m = k.match(/^(.*):([a-zA-Z_-]+)$/);
38841 if (m && m[1] === field.key && m[2]) {
38842 postfixed.push({ lang: m[2], value: tags[k] });
38846 localizedInputs.call(render, postfixed.reverse());
38849 i.focus = function() {
38850 input.node().focus();
38853 i.entity = function(_) {
38857 return d3.rebind(i, dispatch, 'on');
38859 iD.ui.preset.maxspeed = function(field, context) {
38860 var dispatch = d3.dispatch('change'),
38867 var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
38868 imperialValues = [20, 25, 30, 35, 40, 45, 50, 55, 65, 70];
38870 function maxspeed(selection) {
38871 combobox = d3.combobox();
38872 var unitCombobox = d3.combobox().data(['km/h', 'mph'].map(comboValues));
38874 input = selection.selectAll('#preset-input-' + field.id)
38877 input.enter().append('input')
38878 .attr('type', 'text')
38879 .attr('id', 'preset-input-' + field.id)
38880 .attr('placeholder', field.placeholder());
38884 .on('change', change)
38885 .on('blur', change);
38887 var childNodes = context.graph().childNodes(context.entity(entity.id)),
38888 loc = childNodes[~~(childNodes.length/2)].loc;
38890 imperial = _.any(iD.data.imperial.features, function(f) {
38891 return _.any(f.geometry.coordinates, function(d) {
38892 return iD.geo.pointInPolygon(loc, d[0]);
38896 unitInput = selection.selectAll('input.maxspeed-unit')
38899 unitInput.enter().append('input')
38900 .attr('type', 'text')
38901 .attr('class', 'maxspeed-unit');
38904 .on('blur', changeUnits)
38905 .on('change', changeUnits)
38906 .call(unitCombobox);
38908 function changeUnits() {
38909 imperial = unitInput.value() === 'mph';
38910 unitInput.value(imperial ? 'mph' : 'km/h');
38917 function setSuggestions() {
38918 combobox.data((imperial ? imperialValues : metricValues).map(comboValues));
38919 unitInput.value(imperial ? 'mph' : 'km/h');
38922 function comboValues(d) {
38924 value: d.toString(),
38925 title: d.toString()
38929 function change() {
38931 value = input.value();
38934 tag[field.key] = undefined;
38935 } else if (isNaN(value) || !imperial) {
38936 tag[field.key] = value;
38938 tag[field.key] = value + ' mph';
38941 dispatch.change(tag);
38944 maxspeed.tags = function(tags) {
38945 var value = tags[field.key];
38947 if (value && value.indexOf('mph') >= 0) {
38948 value = parseInt(value, 10);
38950 } else if (value) {
38956 input.value(value || '');
38959 maxspeed.focus = function() {
38960 input.node().focus();
38963 maxspeed.entity = function(_) {
38967 return d3.rebind(maxspeed, dispatch, 'on');
38969 iD.ui.preset.radio = function(field) {
38970 var dispatch = d3.dispatch('change'),
38971 labels, radios, placeholder;
38973 function radio(selection) {
38974 selection.classed('preset-radio', true);
38976 var wrap = selection.selectAll('.preset-input-wrap')
38979 var buttonWrap = wrap.enter().append('div')
38980 .attr('class', 'preset-input-wrap toggle-list');
38982 buttonWrap.append('span')
38983 .attr('class', 'placeholder');
38985 placeholder = selection.selectAll('.placeholder');
38987 labels = wrap.selectAll('label')
38988 .data(field.options || field.keys);
38990 var enter = labels.enter().append('label');
38992 enter.append('input')
38993 .attr('type', 'radio')
38994 .attr('name', field.id)
38995 .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
38996 .attr('checked', false);
38998 enter.append('span')
38999 .text(function(d) { return field.t('options.' + d, { 'default': d }); });
39001 radios = labels.selectAll('input')
39002 .on('change', change);
39005 function change() {
39007 if (field.key) t[field.key] = undefined;
39008 radios.each(function(d) {
39009 var active = d3.select(this).property('checked');
39011 if (active) t[field.key] = d;
39013 t[d] = active ? 'yes' : undefined;
39016 dispatch.change(t);
39019 radio.tags = function(tags) {
39020 function checked(d) {
39022 return tags[field.key] === d;
39024 return !!(tags[d] && tags[d] !== 'no');
39028 labels.classed('active', checked);
39029 radios.property('checked', checked);
39030 var selection = radios.filter(function() { return this.checked; });
39031 if (selection.empty()) {
39032 placeholder.text(t('inspector.none'));
39034 placeholder.text(selection.attr('value'));
39038 radio.focus = function() {
39039 radios.node().focus();
39042 return d3.rebind(radio, dispatch, 'on');
39044 iD.ui.preset.restrictions = function(field, context) {
39045 var dispatch = d3.dispatch('change'),
39046 hover = iD.behavior.Hover(context),
39051 function restrictions(selection) {
39052 // if form field is hidden or has detached from dom, clean up.
39053 if (!d3.select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
39054 selection.call(restrictions.off);
39058 var wrap = selection.selectAll('.preset-input-wrap')
39061 var enter = wrap.enter()
39063 .attr('class', 'preset-input-wrap');
39067 .attr('class', 'restriction-help');
39070 var intersection = iD.geo.Intersection(context.graph(), vertexID),
39071 graph = intersection.graph,
39072 vertex = graph.entity(vertexID),
39073 filter = d3.functor(true),
39074 extent = iD.geo.Extent(),
39075 projection = iD.geo.RawMercator();
39077 var d = wrap.dimensions(),
39078 c = [d[0] / 2, d[1] / 2],
39082 .scale(256 * Math.pow(2, z) / (2 * Math.PI));
39084 var s = projection(vertex.loc);
39087 .translate([c[0] - s[0], c[1] - s[1]])
39088 .clipExtent([[0, 0], d]);
39090 var drawLayers = iD.svg.Layers(projection, context).only('osm').dimensions(d),
39091 drawVertices = iD.svg.Vertices(projection, context),
39092 drawLines = iD.svg.Lines(projection, context),
39093 drawTurns = iD.svg.Turns(projection, context);
39097 .selectAll('.surface')
39101 var surface = wrap.selectAll('.surface');
39105 .call(drawVertices, graph, [vertex], filter, extent, z)
39106 .call(drawLines, graph, intersection.ways, filter)
39107 .call(drawTurns, graph, intersection.turns(fromNodeID));
39110 .on('click.restrictions', click)
39111 .on('mouseover.restrictions', mouseover)
39112 .on('mouseout.restrictions', mouseout);
39115 .selectAll('.selected')
39116 .classed('selected', false);
39120 .selectAll('.' + intersection.highways[fromNodeID].id)
39121 .classed('selected', true);
39127 .on('change.restrictions', render);
39130 .on('resize.restrictions', function() {
39131 wrap.dimensions(null);
39136 var datum = d3.event.target.__data__;
39137 if (datum instanceof iD.Entity) {
39138 fromNodeID = intersection.adjacentNodeId(datum.id);
39140 } else if (datum instanceof iD.geo.Turn) {
39141 if (datum.restriction) {
39143 iD.actions.UnrestrictTurn(datum, projection),
39144 t('operations.restriction.annotation.delete'));
39147 iD.actions.RestrictTurn(datum, projection),
39148 t('operations.restriction.annotation.create'));
39153 function mouseover() {
39154 var datum = d3.event.target.__data__;
39155 if (datum instanceof iD.geo.Turn) {
39156 var graph = context.graph(),
39157 presets = context.presets(),
39160 if (datum.restriction) {
39161 preset = presets.match(graph.entity(datum.restriction), graph);
39163 preset = presets.item('type/restriction/' +
39164 iD.geo.inferRestriction(
39172 wrap.selectAll('.restriction-help')
39173 .text(t('operations.restriction.help.' +
39174 (datum.restriction ? 'toggle_off' : 'toggle_on'),
39175 {restriction: preset.name()}));
39179 function mouseout() {
39180 wrap.selectAll('.restriction-help')
39181 .text(t('operations.restriction.help.' +
39182 (fromNodeID ? 'toggle' : 'select')));
39185 function render() {
39186 if (context.hasEntity(vertexID)) {
39187 restrictions(selection);
39192 restrictions.entity = function(_) {
39193 if (!vertexID || vertexID !== _.id) {
39199 restrictions.tags = function() {};
39200 restrictions.focus = function() {};
39202 restrictions.off = function(selection) {
39203 selection.selectAll('.surface')
39205 .on('click.restrictions', null)
39206 .on('mouseover.restrictions', null)
39207 .on('mouseout.restrictions', null);
39210 .on('change.restrictions', null);
39213 .on('resize.restrictions', null);
39216 return d3.rebind(restrictions, dispatch, 'on');
39218 iD.ui.preset.textarea = function(field) {
39219 var dispatch = d3.dispatch('change'),
39222 function i(selection) {
39223 input = selection.selectAll('textarea')
39226 input.enter().append('textarea')
39227 .attr('id', 'preset-input-' + field.id)
39228 .attr('placeholder', field.placeholder() || t('inspector.unknown'))
39229 .attr('maxlength', 255);
39232 .on('input', change(true))
39233 .on('blur', change())
39234 .on('change', change());
39237 function change(onInput) {
39238 return function() {
39240 t[field.key] = input.value() || undefined;
39241 dispatch.change(t, onInput);
39245 i.tags = function(tags) {
39246 input.value(tags[field.key] || '');
39249 i.focus = function() {
39250 input.node().focus();
39253 return d3.rebind(i, dispatch, 'on');
39255 iD.ui.preset.wikipedia = function(field, context) {
39256 var dispatch = d3.dispatch('change'),
39257 wikipedia = iD.services.wikipedia(),
39258 link, entity, lang, title;
39260 function i(selection) {
39261 var langcombo = d3.combobox()
39262 .fetcher(function(value, cb) {
39263 var v = value.toLowerCase();
39265 cb(iD.data.wikipedia.filter(function(d) {
39266 return d[0].toLowerCase().indexOf(v) >= 0 ||
39267 d[1].toLowerCase().indexOf(v) >= 0 ||
39268 d[2].toLowerCase().indexOf(v) >= 0;
39269 }).map(function(d) {
39270 return { value: d[1] };
39274 var titlecombo = d3.combobox()
39275 .fetcher(function(value, cb) {
39277 if (!value) value = context.entity(entity.id).tags.name || '';
39278 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
39280 searchfn(language()[2], value, function(query, data) {
39281 cb(data.map(function(d) {
39282 return { value: d };
39287 lang = selection.selectAll('input.wiki-lang')
39290 lang.enter().append('input')
39291 .attr('type', 'text')
39292 .attr('class', 'wiki-lang')
39297 .on('blur', changeLang)
39298 .on('change', changeLang);
39300 title = selection.selectAll('input.wiki-title')
39303 title.enter().append('input')
39304 .attr('type', 'text')
39305 .attr('class', 'wiki-title')
39306 .attr('id', 'preset-input-' + field.id);
39310 .on('blur', change)
39311 .on('change', change);
39313 link = selection.selectAll('a.wiki-link')
39316 link.enter().append('a')
39317 .attr('class', 'wiki-link button-input-action minor')
39318 .attr('target', '_blank')
39319 .call(iD.svg.Icon('#icon-out-link', 'inline'));
39322 function language() {
39323 var value = lang.value().toLowerCase();
39324 var locale = iD.detect().locale.toLowerCase();
39325 var localeLanguage;
39326 return _.find(iD.data.wikipedia, function(d) {
39327 if (d[2] === locale) localeLanguage = d;
39328 return d[0].toLowerCase() === value ||
39329 d[1].toLowerCase() === value ||
39331 }) || localeLanguage || ['English', 'English', 'en'];
39334 function changeLang() {
39335 lang.value(language()[1]);
39339 function change() {
39340 var value = title.value(),
39341 m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
39342 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
39346 // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
39347 value = decodeURIComponent(m[2]).replace(/_/g, ' ');
39350 // Best-effort `anchordecode:` implementation
39351 anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
39353 anchor = decodeURIComponent(m[3]);
39355 value += '#' + anchor.replace(/_/g, ' ');
39357 value = value.slice(0, 1).toUpperCase() + value.slice(1);
39359 title.value(value);
39363 t[field.key] = value ? language()[2] + ':' + value : undefined;
39364 dispatch.change(t);
39367 i.tags = function(tags) {
39368 var value = tags[field.key] || '',
39369 m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
39370 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
39371 anchor = m && m[3];
39373 // value in correct format
39376 title.value(m[2] + (anchor ? ('#' + anchor) : ''));
39379 // Best-effort `anchorencode:` implementation
39380 anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
39382 anchor = anchor.replace(/ /g, '_');
39385 link.attr('href', 'https://' + m[1] + '.wikipedia.org/wiki/' +
39386 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : ''));
39388 // unrecognized value format
39390 title.value(value);
39391 link.attr('href', 'https://en.wikipedia.org/wiki/Special:Search?search=' + value);
39395 i.entity = function(_) {
39399 i.focus = function() {
39400 title.node().focus();
39403 return d3.rebind(i, dispatch, 'on');
39405 iD.ui.intro.area = function(context, reveal) {
39406 var event = d3.dispatch('done'),
39410 title: 'intro.areas.title'
39413 step.enter = function() {
39414 var playground = [-85.63552, 41.94159],
39415 corner = [-85.63565411045074, 41.9417715536927];
39416 context.map().centerZoom(playground, 19);
39417 reveal('button.add-area',
39418 t('intro.areas.add', { button: iD.ui.intro.icon('#icon-area', 'pre-text') }),
39419 { tooltipClass: 'intro-areas-add' });
39421 context.on('enter.intro', addArea);
39423 function addArea(mode) {
39424 if (mode.id !== 'add-area') return;
39425 context.on('enter.intro', drawArea);
39427 var padding = 120 * Math.pow(2, context.map().zoom() - 19);
39428 var pointBox = iD.ui.intro.pad(corner, padding, context);
39429 reveal(pointBox, t('intro.areas.corner'));
39431 context.map().on('move.intro', function() {
39432 padding = 120 * Math.pow(2, context.map().zoom() - 19);
39433 pointBox = iD.ui.intro.pad(corner, padding, context);
39434 reveal(pointBox, t('intro.areas.corner'), {duration: 0});
39438 function drawArea(mode) {
39439 if (mode.id !== 'draw-area') return;
39440 context.on('enter.intro', enterSelect);
39442 var padding = 150 * Math.pow(2, context.map().zoom() - 19);
39443 var pointBox = iD.ui.intro.pad(playground, padding, context);
39444 reveal(pointBox, t('intro.areas.place'));
39446 context.map().on('move.intro', function() {
39447 padding = 150 * Math.pow(2, context.map().zoom() - 19);
39448 pointBox = iD.ui.intro.pad(playground, padding, context);
39449 reveal(pointBox, t('intro.areas.place'), {duration: 0});
39453 function enterSelect(mode) {
39454 if (mode.id !== 'select') return;
39455 context.map().on('move.intro', null);
39456 context.on('enter.intro', null);
39458 timeout = setTimeout(function() {
39459 reveal('.preset-search-input',
39460 t('intro.areas.search',
39461 { name: context.presets().item('leisure/playground').name() }));
39462 d3.select('.preset-search-input').on('keyup.intro', keySearch);
39466 function keySearch() {
39467 var first = d3.select('.preset-list-item:first-child');
39468 if (first.classed('preset-leisure-playground')) {
39469 reveal(first.select('.preset-list-button').node(), t('intro.areas.choose'));
39470 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
39471 d3.select('.preset-search-input').on('keyup.intro', null);
39475 function selectedPreset() {
39477 t('intro.areas.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39478 context.on('exit.intro', event.done);
39482 step.exit = function() {
39483 window.clearTimeout(timeout);
39484 context.on('enter.intro', null);
39485 context.on('exit.intro', null);
39486 context.history().on('change.intro', null);
39487 context.map().on('move.intro', null);
39488 d3.select('.preset-search-input').on('keyup.intro', null);
39491 return d3.rebind(step, event, 'on');
39493 iD.ui.intro.line = function(context, reveal) {
39494 var event = d3.dispatch('done'),
39498 title: 'intro.lines.title'
39501 function timeout(f, t) {
39502 timeouts.push(window.setTimeout(f, t));
39505 function eventCancel() {
39506 d3.event.stopPropagation();
39507 d3.event.preventDefault();
39510 step.enter = function() {
39511 var centroid = [-85.62830, 41.95699];
39512 var midpoint = [-85.62975395449628, 41.95787501510204];
39513 var start = [-85.6297754121684, 41.95805253325314];
39514 var intersection = [-85.62974496187628, 41.95742515554585];
39516 context.map().centerZoom(start, 18);
39517 reveal('button.add-line',
39518 t('intro.lines.add', { button: iD.ui.intro.icon('#icon-line', 'pre-text') }),
39519 { tooltipClass: 'intro-lines-add' });
39521 context.on('enter.intro', addLine);
39523 function addLine(mode) {
39524 if (mode.id !== 'add-line') return;
39525 context.on('enter.intro', drawLine);
39527 var padding = 150 * Math.pow(2, context.map().zoom() - 18);
39528 var pointBox = iD.ui.intro.pad(start, padding, context);
39529 reveal(pointBox, t('intro.lines.start'));
39531 context.map().on('move.intro', function() {
39532 padding = 150 * Math.pow(2, context.map().zoom() - 18);
39533 pointBox = iD.ui.intro.pad(start, padding, context);
39534 reveal(pointBox, t('intro.lines.start'), {duration: 0});
39538 function drawLine(mode) {
39539 if (mode.id !== 'draw-line') return;
39540 context.history().on('change.intro', addIntersection);
39541 context.on('enter.intro', retry);
39543 var padding = 300 * Math.pow(2, context.map().zoom() - 19);
39544 var pointBox = iD.ui.intro.pad(midpoint, padding, context);
39545 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}));
39547 context.map().on('move.intro', function() {
39548 padding = 300 * Math.pow(2, context.map().zoom() - 19);
39549 pointBox = iD.ui.intro.pad(midpoint, padding, context);
39550 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}), {duration: 0});
39554 // ended line before creating intersection
39555 function retry(mode) {
39556 if (mode.id !== 'select') return;
39557 var pointBox = iD.ui.intro.pad(intersection, 30, context),
39558 ids = mode.selectedIDs();
39559 reveal(pointBox, t('intro.lines.restart', {name: t('intro.graph.flower_st')}));
39560 d3.select(window).on('mousedown.intro', eventCancel, true);
39562 timeout(function() {
39563 context.replace(iD.actions.DeleteMultiple(ids));
39569 function addIntersection(changes) {
39570 if ( _.any(changes.created(), function(d) {
39571 return d.type === 'node' && context.graph().parentWays(d).length > 1;
39573 context.history().on('change.intro', null);
39574 context.on('enter.intro', enterSelect);
39576 var padding = 900 * Math.pow(2, context.map().zoom() - 19);
39577 var pointBox = iD.ui.intro.pad(centroid, padding, context);
39578 reveal(pointBox, t('intro.lines.finish'));
39580 context.map().on('move.intro', function() {
39581 padding = 900 * Math.pow(2, context.map().zoom() - 19);
39582 pointBox = iD.ui.intro.pad(centroid, padding, context);
39583 reveal(pointBox, t('intro.lines.finish'), {duration: 0});
39588 function enterSelect(mode) {
39589 if (mode.id !== 'select') return;
39590 context.map().on('move.intro', null);
39591 context.on('enter.intro', null);
39592 d3.select('#curtain').style('pointer-events', 'all');
39597 function presetCategory() {
39598 timeout(function() {
39599 d3.select('#curtain').style('pointer-events', 'none');
39600 var road = d3.select('.preset-category-road .preset-list-button');
39601 reveal(road.node(), t('intro.lines.road'));
39602 road.one('click.intro', roadCategory);
39606 function roadCategory() {
39607 timeout(function() {
39608 var grid = d3.select('.subgrid');
39609 reveal(grid.node(), t('intro.lines.residential'));
39610 grid.selectAll(':not(.preset-highway-residential) .preset-list-button')
39611 .one('click.intro', retryPreset);
39612 grid.selectAll('.preset-highway-residential .preset-list-button')
39613 .one('click.intro', roadDetails);
39617 // selected wrong road type
39618 function retryPreset() {
39619 timeout(function() {
39620 var preset = d3.select('.entity-editor-pane .preset-list-button');
39621 reveal(preset.node(), t('intro.lines.wrong_preset'));
39622 preset.one('click.intro', presetCategory);
39626 function roadDetails() {
39628 t('intro.lines.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39629 context.on('exit.intro', event.done);
39634 step.exit = function() {
39635 d3.select(window).on('mousedown.intro', null, true);
39636 d3.select('#curtain').style('pointer-events', 'none');
39637 timeouts.forEach(window.clearTimeout);
39638 context.on('enter.intro', null);
39639 context.on('exit.intro', null);
39640 context.map().on('move.intro', null);
39641 context.history().on('change.intro', null);
39644 return d3.rebind(step, event, 'on');
39646 iD.ui.intro.navigation = function(context, reveal) {
39647 var event = d3.dispatch('done'),
39651 title: 'intro.navigation.title'
39654 function set(f, t) {
39655 timeouts.push(window.setTimeout(f, t));
39658 function eventCancel() {
39659 d3.event.stopPropagation();
39660 d3.event.preventDefault();
39663 step.enter = function() {
39664 var rect = context.surfaceRect(),
39666 left: rect.left + 10,
39667 top: rect.top + 70,
39668 width: rect.width - 70,
39669 height: rect.height - 170
39672 context.map().centerZoom([-85.63591, 41.94285], 19);
39674 reveal(map, t('intro.navigation.drag'));
39676 context.map().on('move.intro', _.debounce(function() {
39677 context.map().on('move.intro', null);
39679 context.on('enter.intro', inspectTownHall);
39682 function townhall() {
39683 var hall = [-85.63645945147184, 41.942986488012565];
39685 var point = context.projection(hall);
39686 if (point[0] < 0 || point[0] > rect.width ||
39687 point[1] < 0 || point[1] > rect.height) {
39688 context.map().center(hall);
39691 var box = iD.ui.intro.pointBox(hall, context);
39692 reveal(box, t('intro.navigation.select'));
39694 context.map().on('move.intro', function() {
39695 var box = iD.ui.intro.pointBox(hall, context);
39696 reveal(box, t('intro.navigation.select'), {duration: 0});
39700 function inspectTownHall(mode) {
39701 if (mode.id !== 'select') return;
39702 context.on('enter.intro', null);
39703 context.map().on('move.intro', null);
39705 reveal('.entity-editor-pane',
39706 t('intro.navigation.pane', { button: iD.ui.intro.icon('#icon-close', 'pre-text') }));
39707 context.on('exit.intro', streetSearch);
39711 function streetSearch() {
39712 context.on('exit.intro', null);
39713 reveal('.search-header input',
39714 t('intro.navigation.search', { name: t('intro.graph.spring_st') }));
39715 d3.select('.search-header input').on('keyup.intro', searchResult);
39718 function searchResult() {
39719 var first = d3.select('.feature-list-item:nth-child(0n+2)'), // skip No Results item
39720 firstName = first.select('.entity-name'),
39721 name = t('intro.graph.spring_st');
39723 if (!firstName.empty() && firstName.text() === name) {
39724 reveal(first.node(), t('intro.navigation.choose', { name: name }));
39725 context.on('exit.intro', selectedStreet);
39726 d3.select('.search-header input')
39727 .on('keydown.intro', eventCancel, true)
39728 .on('keyup.intro', null);
39732 function selectedStreet() {
39733 var springSt = [-85.63585099140167, 41.942506848938926];
39734 context.map().center(springSt);
39735 context.on('exit.intro', event.done);
39737 reveal('.entity-editor-pane',
39738 t('intro.navigation.chosen', {
39739 name: t('intro.graph.spring_st'),
39740 button: iD.ui.intro.icon('#icon-close', 'pre-text')
39746 step.exit = function() {
39747 timeouts.forEach(window.clearTimeout);
39748 context.map().on('move.intro', null);
39749 context.on('enter.intro', null);
39750 context.on('exit.intro', null);
39751 d3.select('.search-header input')
39752 .on('keydown.intro', null)
39753 .on('keyup.intro', null);
39756 return d3.rebind(step, event, 'on');
39758 iD.ui.intro.point = function(context, reveal) {
39759 var event = d3.dispatch('done'),
39763 title: 'intro.points.title'
39766 function setTimeout(f, t) {
39767 timeouts.push(window.setTimeout(f, t));
39770 function eventCancel() {
39771 d3.event.stopPropagation();
39772 d3.event.preventDefault();
39775 step.enter = function() {
39776 context.map().centerZoom([-85.63279, 41.94394], 19);
39777 reveal('button.add-point',
39778 t('intro.points.add', { button: iD.ui.intro.icon('#icon-point', 'pre-text') }),
39779 { tooltipClass: 'intro-points-add' });
39781 var corner = [-85.632481,41.944094];
39783 context.on('enter.intro', addPoint);
39785 function addPoint(mode) {
39786 if (mode.id !== 'add-point') return;
39787 context.on('enter.intro', enterSelect);
39789 var pointBox = iD.ui.intro.pad(corner, 150, context);
39790 reveal(pointBox, t('intro.points.place'));
39792 context.map().on('move.intro', function() {
39793 pointBox = iD.ui.intro.pad(corner, 150, context);
39794 reveal(pointBox, t('intro.points.place'), {duration: 0});
39798 function enterSelect(mode) {
39799 if (mode.id !== 'select') return;
39800 context.map().on('move.intro', null);
39801 context.on('enter.intro', null);
39803 setTimeout(function() {
39804 reveal('.preset-search-input',
39805 t('intro.points.search', {name: context.presets().item('amenity/cafe').name()}));
39806 d3.select('.preset-search-input').on('keyup.intro', keySearch);
39810 function keySearch() {
39811 var first = d3.select('.preset-list-item:first-child');
39812 if (first.classed('preset-amenity-cafe')) {
39813 reveal(first.select('.preset-list-button').node(), t('intro.points.choose'));
39814 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
39815 d3.select('.preset-search-input')
39816 .on('keydown.intro', eventCancel, true)
39817 .on('keyup.intro', null);
39821 function selectedPreset() {
39822 setTimeout(function() {
39823 reveal('.entity-editor-pane', t('intro.points.describe'), {tooltipClass: 'intro-points-describe'});
39824 context.history().on('change.intro', closeEditor);
39825 context.on('exit.intro', selectPoint);
39829 function closeEditor() {
39830 d3.select('.preset-search-input').on('keydown.intro', null);
39831 context.history().on('change.intro', null);
39832 reveal('.entity-editor-pane',
39833 t('intro.points.close', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39836 function selectPoint() {
39837 context.on('exit.intro', null);
39838 context.history().on('change.intro', null);
39839 context.on('enter.intro', enterReselect);
39841 var pointBox = iD.ui.intro.pad(corner, 150, context);
39842 reveal(pointBox, t('intro.points.reselect'));
39844 context.map().on('move.intro', function() {
39845 pointBox = iD.ui.intro.pad(corner, 150, context);
39846 reveal(pointBox, t('intro.points.reselect'), {duration: 0});
39850 function enterReselect(mode) {
39851 if (mode.id !== 'select') return;
39852 context.map().on('move.intro', null);
39853 context.on('enter.intro', null);
39855 setTimeout(function() {
39856 reveal('.entity-editor-pane',
39857 t('intro.points.fixname', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39858 context.on('exit.intro', deletePoint);
39862 function deletePoint() {
39863 context.on('exit.intro', null);
39864 context.on('enter.intro', enterDelete);
39866 var pointBox = iD.ui.intro.pad(corner, 150, context);
39867 reveal(pointBox, t('intro.points.reselect_delete'));
39869 context.map().on('move.intro', function() {
39870 pointBox = iD.ui.intro.pad(corner, 150, context);
39871 reveal(pointBox, t('intro.points.reselect_delete'), {duration: 0});
39875 function enterDelete(mode) {
39876 if (mode.id !== 'select') return;
39877 context.map().on('move.intro', null);
39878 context.on('enter.intro', null);
39879 context.on('exit.intro', deletePoint);
39880 context.map().on('move.intro', deletePoint);
39881 context.history().on('change.intro', deleted);
39883 setTimeout(function() {
39884 var node = d3.select('.radial-menu-item-delete').node();
39885 var pointBox = iD.ui.intro.pad(node.getBoundingClientRect(), 50, context);
39887 t('intro.points.delete', { button: iD.ui.intro.icon('#operation-delete', 'pre-text') }));
39891 function deleted(changed) {
39892 if (changed.deleted().length) event.done();
39897 step.exit = function() {
39898 timeouts.forEach(window.clearTimeout);
39899 context.on('exit.intro', null);
39900 context.on('enter.intro', null);
39901 context.map().on('move.intro', null);
39902 context.history().on('change.intro', null);
39903 d3.select('.preset-search-input')
39904 .on('keyup.intro', null)
39905 .on('keydown.intro', null);
39908 return d3.rebind(step, event, 'on');
39910 iD.ui.intro.startEditing = function(context, reveal) {
39911 var event = d3.dispatch('done', 'startEditing'),
39916 title: 'intro.startediting.title'
39919 function timeout(f, t) {
39920 timeouts.push(window.setTimeout(f, t));
39923 step.enter = function() {
39924 reveal('.map-control.help-control',
39925 t('intro.startediting.help', { button: iD.ui.intro.icon('#icon-help', 'pre-text') }));
39927 timeout(function() {
39928 reveal('#bar button.save', t('intro.startediting.save'));
39931 timeout(function() {
39932 reveal('#surface');
39935 timeout(function() {
39936 modal = iD.ui.modal(context.container());
39938 modal.select('.modal')
39939 .attr('class', 'modal-splash modal col6');
39941 modal.selectAll('.close').remove();
39943 var startbutton = modal.select('.content')
39944 .attr('class', 'fillL')
39946 .attr('class', 'modal-section huge-modal-button')
39947 .on('click', function() {
39951 startbutton.append('div')
39952 .attr('class','illustration');
39953 startbutton.append('h2')
39954 .text(t('intro.startediting.start'));
39956 event.startEditing();
39960 step.exit = function() {
39961 if (modal) modal.remove();
39962 timeouts.forEach(window.clearTimeout);
39965 return d3.rebind(step, event, 'on');
39967 iD.presets = function() {
39969 // an iD.presets.Collection with methods for
39970 // loading new data and returning defaults
39972 var all = iD.presets.Collection([]),
39973 defaults = { area: all, line: all, point: all, vertex: all, relation: all },
39976 recent = iD.presets.Collection([]);
39978 // Index of presets by (geometry, tag key).
39987 all.match = function(entity, resolver) {
39988 var geometry = entity.geometry(resolver),
39989 geometryMatches = index[geometry],
39993 for (var k in entity.tags) {
39994 var keyMatches = geometryMatches[k];
39995 if (!keyMatches) continue;
39997 for (var i = 0; i < keyMatches.length; i++) {
39998 var score = keyMatches[i].matchScore(entity);
39999 if (score > best) {
40001 match = keyMatches[i];
40006 return match || all.item(geometry);
40009 // Because of the open nature of tagging, iD will never have a complete
40010 // list of tags used in OSM, so we want it to have logic like "assume
40011 // that a closed way with an amenity tag is an area, unless the amenity
40012 // is one of these specific types". This function computes a structure
40013 // that allows testing of such conditions, based on the presets designated
40014 // as as supporting (or not supporting) the area geometry.
40016 // The returned object L is a whitelist/blacklist of tags. A closed way
40017 // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
40018 // (see `iD.Way#isArea()`). In other words, the keys of L form the whitelist,
40019 // and the subkeys form the blacklist.
40020 all.areaKeys = function() {
40022 ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],
40023 presets = _.reject(all.collection, 'suggestion');
40026 presets.forEach(function(d) {
40027 for (var key in d.tags) break;
40029 if (ignore.indexOf(key) !== -1) return;
40031 if (d.geometry.indexOf('area') !== -1) {
40032 areaKeys[key] = areaKeys[key] || {};
40037 presets.forEach(function(d) {
40038 for (var key in d.tags) break;
40040 if (ignore.indexOf(key) !== -1) return;
40042 var value = d.tags[key];
40043 if (d.geometry.indexOf('area') === -1 && key in areaKeys && value !== '*') {
40044 areaKeys[key][value] = true;
40051 all.load = function(d) {
40054 _.forEach(d.fields, function(d, id) {
40055 fields[id] = iD.presets.Field(id, d);
40056 if (d.universal) universal.push(fields[id]);
40061 _.forEach(d.presets, function(d, id) {
40062 all.collection.push(iD.presets.Preset(id, d, fields));
40066 if (d.categories) {
40067 _.forEach(d.categories, function(d, id) {
40068 all.collection.push(iD.presets.Category(id, d, all));
40073 var getItem = _.bind(all.item, all);
40075 area: iD.presets.Collection(d.defaults.area.map(getItem)),
40076 line: iD.presets.Collection(d.defaults.line.map(getItem)),
40077 point: iD.presets.Collection(d.defaults.point.map(getItem)),
40078 vertex: iD.presets.Collection(d.defaults.vertex.map(getItem)),
40079 relation: iD.presets.Collection(d.defaults.relation.map(getItem))
40083 for (var i = 0; i < all.collection.length; i++) {
40084 var preset = all.collection[i],
40085 geometry = preset.geometry;
40087 for (var j = 0; j < geometry.length; j++) {
40088 var g = index[geometry[j]];
40089 for (var k in preset.tags) {
40090 (g[k] = g[k] || []).push(preset);
40098 all.field = function(id) {
40102 all.universal = function() {
40106 all.defaults = function(geometry, n) {
40107 var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
40108 def = _.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
40109 return iD.presets.Collection(_.unique(rec.concat(def).concat(all.item(geometry))));
40112 all.choose = function(preset) {
40113 if (!preset.isFallback()) {
40114 recent = iD.presets.Collection(_.unique([preset].concat(recent.collection)));
40121 iD.presets.Category = function(id, category, all) {
40122 category = _.clone(category);
40126 category.members = iD.presets.Collection(category.members.map(function(id) {
40127 return all.item(id);
40130 category.matchGeometry = function(geometry) {
40131 return category.geometry.indexOf(geometry) >= 0;
40134 category.matchScore = function() { return -1; };
40136 category.name = function() {
40137 return t('presets.categories.' + id + '.name', {'default': id});
40140 category.terms = function() {
40146 iD.presets.Collection = function(collection) {
40148 var maxSearchResults = 50,
40149 maxSuggestionResults = 10;
40153 collection: collection,
40155 item: function(id) {
40156 return _.find(collection, function(d) {
40157 return d.id === id;
40161 matchGeometry: function(geometry) {
40162 return iD.presets.Collection(collection.filter(function(d) {
40163 return d.matchGeometry(geometry);
40167 search: function(value, geometry) {
40168 if (!value) return this;
40170 value = value.toLowerCase();
40172 var searchable = _.filter(collection, function(a) {
40173 return a.searchable !== false && a.suggestion !== true;
40175 suggestions = _.filter(collection, function(a) {
40176 return a.suggestion === true;
40179 function leading(a) {
40180 var index = a.indexOf(value);
40181 return index === 0 || a[index - 1] === ' ';
40184 // matches value to preset.name
40185 var leading_name = _.filter(searchable, function(a) {
40186 return leading(a.name().toLowerCase());
40187 }).sort(function(a, b) {
40188 var i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
40189 if (i === 0) return a.name().length - b.name().length;
40193 // matches value to preset.terms values
40194 var leading_terms = _.filter(searchable, function(a) {
40195 return _.any(a.terms() || [], leading);
40198 // matches value to preset.tags values
40199 var leading_tag_values = _.filter(searchable, function(a) {
40200 return _.any(_.without(_.values(a.tags || {}), '*'), leading);
40204 // finds close matches to value in preset.name
40205 var levenstein_name = searchable.map(function(a) {
40208 dist: iD.util.editDistance(value, a.name().toLowerCase())
40210 }).filter(function(a) {
40211 return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
40212 }).sort(function(a, b) {
40213 return a.dist - b.dist;
40214 }).map(function(a) {
40218 // finds close matches to value in preset.terms
40219 var leventstein_terms = _.filter(searchable, function(a) {
40220 return _.any(a.terms() || [], function(b) {
40221 return iD.util.editDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
40225 function suggestionName(name) {
40226 var nameArray = name.split(' - ');
40227 if (nameArray.length > 1) {
40228 name = nameArray.slice(0, nameArray.length-1).join(' - ');
40230 return name.toLowerCase();
40233 var leading_suggestions = _.filter(suggestions, function(a) {
40234 return leading(suggestionName(a.name()));
40235 }).sort(function(a, b) {
40236 a = suggestionName(a.name());
40237 b = suggestionName(b.name());
40238 var i = a.indexOf(value) - b.indexOf(value);
40239 if (i === 0) return a.length - b.length;
40243 var leven_suggestions = suggestions.map(function(a) {
40246 dist: iD.util.editDistance(value, suggestionName(a.name()))
40248 }).filter(function(a) {
40249 return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
40250 }).sort(function(a, b) {
40251 return a.dist - b.dist;
40252 }).map(function(a) {
40256 var other = presets.item(geometry);
40258 var results = leading_name.concat(
40260 leading_tag_values,
40261 leading_suggestions.slice(0, maxSuggestionResults+5),
40264 leven_suggestions.slice(0, maxSuggestionResults)
40265 ).slice(0, maxSearchResults-1);
40267 return iD.presets.Collection(_.unique(
40268 results.concat(other)
40275 iD.presets.Field = function(id, field) {
40276 field = _.clone(field);
40280 field.matchGeometry = function(geometry) {
40281 return !field.geometry || field.geometry === geometry;
40284 field.t = function(scope, options) {
40285 return t('presets.fields.' + id + '.' + scope, options);
40288 field.label = function() {
40289 return field.t('label', {'default': id});
40292 var placeholder = field.placeholder;
40293 field.placeholder = function() {
40294 return field.t('placeholder', {'default': placeholder});
40299 iD.presets.Preset = function(id, preset, fields) {
40300 preset = _.clone(preset);
40303 preset.fields = (preset.fields || []).map(getFields);
40304 preset.geometry = (preset.geometry || []);
40306 function getFields(f) {
40310 preset.matchGeometry = function(geometry) {
40311 return preset.geometry.indexOf(geometry) >= 0;
40314 var matchScore = preset.matchScore || 1;
40315 preset.matchScore = function(entity) {
40316 var tags = preset.tags,
40319 for (var t in tags) {
40320 if (entity.tags[t] === tags[t]) {
40321 score += matchScore;
40322 } else if (tags[t] === '*' && t in entity.tags) {
40323 score += matchScore / 2;
40332 preset.t = function(scope, options) {
40333 return t('presets.presets.' + id + '.' + scope, options);
40336 var name = preset.name;
40337 preset.name = function() {
40338 if (preset.suggestion) {
40339 id = id.split('/');
40340 id = id[0] + '/' + id[1];
40341 return name + ' - ' + t('presets.presets.' + id + '.name');
40343 return preset.t('name', {'default': name});
40346 preset.terms = function() {
40347 return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
40350 preset.isFallback = function() {
40351 var tagCount = Object.keys(preset.tags).length;
40352 return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
40355 preset.reference = function(geometry) {
40356 var key = Object.keys(preset.tags)[0],
40357 value = preset.tags[key];
40359 if (geometry === 'relation' && key === 'type') {
40360 return { rtype: value };
40361 } else if (value === '*') {
40362 return { key: key };
40364 return { key: key, value: value };
40368 var removeTags = preset.removeTags || preset.tags;
40369 preset.removeTags = function(tags, geometry) {
40370 tags = _.omit(tags, _.keys(removeTags));
40372 for (var f in preset.fields) {
40373 var field = preset.fields[f];
40374 if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
40375 delete tags[field.key];
40383 var applyTags = preset.addTags || preset.tags;
40384 preset.applyTags = function(tags, geometry) {
40387 tags = _.clone(tags);
40389 for (k in applyTags) {
40390 if (applyTags[k] === '*') {
40393 tags[k] = applyTags[k];
40397 // Add area=yes if necessary.
40398 // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
40399 // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
40400 // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
40401 if (geometry === 'area') {
40402 var needsAreaTag = true;
40403 if (preset.geometry.indexOf('line') === -1) {
40404 for (k in applyTags) {
40405 if (k in iD.areaKeys) {
40406 needsAreaTag = false;
40411 if (needsAreaTag) {
40416 for (var f in preset.fields) {
40417 var field = preset.fields[f];
40418 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
40419 tags[field.key] = field.default;
40428 iD.validations = {};
40429 iD.validations.DeprecatedTag = function() {
40431 var validation = function(changes) {
40433 for (var i = 0; i < changes.created.length; i++) {
40434 var change = changes.created[i],
40435 deprecatedTags = change.deprecatedTags();
40437 if (!_.isEmpty(deprecatedTags)) {
40438 var tags = iD.util.tagText({ tags: deprecatedTags });
40440 id: 'deprecated_tags',
40441 message: t('validations.deprecated_tags', { tags: tags }),
40451 iD.validations.ManyDeletions = function() {
40452 var threshold = 100;
40454 var validation = function(changes) {
40456 if (changes.deleted.length > threshold) {
40458 id: 'many_deletions',
40459 message: t('validations.many_deletions', { n: changes.deleted.length })
40467 iD.validations.MissingTag = function() {
40469 var validation = function(changes, graph) {
40471 for (var i = 0; i < changes.created.length; i++) {
40472 var change = changes.created[i],
40473 geometry = change.geometry(graph);
40475 if ((geometry === 'point' || geometry === 'line' || geometry === 'area') && !change.isUsed(graph)) {
40478 message: t('validations.untagged_' + geometry),
40479 tooltip: t('validations.untagged_' + geometry + '_tooltip'),
40489 iD.validations.TagSuggestsArea = function() {
40491 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
40492 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
40493 function tagSuggestsArea(tags) {
40494 if (_.isEmpty(tags)) return false;
40496 var presence = ['landuse', 'amenities', 'tourism', 'shop'];
40497 for (var i = 0; i < presence.length; i++) {
40498 if (tags[presence[i]] !== undefined) {
40499 return presence[i] + '=' + tags[presence[i]];
40503 if (tags.building && tags.building === 'yes') return 'building=yes';
40506 var validation = function(changes, graph) {
40508 for (var i = 0; i < changes.created.length; i++) {
40509 var change = changes.created[i],
40510 geometry = change.geometry(graph),
40511 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
40515 id: 'tag_suggests_area',
40516 message: t('validations.tag_suggests_area', { tag: suggestion }),
40527 window.locale = { _current: 'en' };
40529 locale.current = function(_) {
40530 if (!arguments.length) return locale._current;
40531 if (locale[_] !== undefined) locale._current = _;
40532 else if (locale[_.split('-')[0]]) locale._current = _.split('-')[0];
40536 function t(s, o, loc) {
40537 loc = loc || locale._current;
40539 var path = s.split(".").reverse(),
40542 while (rep !== undefined && path.length) rep = rep[path.pop()];
40544 if (rep !== undefined) {
40545 if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
40549 if (loc !== 'en') {
40550 return t(s, o, 'en');
40553 if (o && 'default' in o) {
40554 return o['default'];
40557 var missing = 'Missing ' + loc + ' translation: ' + s;
40558 if (typeof console !== "undefined") console.error(missing);
40562 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"]]}]};