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.2';
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) {
24078 function mousedown() {
24079 var button = 0; // left
24080 if (d3.event.button === button && d3.event.shiftKey === true) {
24084 .on('mousemove.lasso', mousemove)
24085 .on('mouseup.lasso', mouseup);
24087 d3.event.stopPropagation();
24091 function mousemove() {
24093 lasso = iD.ui.Lasso(context);
24094 context.surface().call(lasso);
24097 lasso.p(context.mouse());
24100 function normalize(a, b) {
24102 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
24103 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
24106 function lassoed() {
24107 if (!lasso) return [];
24109 var graph = context.graph(),
24110 bounds = lasso.extent().map(context.projection.invert),
24111 extent = iD.geo.Extent(normalize(bounds[0], bounds[1]));
24113 return _.pluck(context.intersects(extent).filter(function(entity) {
24114 return entity.type === 'node' &&
24115 iD.geo.pointInPolygon(context.projection(entity.loc), lasso.coordinates) &&
24116 !context.features().isHidden(entity, graph, entity.geometry(graph));
24120 function mouseup() {
24122 .on('mousemove.lasso', null)
24123 .on('mouseup.lasso', null);
24125 if (!lasso) return;
24127 var ids = lassoed();
24131 context.enter(iD.modes.Select(context, ids));
24136 .on('mousedown.lasso', mousedown);
24139 behavior.off = function(selection) {
24140 selection.on('mousedown.lasso', null);
24145 iD.behavior.Paste = function(context) {
24146 var keybinding = d3.keybinding('paste');
24148 function omitTag(v, k) {
24156 k === 'description' ||
24157 k.indexOf('name') !== -1 ||
24158 k.indexOf('wiki') === 0 ||
24159 k.indexOf('addr:') === 0 ||
24160 k.indexOf('contact:') === 0
24164 function doPaste() {
24165 d3.event.preventDefault();
24166 if (context.inIntro()) return;
24168 var baseGraph = context.graph(),
24169 mouse = context.mouse(),
24170 projection = context.projection,
24171 viewport = iD.geo.Extent(projection.clipExtent()).polygon();
24173 if (!iD.geo.pointInPolygon(mouse, viewport)) return;
24175 var extent = iD.geo.Extent(),
24176 oldIDs = context.copyIDs(),
24177 oldGraph = context.copyGraph(),
24180 if (!oldIDs.length) return;
24182 var action = iD.actions.CopyEntities(oldIDs, oldGraph);
24183 context.perform(action);
24185 var copies = action.copies();
24186 for (var id in copies) {
24187 var oldEntity = oldGraph.entity(id),
24188 newEntity = copies[id];
24190 extent._extend(oldEntity.extent(oldGraph));
24191 newIDs.push(newEntity.id);
24192 context.perform(iD.actions.ChangeTags(newEntity.id, _.omit(newEntity.tags, omitTag)));
24195 // Put pasted objects where mouse pointer is..
24196 var center = projection(extent.center()),
24197 delta = [ mouse[0] - center[0], mouse[1] - center[1] ];
24199 context.perform(iD.actions.Move(newIDs, delta, projection));
24200 context.enter(iD.modes.Move(context, newIDs, baseGraph));
24204 keybinding.on(iD.ui.cmd('⌘V'), doPaste);
24205 d3.select(document).call(keybinding);
24209 paste.off = function() {
24210 d3.select(document).call(keybinding.off);
24215 iD.behavior.Select = function(context) {
24216 function keydown() {
24217 if (d3.event && d3.event.shiftKey) {
24219 .classed('behavior-multiselect', true);
24224 if (!d3.event || !d3.event.shiftKey) {
24226 .classed('behavior-multiselect', false);
24231 var datum = d3.event.target.__data__,
24232 lasso = d3.select('#surface .lasso').node(),
24233 mode = context.mode();
24235 if (!(datum instanceof iD.Entity)) {
24236 if (!d3.event.shiftKey && !lasso && mode.id !== 'browse')
24237 context.enter(iD.modes.Browse(context));
24239 } else if (!d3.event.shiftKey && !lasso) {
24240 // Avoid re-entering Select mode with same entity.
24241 if (context.selectedIDs().length !== 1 || context.selectedIDs()[0] !== datum.id) {
24242 context.enter(iD.modes.Select(context, [datum.id]));
24244 mode.suppressMenu(false).reselect();
24246 } else if (context.selectedIDs().indexOf(datum.id) >= 0) {
24247 var selectedIDs = _.without(context.selectedIDs(), datum.id);
24248 context.enter(selectedIDs.length ?
24249 iD.modes.Select(context, selectedIDs) :
24250 iD.modes.Browse(context));
24253 context.enter(iD.modes.Select(context, context.selectedIDs().concat([datum.id])));
24257 var behavior = function(selection) {
24259 .on('keydown.select', keydown)
24260 .on('keyup.select', keyup);
24262 selection.on('click.select', click);
24267 behavior.off = function(selection) {
24269 .on('keydown.select', null)
24270 .on('keyup.select', null);
24272 selection.on('click.select', null);
24279 iD.behavior.Tail = function() {
24283 tooltipSize = [0, 0],
24284 selectionSize = [0, 0];
24286 function tail(selection) {
24290 .on('resize.tail', function() { selectionSize = selection.dimensions(); });
24293 container.style('display', 'block');
24294 tooltipSize = container.dimensions();
24297 function mousemove() {
24298 if (container.style('display') === 'none') show();
24299 var xoffset = ((d3.event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
24300 -tooltipSize[0] - xmargin : xmargin;
24301 container.classed('left', xoffset > 0);
24302 iD.util.setTransform(container, d3.event.clientX + xoffset, d3.event.clientY);
24305 function mouseleave() {
24306 if (d3.event.relatedTarget !== container.node()) {
24307 container.style('display', 'none');
24311 function mouseenter() {
24312 if (d3.event.relatedTarget !== container.node()) {
24317 container = d3.select(document.body)
24319 .style('display', 'none')
24320 .attr('class', 'tail tooltip-inner');
24322 container.append('div')
24326 .on('mousemove.tail', mousemove)
24327 .on('mouseenter.tail', mouseenter)
24328 .on('mouseleave.tail', mouseleave);
24331 .on('mousemove.tail', mousemove);
24333 tooltipSize = container.dimensions();
24334 selectionSize = selection.dimensions();
24337 tail.off = function(selection) {
24341 .on('mousemove.tail', null)
24345 .on('mousemove.tail', null)
24346 .on('mouseenter.tail', null)
24347 .on('mouseleave.tail', null);
24350 .on('resize.tail', null);
24353 tail.text = function(_) {
24354 if (!arguments.length) return text;
24362 iD.modes.AddArea = function(context) {
24366 title: t('modes.add_area.title'),
24367 description: t('modes.add_area.description'),
24371 var behavior = iD.behavior.AddWay(context)
24372 .tail(t('modes.add_area.tail'))
24373 .on('start', start)
24374 .on('startFromWay', startFromWay)
24375 .on('startFromNode', startFromNode),
24376 defaultTags = {area: 'yes'};
24378 function start(loc) {
24379 var graph = context.graph(),
24380 node = iD.Node({loc: loc}),
24381 way = iD.Way({tags: defaultTags});
24384 iD.actions.AddEntity(node),
24385 iD.actions.AddEntity(way),
24386 iD.actions.AddVertex(way.id, node.id),
24387 iD.actions.AddVertex(way.id, node.id));
24389 context.enter(iD.modes.DrawArea(context, way.id, graph));
24392 function startFromWay(loc, edge) {
24393 var graph = context.graph(),
24394 node = iD.Node({loc: loc}),
24395 way = iD.Way({tags: defaultTags});
24398 iD.actions.AddEntity(node),
24399 iD.actions.AddEntity(way),
24400 iD.actions.AddVertex(way.id, node.id),
24401 iD.actions.AddVertex(way.id, node.id),
24402 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
24404 context.enter(iD.modes.DrawArea(context, way.id, graph));
24407 function startFromNode(node) {
24408 var graph = context.graph(),
24409 way = iD.Way({tags: defaultTags});
24412 iD.actions.AddEntity(way),
24413 iD.actions.AddVertex(way.id, node.id),
24414 iD.actions.AddVertex(way.id, node.id));
24416 context.enter(iD.modes.DrawArea(context, way.id, graph));
24419 mode.enter = function() {
24420 context.install(behavior);
24423 mode.exit = function() {
24424 context.uninstall(behavior);
24429 iD.modes.AddLine = function(context) {
24433 title: t('modes.add_line.title'),
24434 description: t('modes.add_line.description'),
24438 var behavior = iD.behavior.AddWay(context)
24439 .tail(t('modes.add_line.tail'))
24440 .on('start', start)
24441 .on('startFromWay', startFromWay)
24442 .on('startFromNode', startFromNode);
24444 function start(loc) {
24445 var baseGraph = context.graph(),
24446 node = iD.Node({loc: loc}),
24450 iD.actions.AddEntity(node),
24451 iD.actions.AddEntity(way),
24452 iD.actions.AddVertex(way.id, node.id));
24454 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24457 function startFromWay(loc, edge) {
24458 var baseGraph = context.graph(),
24459 node = iD.Node({loc: loc}),
24463 iD.actions.AddEntity(node),
24464 iD.actions.AddEntity(way),
24465 iD.actions.AddVertex(way.id, node.id),
24466 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
24468 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24471 function startFromNode(node) {
24472 var baseGraph = context.graph(),
24476 iD.actions.AddEntity(way),
24477 iD.actions.AddVertex(way.id, node.id));
24479 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24482 mode.enter = function() {
24483 context.install(behavior);
24486 mode.exit = function() {
24487 context.uninstall(behavior);
24492 iD.modes.AddPoint = function(context) {
24496 title: t('modes.add_point.title'),
24497 description: t('modes.add_point.description'),
24501 var behavior = iD.behavior.Draw(context)
24502 .tail(t('modes.add_point.tail'))
24504 .on('clickWay', addWay)
24505 .on('clickNode', addNode)
24506 .on('cancel', cancel)
24507 .on('finish', cancel);
24509 function add(loc) {
24510 var node = iD.Node({loc: loc});
24513 iD.actions.AddEntity(node),
24514 t('operations.add.annotation.point'));
24517 iD.modes.Select(context, [node.id])
24518 .suppressMenu(true)
24519 .newFeature(true));
24522 function addWay(loc) {
24526 function addNode(node) {
24530 function cancel() {
24531 context.enter(iD.modes.Browse(context));
24534 mode.enter = function() {
24535 context.install(behavior);
24538 mode.exit = function() {
24539 context.uninstall(behavior);
24544 iD.modes.Browse = function(context) {
24548 title: t('modes.browse.title'),
24549 description: t('modes.browse.description')
24553 iD.behavior.Paste(context),
24554 iD.behavior.Hover(context)
24555 .on('hover', context.ui().sidebar.hover),
24556 iD.behavior.Select(context),
24557 iD.behavior.Lasso(context),
24558 iD.modes.DragNode(context).behavior];
24560 mode.enter = function() {
24561 behaviors.forEach(function(behavior) {
24562 context.install(behavior);
24565 // Get focus on the body.
24566 if (document.activeElement && document.activeElement.blur) {
24567 document.activeElement.blur();
24571 context.ui().sidebar.show(sidebar);
24573 context.ui().sidebar.select(null);
24577 mode.exit = function() {
24578 context.ui().sidebar.hover.cancel();
24579 behaviors.forEach(function(behavior) {
24580 context.uninstall(behavior);
24584 context.ui().sidebar.hide();
24588 mode.sidebar = function(_) {
24589 if (!arguments.length) return sidebar;
24596 iD.modes.DragNode = function(context) {
24607 hover = iD.behavior.Hover(context)
24609 .on('hover', context.ui().sidebar.hover),
24610 edit = iD.behavior.Edit(context);
24612 function edge(point, size) {
24613 var pad = [30, 100, 30, 100];
24614 if (point[0] > size[0] - pad[0]) return [-10, 0];
24615 else if (point[0] < pad[2]) return [10, 0];
24616 else if (point[1] > size[1] - pad[1]) return [0, -10];
24617 else if (point[1] < pad[3]) return [0, 10];
24621 function startNudge(nudge) {
24622 if (nudgeInterval) window.clearInterval(nudgeInterval);
24623 nudgeInterval = window.setInterval(function() {
24624 context.pan(nudge);
24628 function stopNudge() {
24629 if (nudgeInterval) window.clearInterval(nudgeInterval);
24630 nudgeInterval = null;
24633 function moveAnnotation(entity) {
24634 return t('operations.move.annotation.' + entity.geometry(context.graph()));
24637 function connectAnnotation(entity) {
24638 return t('operations.connect.annotation.' + entity.geometry(context.graph()));
24641 function origin(entity) {
24642 return context.projection(entity.loc);
24645 function start(entity) {
24646 cancelled = d3.event.sourceEvent.shiftKey ||
24647 context.features().hasHiddenConnections(entity, context.graph());
24649 if (cancelled) return behavior.cancel();
24651 wasMidpoint = entity.type === 'midpoint';
24653 var midpoint = entity;
24654 entity = iD.Node();
24655 context.perform(iD.actions.AddMidpoint(midpoint, entity));
24657 var vertex = context.surface()
24658 .selectAll('.' + entity.id);
24659 behavior.target(vertex.node(), entity);
24663 iD.actions.Noop());
24666 activeIDs = _.pluck(context.graph().parentWays(entity), 'id');
24667 activeIDs.push(entity.id);
24669 context.enter(mode);
24673 if (d3.event.sourceEvent.altKey) {
24677 return d3.event.sourceEvent.target.__data__ || {};
24680 // via https://gist.github.com/shawnbot/4166283
24681 function childOf(p, c) {
24682 if (p === c) return false;
24683 while (c && c !== p) c = c.parentNode;
24687 function move(entity) {
24688 if (cancelled) return;
24689 d3.event.sourceEvent.stopPropagation();
24691 var nudge = childOf(context.container().node(),
24692 d3.event.sourceEvent.toElement) &&
24693 edge(d3.event.point, context.map().dimensions());
24695 if (nudge) startNudge(nudge);
24698 var loc = context.projection.invert(d3.event.point);
24701 if (d.type === 'node' && d.id !== entity.id) {
24703 } else if (d.type === 'way' && !d3.select(d3.event.sourceEvent.target).classed('fill')) {
24704 loc = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
24708 iD.actions.MoveNode(entity.id, loc),
24709 moveAnnotation(entity));
24712 function end(entity) {
24713 if (cancelled) return;
24717 if (d.type === 'way') {
24718 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection);
24720 iD.actions.AddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
24721 connectAnnotation(d));
24723 } else if (d.type === 'node' && d.id !== entity.id) {
24725 iD.actions.Connect([d.id, entity.id]),
24726 connectAnnotation(d));
24728 } else if (wasMidpoint) {
24731 t('operations.add.annotation.vertex'));
24736 moveAnnotation(entity));
24739 var reselection = selectedIDs.filter(function(id) {
24740 return context.graph().hasEntity(id);
24743 if (reselection.length) {
24745 iD.modes.Select(context, reselection)
24746 .suppressMenu(true));
24748 context.enter(iD.modes.Browse(context));
24752 function cancel() {
24754 context.enter(iD.modes.Browse(context));
24757 function setActiveElements() {
24758 context.surface().selectAll(iD.util.entitySelector(activeIDs))
24759 .classed('active', true);
24762 var behavior = iD.behavior.drag()
24763 .delegate('g.node, g.point, g.midpoint')
24764 .surface(context.surface().node())
24766 .on('start', start)
24770 mode.enter = function() {
24771 context.install(hover);
24772 context.install(edit);
24775 .on('undone.drag-node', cancel);
24778 .on('drawn.drag-node', setActiveElements);
24780 setActiveElements();
24783 mode.exit = function() {
24784 context.ui().sidebar.hover.cancel();
24785 context.uninstall(hover);
24786 context.uninstall(edit);
24789 .on('undone.drag-node', null);
24792 .on('drawn.drag-node', null);
24795 .selectAll('.active')
24796 .classed('active', false);
24801 mode.selectedIDs = function(_) {
24802 if (!arguments.length) return selectedIDs;
24807 mode.behavior = behavior;
24811 iD.modes.DrawArea = function(context, wayId, baseGraph) {
24819 mode.enter = function() {
24820 var way = context.entity(wayId),
24821 headId = way.nodes[way.nodes.length - 2],
24822 tailId = way.first();
24824 behavior = iD.behavior.DrawWay(context, wayId, -1, mode, baseGraph)
24825 .tail(t('modes.draw_area.tail'));
24827 var addNode = behavior.addNode;
24829 behavior.addNode = function(node) {
24830 if (node.id === headId || node.id === tailId) {
24837 context.install(behavior);
24840 mode.exit = function() {
24841 context.uninstall(behavior);
24844 mode.selectedIDs = function() {
24850 iD.modes.DrawLine = function(context, wayId, baseGraph, affix) {
24858 mode.enter = function() {
24859 var way = context.entity(wayId),
24860 index = (affix === 'prefix') ? 0 : undefined,
24861 headId = (affix === 'prefix') ? way.first() : way.last();
24863 behavior = iD.behavior.DrawWay(context, wayId, index, mode, baseGraph)
24864 .tail(t('modes.draw_line.tail'));
24866 var addNode = behavior.addNode;
24868 behavior.addNode = function(node) {
24869 if (node.id === headId) {
24876 context.install(behavior);
24879 mode.exit = function() {
24880 context.uninstall(behavior);
24883 mode.selectedIDs = function() {
24889 iD.modes.Move = function(context, entityIDs, baseGraph) {
24895 var keybinding = d3.keybinding('move'),
24896 edit = iD.behavior.Edit(context),
24897 annotation = entityIDs.length === 1 ?
24898 t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
24899 t('operations.move.annotation.multiple'),
24904 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
24906 function edge(point, size) {
24907 var pad = [30, 100, 30, 100];
24908 if (point[0] > size[0] - pad[0]) return [-10, 0];
24909 else if (point[0] < pad[2]) return [10, 0];
24910 else if (point[1] > size[1] - pad[1]) return [0, -10];
24911 else if (point[1] < pad[3]) return [0, 10];
24915 function startNudge(nudge) {
24916 if (nudgeInterval) window.clearInterval(nudgeInterval);
24917 nudgeInterval = window.setInterval(function() {
24918 context.pan(nudge);
24920 var currMouse = context.mouse(),
24921 origMouse = context.projection(origin),
24922 delta = vecSub(vecSub(currMouse, origMouse), nudge),
24923 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
24925 context.overwrite(action, annotation);
24930 function stopNudge() {
24931 if (nudgeInterval) window.clearInterval(nudgeInterval);
24932 nudgeInterval = null;
24936 var currMouse = context.mouse(),
24937 origMouse = context.projection(origin),
24938 delta = vecSub(currMouse, origMouse),
24939 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
24941 context.overwrite(action, annotation);
24943 var nudge = edge(currMouse, context.map().dimensions());
24944 if (nudge) startNudge(nudge);
24948 function finish() {
24949 d3.event.stopPropagation();
24950 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
24954 function cancel() {
24956 while (context.graph() !== baseGraph) context.pop();
24957 context.enter(iD.modes.Browse(context));
24960 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
24965 function undone() {
24966 context.enter(iD.modes.Browse(context));
24969 mode.enter = function() {
24970 origin = context.map().mouseCoordinates();
24973 context.install(edit);
24980 .on('mousemove.move', move)
24981 .on('click.move', finish);
24984 .on('undone.move', undone);
24990 d3.select(document)
24994 mode.exit = function() {
24997 context.uninstall(edit);
25000 .on('mousemove.move', null)
25001 .on('click.move', null);
25004 .on('undone.move', null);
25011 iD.modes.RotateWay = function(context, wayId) {
25017 var keybinding = d3.keybinding('rotate-way'),
25018 edit = iD.behavior.Edit(context);
25020 mode.enter = function() {
25021 context.install(edit);
25023 var annotation = t('operations.rotate.annotation.' + context.geometry(wayId)),
25024 way = context.graph().entity(wayId),
25025 nodes = _.uniq(context.graph().childNodes(way)),
25026 points = nodes.map(function(n) { return context.projection(n.loc); }),
25027 pivot = d3.geom.polygon(points).centroid(),
25034 function rotate() {
25036 var mousePoint = context.mouse(),
25037 newAngle = Math.atan2(mousePoint[1] - pivot[1], mousePoint[0] - pivot[0]);
25039 if (typeof angle === 'undefined') angle = newAngle;
25042 iD.actions.RotateWay(wayId, pivot, newAngle - angle, context.projection),
25048 function finish() {
25049 d3.event.stopPropagation();
25050 context.enter(iD.modes.Select(context, [wayId])
25051 .suppressMenu(true));
25054 function cancel() {
25056 context.enter(iD.modes.Select(context, [wayId])
25057 .suppressMenu(true));
25060 function undone() {
25061 context.enter(iD.modes.Browse(context));
25065 .on('mousemove.rotate-way', rotate)
25066 .on('click.rotate-way', finish);
25069 .on('undone.rotate-way', undone);
25075 d3.select(document)
25079 mode.exit = function() {
25080 context.uninstall(edit);
25083 .on('mousemove.rotate-way', null)
25084 .on('click.rotate-way', null);
25087 .on('undone.rotate-way', null);
25094 iD.modes.Save = function(context) {
25095 var ui = iD.ui.Commit(context)
25096 .on('cancel', cancel)
25099 function cancel() {
25100 context.enter(iD.modes.Browse(context));
25103 function save(e, tryAgain) {
25104 function withChildNodes(ids, graph) {
25105 return _.uniq(_.reduce(ids, function(result, id) {
25106 var e = graph.entity(id);
25107 if (e.type === 'way') {
25109 var cn = graph.childNodes(e);
25110 result.push.apply(result, _.pluck(_.filter(cn, 'version'), 'id'));
25112 /* eslint-disable no-console */
25113 if (typeof console !== 'undefined') console.error(err);
25114 /* eslint-enable no-console */
25121 var loading = iD.ui.Loading(context).message(t('save.uploading')).blocking(true),
25122 history = context.history(),
25123 origChanges = history.changes(iD.actions.DiscardTags(history.difference())),
25124 localGraph = context.graph(),
25125 remoteGraph = iD.Graph(history.base(), true),
25126 modified = _.filter(history.difference().summary(), {changeType: 'modified'}),
25127 toCheck = _.pluck(_.pluck(modified, 'entity'), 'id'),
25128 toLoad = withChildNodes(toCheck, localGraph),
25132 if (!tryAgain) history.perform(iD.actions.Noop()); // checkpoint
25133 context.container().call(loading);
25135 if (toCheck.length) {
25136 context.connection().loadMultiple(toLoad, loaded);
25142 // Reload modified entities into an alternate graph and check for conflicts..
25143 function loaded(err, result) {
25144 if (errors.length) return;
25148 msg: err.responseText,
25149 details: [ t('save.status_code', { code: err.status }) ]
25155 _.each(result.data, function(entity) {
25156 remoteGraph.replace(entity);
25157 toLoad = _.without(toLoad, entity.id);
25159 // Because loadMultiple doesn't download /full like loadEntity,
25160 // need to also load children that aren't already being checked..
25161 if (!entity.visible) return;
25162 if (entity.type === 'way') {
25163 loadMore.push.apply(loadMore,
25164 _.difference(entity.nodes, toCheck, toLoad, loadMore));
25165 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
25166 loadMore.push.apply(loadMore,
25167 _.difference(_.pluck(entity.members, 'id'), toCheck, toLoad, loadMore));
25171 if (loadMore.length) {
25172 toLoad.push.apply(toLoad, loadMore);
25173 context.connection().loadMultiple(loadMore, loaded);
25176 if (!toLoad.length) {
25183 function checkConflicts() {
25184 function choice(id, text, action) {
25185 return { id: id, text: text, action: function() { history.replace(action); } };
25187 function formatUser(d) {
25188 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
25190 function entityName(entity) {
25191 return iD.util.displayName(entity) || (iD.util.displayType(entity.id) + ' ' + entity.id);
25194 function compareVersions(local, remote) {
25195 if (local.version !== remote.version) return false;
25197 if (local.type === 'way') {
25198 var children = _.union(local.nodes, remote.nodes);
25200 for (var i = 0; i < children.length; i++) {
25201 var a = localGraph.hasEntity(children[i]),
25202 b = remoteGraph.hasEntity(children[i]);
25204 if (a && b && a.version !== b.version) return false;
25211 _.each(toCheck, function(id) {
25212 var local = localGraph.entity(id),
25213 remote = remoteGraph.entity(id);
25215 if (compareVersions(local, remote)) return;
25217 var action = iD.actions.MergeRemoteChanges,
25218 merge = action(id, localGraph, remoteGraph, formatUser);
25220 history.replace(merge);
25222 var mergeConflicts = merge.conflicts();
25223 if (!mergeConflicts.length) return; // merged safely
25225 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
25226 forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
25227 keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
25228 keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
25232 name: entityName(local),
25233 details: mergeConflicts,
25236 choice(id, keepMine, forceLocal),
25237 choice(id, keepTheirs, forceRemote)
25246 function finalize() {
25247 if (conflicts.length) {
25248 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
25250 } else if (errors.length) {
25253 var changes = history.changes(iD.actions.DiscardTags(history.difference()));
25254 if (changes.modified.length || changes.created.length || changes.deleted.length) {
25255 context.connection().putChangeset(
25258 history.imageryUsed(),
25259 function(err, changeset_id) {
25262 msg: err.responseText,
25263 details: [ t('save.status_code', { code: err.status }) ]
25267 history.clearSaved();
25268 success(e, changeset_id);
25269 // Add delay to allow for postgres replication #1646 #2678
25270 window.setTimeout(function() {
25276 } else { // changes were insignificant or reverted by user
25285 function showConflicts() {
25286 var selection = context.container()
25287 .select('#sidebar')
25289 .attr('class','sidebar-component');
25293 selection.call(iD.ui.Conflicts(context)
25295 .on('download', function() {
25296 var data = JXON.stringify(context.connection().osmChangeJXON('CHANGEME', origChanges)),
25297 win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
25300 .on('cancel', function() {
25302 selection.remove();
25304 .on('save', function() {
25305 for (var i = 0; i < conflicts.length; i++) {
25306 if (conflicts[i].chosen === 1) { // user chose "keep theirs"
25307 var entity = context.hasEntity(conflicts[i].id);
25308 if (entity && entity.type === 'way') {
25309 var children = _.uniq(entity.nodes);
25310 for (var j = 0; j < children.length; j++) {
25311 history.replace(iD.actions.Revert(children[j]));
25314 history.replace(iD.actions.Revert(conflicts[i].id));
25318 selection.remove();
25325 function showErrors() {
25326 var selection = iD.ui.confirm(context.container());
25332 .select('.modal-section.header')
25334 .text(t('save.error'));
25336 addErrors(selection, errors);
25337 selection.okButton();
25341 function addErrors(selection, data) {
25342 var message = selection
25343 .select('.modal-section.message-text');
25345 var items = message
25346 .selectAll('.error-container')
25349 var enter = items.enter()
25351 .attr('class', 'error-container');
25355 .attr('class', 'error-description')
25357 .classed('hide-toggle', true)
25358 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
25359 .on('click', function() {
25360 var error = d3.select(this),
25361 detail = d3.select(this.nextElementSibling),
25362 exp = error.classed('expanded');
25364 detail.style('display', exp ? 'none' : 'block');
25365 error.classed('expanded', !exp);
25367 d3.event.preventDefault();
25370 var details = enter
25372 .attr('class', 'error-detail-container')
25373 .style('display', 'none');
25377 .attr('class', 'error-detail-list')
25379 .data(function(d) { return d.details || []; })
25382 .attr('class', 'error-detail-item')
25383 .text(function(d) { return d; });
25392 function success(e, changeset_id) {
25393 context.enter(iD.modes.Browse(context)
25394 .sidebar(iD.ui.Success(context)
25399 .on('cancel', function() {
25400 context.ui().sidebar.hide();
25408 mode.enter = function() {
25409 context.connection().authenticate(function(err) {
25413 context.ui().sidebar.show(ui);
25418 mode.exit = function() {
25419 context.ui().sidebar.hide();
25424 iD.modes.Select = function(context, selectedIDs) {
25430 var keybinding = d3.keybinding('select'),
25433 iD.behavior.Copy(context),
25434 iD.behavior.Paste(context),
25435 iD.behavior.Breathe(context),
25436 iD.behavior.Hover(context),
25437 iD.behavior.Select(context),
25438 iD.behavior.Lasso(context),
25439 iD.modes.DragNode(context)
25440 .selectedIDs(selectedIDs)
25444 newFeature = false,
25445 suppressMenu = false;
25447 var wrap = context.container()
25448 .select('.inspector-wrap');
25451 function singular() {
25452 if (selectedIDs.length === 1) {
25453 return context.hasEntity(selectedIDs[0]);
25457 function closeMenu() {
25459 context.surface().call(radialMenu.close);
25463 function positionMenu() {
25464 if (suppressMenu || !radialMenu) { return; }
25466 var entity = singular();
25467 if (entity && context.geometry(entity.id) === 'relation') {
25468 suppressMenu = true;
25469 } else if (entity && entity.type === 'node') {
25470 radialMenu.center(context.projection(entity.loc));
25472 var point = context.mouse(),
25473 viewport = iD.geo.Extent(context.projection.clipExtent()).polygon();
25474 if (iD.geo.pointInPolygon(point, viewport)) {
25475 radialMenu.center(point);
25477 suppressMenu = true;
25482 function showMenu() {
25484 if (!suppressMenu && radialMenu) {
25485 context.surface().call(radialMenu);
25489 function toggleMenu() {
25490 if (d3.select('.radial-menu').empty()) {
25497 mode.selectedIDs = function() {
25498 return selectedIDs;
25501 mode.reselect = function() {
25502 var surfaceNode = context.surface().node();
25503 if (surfaceNode.focus) { // FF doesn't support it
25504 surfaceNode.focus();
25511 mode.newFeature = function(_) {
25512 if (!arguments.length) return newFeature;
25517 mode.suppressMenu = function(_) {
25518 if (!arguments.length) return suppressMenu;
25523 mode.enter = function() {
25524 function update() {
25526 if (_.any(selectedIDs, function(id) { return !context.hasEntity(id); })) {
25527 // Exit mode if selected entity gets undone
25528 context.enter(iD.modes.Browse(context));
25532 function dblclick() {
25533 var target = d3.select(d3.event.target),
25534 datum = target.datum();
25536 if (datum instanceof iD.Way && !target.classed('fill')) {
25537 var choice = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection),
25540 var prev = datum.nodes[choice.index - 1],
25541 next = datum.nodes[choice.index];
25544 iD.actions.AddMidpoint({loc: choice.loc, edge: [prev, next]}, node),
25545 t('operations.add.annotation.vertex'));
25547 d3.event.preventDefault();
25548 d3.event.stopPropagation();
25552 function selectElements(drawn) {
25553 var entity = singular();
25554 if (entity && context.geometry(entity.id) === 'relation') {
25555 suppressMenu = true;
25559 var selection = context.surface()
25560 .selectAll(iD.util.entityOrMemberSelector(selectedIDs, context.graph()));
25562 if (selection.empty()) {
25563 if (drawn) { // Exit mode if selected DOM elements have disappeared..
25564 context.enter(iD.modes.Browse(context));
25568 .classed('selected', true);
25573 if (!context.inIntro()) {
25574 context.enter(iD.modes.Browse(context));
25579 behaviors.forEach(function(behavior) {
25580 context.install(behavior);
25583 var operations = _.without(d3.values(iD.operations), iD.operations.Delete)
25584 .map(function(o) { return o(selectedIDs, context); })
25585 .filter(function(o) { return o.available(); });
25587 operations.unshift(iD.operations.Delete(selectedIDs, context));
25590 .on('⎋', esc, true)
25591 .on('space', toggleMenu);
25593 operations.forEach(function(operation) {
25594 operation.keys.forEach(function(key) {
25595 keybinding.on(key, function() {
25596 if (!(context.inIntro() || operation.disabled())) {
25603 d3.select(document)
25606 radialMenu = iD.ui.RadialMenu(context, operations);
25608 context.ui().sidebar
25609 .select(singular() ? singular().id : null, newFeature);
25612 .on('undone.select', update)
25613 .on('redone.select', update);
25616 .on('move.select', closeMenu)
25617 .on('drawn.select', selectElements);
25621 var show = d3.event && !suppressMenu;
25627 timeout = window.setTimeout(function() {
25633 .on('dblclick.select', dblclick);
25636 if (selectedIDs.length > 1) {
25637 var entities = iD.ui.SelectionList(context, selectedIDs);
25638 context.ui().sidebar.show(entities);
25642 mode.exit = function() {
25643 if (timeout) window.clearTimeout(timeout);
25645 if (inspector) wrap.call(inspector.close);
25647 behaviors.forEach(function(behavior) {
25648 context.uninstall(behavior);
25653 radialMenu = undefined;
25656 .on('undone.select', null)
25657 .on('redone.select', null);
25660 .on('dblclick.select', null)
25661 .selectAll('.selected')
25662 .classed('selected', false);
25664 context.map().on('drawn.select', null);
25665 context.ui().sidebar.hide();
25670 iD.operations = {};
25671 iD.operations.Circularize = function(selectedIDs, context) {
25672 var entityId = selectedIDs[0],
25673 entity = context.entity(entityId),
25674 extent = entity.extent(context.graph()),
25675 geometry = context.geometry(entityId),
25676 action = iD.actions.Circularize(entityId, context.projection);
25678 var operation = function() {
25679 var annotation = t('operations.circularize.annotation.' + geometry);
25680 context.perform(action, annotation);
25683 operation.available = function() {
25684 return selectedIDs.length === 1 &&
25685 entity.type === 'way' &&
25686 _.uniq(entity.nodes).length > 1;
25689 operation.disabled = function() {
25691 if (extent.percentContainedIn(context.extent()) < 0.8) {
25692 reason = 'too_large';
25693 } else if (context.hasHiddenConnections(entityId)) {
25694 reason = 'connected_to_hidden';
25696 return action.disabled(context.graph()) || reason;
25699 operation.tooltip = function() {
25700 var disable = operation.disabled();
25702 t('operations.circularize.' + disable) :
25703 t('operations.circularize.description.' + geometry);
25706 operation.id = 'circularize';
25707 operation.keys = [t('operations.circularize.key')];
25708 operation.title = t('operations.circularize.title');
25712 iD.operations.Continue = function(selectedIDs, context) {
25713 var graph = context.graph(),
25714 entities = selectedIDs.map(function(id) { return graph.entity(id); }),
25715 geometries = _.extend({line: [], vertex: []},
25716 _.groupBy(entities, function(entity) { return entity.geometry(graph); })),
25717 vertex = geometries.vertex[0];
25719 function candidateWays() {
25720 return graph.parentWays(vertex).filter(function(parent) {
25721 return parent.geometry(graph) === 'line' &&
25722 parent.affix(vertex.id) &&
25723 (geometries.line.length === 0 || geometries.line[0] === parent);
25727 var operation = function() {
25728 var candidate = candidateWays()[0];
25729 context.enter(iD.modes.DrawLine(
25733 candidate.affix(vertex.id)));
25736 operation.available = function() {
25737 return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
25738 !context.features().hasHiddenConnections(vertex, context.graph());
25741 operation.disabled = function() {
25742 var candidates = candidateWays();
25743 if (candidates.length === 0)
25744 return 'not_eligible';
25745 if (candidates.length > 1)
25749 operation.tooltip = function() {
25750 var disable = operation.disabled();
25752 t('operations.continue.' + disable) :
25753 t('operations.continue.description');
25756 operation.id = 'continue';
25757 operation.keys = [t('operations.continue.key')];
25758 operation.title = t('operations.continue.title');
25762 iD.operations.Delete = function(selectedIDs, context) {
25763 var action = iD.actions.DeleteMultiple(selectedIDs);
25765 var operation = function() {
25769 if (selectedIDs.length > 1) {
25770 annotation = t('operations.delete.annotation.multiple', {n: selectedIDs.length});
25773 var id = selectedIDs[0],
25774 entity = context.entity(id),
25775 geometry = context.geometry(id),
25776 parents = context.graph().parentWays(entity),
25777 parent = parents[0];
25779 annotation = t('operations.delete.annotation.' + geometry);
25781 // Select the next closest node in the way.
25782 if (geometry === 'vertex' && parents.length === 1 && parent.nodes.length > 2) {
25783 var nodes = parent.nodes,
25784 i = nodes.indexOf(id);
25788 } else if (i === nodes.length - 1) {
25791 var a = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
25792 b = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
25793 i = a < b ? i - 1 : i + 1;
25796 nextSelectedID = nodes[i];
25800 if (nextSelectedID && context.hasEntity(nextSelectedID)) {
25801 context.enter(iD.modes.Select(context, [nextSelectedID]));
25803 context.enter(iD.modes.Browse(context));
25811 operation.available = function() {
25815 operation.disabled = function() {
25817 if (_.any(selectedIDs, context.hasHiddenConnections)) {
25818 reason = 'connected_to_hidden';
25820 return action.disabled(context.graph()) || reason;
25823 operation.tooltip = function() {
25824 var disable = operation.disabled();
25826 t('operations.delete.' + disable) :
25827 t('operations.delete.description');
25830 operation.id = 'delete';
25831 operation.keys = [iD.ui.cmd('⌘⌫'), iD.ui.cmd('⌘⌦')];
25832 operation.title = t('operations.delete.title');
25836 iD.operations.Disconnect = function(selectedIDs, context) {
25837 var vertices = _.filter(selectedIDs, function vertex(entityId) {
25838 return context.geometry(entityId) === 'vertex';
25841 var entityId = vertices[0],
25842 action = iD.actions.Disconnect(entityId);
25844 if (selectedIDs.length > 1) {
25845 action.limitWays(_.without(selectedIDs, entityId));
25848 var operation = function() {
25849 context.perform(action, t('operations.disconnect.annotation'));
25852 operation.available = function() {
25853 return vertices.length === 1;
25856 operation.disabled = function() {
25858 if (_.any(selectedIDs, context.hasHiddenConnections)) {
25859 reason = 'connected_to_hidden';
25861 return action.disabled(context.graph()) || reason;
25864 operation.tooltip = function() {
25865 var disable = operation.disabled();
25867 t('operations.disconnect.' + disable) :
25868 t('operations.disconnect.description');
25871 operation.id = 'disconnect';
25872 operation.keys = [t('operations.disconnect.key')];
25873 operation.title = t('operations.disconnect.title');
25877 iD.operations.Merge = function(selectedIDs, context) {
25878 var join = iD.actions.Join(selectedIDs),
25879 merge = iD.actions.Merge(selectedIDs),
25880 mergePolygon = iD.actions.MergePolygon(selectedIDs);
25882 var operation = function() {
25883 var annotation = t('operations.merge.annotation', {n: selectedIDs.length}),
25886 if (!join.disabled(context.graph())) {
25888 } else if (!merge.disabled(context.graph())) {
25891 action = mergePolygon;
25894 context.perform(action, annotation);
25895 context.enter(iD.modes.Select(context, selectedIDs.filter(function(id) { return context.hasEntity(id); }))
25896 .suppressMenu(true));
25899 operation.available = function() {
25900 return selectedIDs.length >= 2;
25903 operation.disabled = function() {
25904 return join.disabled(context.graph()) &&
25905 merge.disabled(context.graph()) &&
25906 mergePolygon.disabled(context.graph());
25909 operation.tooltip = function() {
25910 var j = join.disabled(context.graph()),
25911 m = merge.disabled(context.graph()),
25912 p = mergePolygon.disabled(context.graph());
25914 if (j === 'restriction' && m && p)
25915 return t('operations.merge.restriction', {relation: context.presets().item('type/restriction').name()});
25917 if (p === 'incomplete_relation' && j && m)
25918 return t('operations.merge.incomplete_relation');
25921 return t('operations.merge.' + j);
25923 return t('operations.merge.description');
25926 operation.id = 'merge';
25927 operation.keys = [t('operations.merge.key')];
25928 operation.title = t('operations.merge.title');
25932 iD.operations.Move = function(selectedIDs, context) {
25933 var extent = selectedIDs.reduce(function(extent, id) {
25934 return extent.extend(context.entity(id).extent(context.graph()));
25935 }, iD.geo.Extent());
25937 var operation = function() {
25938 context.enter(iD.modes.Move(context, selectedIDs));
25941 operation.available = function() {
25942 return selectedIDs.length > 1 ||
25943 context.entity(selectedIDs[0]).type !== 'node';
25946 operation.disabled = function() {
25948 if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
25949 reason = 'too_large';
25950 } else if (_.any(selectedIDs, context.hasHiddenConnections)) {
25951 reason = 'connected_to_hidden';
25953 return iD.actions.Move(selectedIDs).disabled(context.graph()) || reason;
25956 operation.tooltip = function() {
25957 var disable = operation.disabled();
25959 t('operations.move.' + disable) :
25960 t('operations.move.description');
25963 operation.id = 'move';
25964 operation.keys = [t('operations.move.key')];
25965 operation.title = t('operations.move.title');
25969 iD.operations.Orthogonalize = function(selectedIDs, context) {
25970 var entityId = selectedIDs[0],
25971 entity = context.entity(entityId),
25972 extent = entity.extent(context.graph()),
25973 geometry = context.geometry(entityId),
25974 action = iD.actions.Orthogonalize(entityId, context.projection);
25976 var operation = function() {
25977 var annotation = t('operations.orthogonalize.annotation.' + geometry);
25978 context.perform(action, annotation);
25981 operation.available = function() {
25982 return selectedIDs.length === 1 &&
25983 entity.type === 'way' &&
25984 entity.isClosed() &&
25985 _.uniq(entity.nodes).length > 2;
25988 operation.disabled = function() {
25990 if (extent.percentContainedIn(context.extent()) < 0.8) {
25991 reason = 'too_large';
25992 } else if (context.hasHiddenConnections(entityId)) {
25993 reason = 'connected_to_hidden';
25995 return action.disabled(context.graph()) || reason;
25998 operation.tooltip = function() {
25999 var disable = operation.disabled();
26001 t('operations.orthogonalize.' + disable) :
26002 t('operations.orthogonalize.description.' + geometry);
26005 operation.id = 'orthogonalize';
26006 operation.keys = [t('operations.orthogonalize.key')];
26007 operation.title = t('operations.orthogonalize.title');
26011 iD.operations.Reverse = function(selectedIDs, context) {
26012 var entityId = selectedIDs[0];
26014 var operation = function() {
26016 iD.actions.Reverse(entityId),
26017 t('operations.reverse.annotation'));
26020 operation.available = function() {
26021 return selectedIDs.length === 1 &&
26022 context.geometry(entityId) === 'line';
26025 operation.disabled = function() {
26029 operation.tooltip = function() {
26030 return t('operations.reverse.description');
26033 operation.id = 'reverse';
26034 operation.keys = [t('operations.reverse.key')];
26035 operation.title = t('operations.reverse.title');
26039 iD.operations.Rotate = function(selectedIDs, context) {
26040 var entityId = selectedIDs[0],
26041 entity = context.entity(entityId),
26042 extent = entity.extent(context.graph()),
26043 geometry = context.geometry(entityId);
26045 var operation = function() {
26046 context.enter(iD.modes.RotateWay(context, entityId));
26049 operation.available = function() {
26050 if (selectedIDs.length !== 1 || entity.type !== 'way')
26052 if (geometry === 'area')
26054 if (entity.isClosed() &&
26055 context.graph().parentRelations(entity).some(function(r) { return r.isMultipolygon(); }))
26060 operation.disabled = function() {
26061 if (extent.percentContainedIn(context.extent()) < 0.8) {
26062 return 'too_large';
26063 } else if (context.hasHiddenConnections(entityId)) {
26064 return 'connected_to_hidden';
26070 operation.tooltip = function() {
26071 var disable = operation.disabled();
26073 t('operations.rotate.' + disable) :
26074 t('operations.rotate.description');
26077 operation.id = 'rotate';
26078 operation.keys = [t('operations.rotate.key')];
26079 operation.title = t('operations.rotate.title');
26083 iD.operations.Split = function(selectedIDs, context) {
26084 var vertices = _.filter(selectedIDs, function vertex(entityId) {
26085 return context.geometry(entityId) === 'vertex';
26088 var entityId = vertices[0],
26089 action = iD.actions.Split(entityId);
26091 if (selectedIDs.length > 1) {
26092 action.limitWays(_.without(selectedIDs, entityId));
26095 var operation = function() {
26098 var ways = action.ways(context.graph());
26099 if (ways.length === 1) {
26100 annotation = t('operations.split.annotation.' + context.geometry(ways[0].id));
26102 annotation = t('operations.split.annotation.multiple', {n: ways.length});
26105 var difference = context.perform(action, annotation);
26106 context.enter(iD.modes.Select(context, difference.extantIDs()));
26109 operation.available = function() {
26110 return vertices.length === 1;
26113 operation.disabled = function() {
26115 if (_.any(selectedIDs, context.hasHiddenConnections)) {
26116 reason = 'connected_to_hidden';
26118 return action.disabled(context.graph()) || reason;
26121 operation.tooltip = function() {
26122 var disable = operation.disabled();
26124 return t('operations.split.' + disable);
26127 var ways = action.ways(context.graph());
26128 if (ways.length === 1) {
26129 return t('operations.split.description.' + context.geometry(ways[0].id));
26131 return t('operations.split.description.multiple');
26135 operation.id = 'split';
26136 operation.keys = [t('operations.split.key')];
26137 operation.title = t('operations.split.title');
26141 iD.operations.Straighten = function(selectedIDs, context) {
26142 var entityId = selectedIDs[0],
26143 action = iD.actions.Straighten(entityId, context.projection);
26145 function operation() {
26146 var annotation = t('operations.straighten.annotation');
26147 context.perform(action, annotation);
26150 operation.available = function() {
26151 var entity = context.entity(entityId);
26152 return selectedIDs.length === 1 &&
26153 entity.type === 'way' &&
26154 !entity.isClosed() &&
26155 _.uniq(entity.nodes).length > 2;
26158 operation.disabled = function() {
26160 if (context.hasHiddenConnections(entityId)) {
26161 reason = 'connected_to_hidden';
26163 return action.disabled(context.graph()) || reason;
26166 operation.tooltip = function() {
26167 var disable = operation.disabled();
26169 t('operations.straighten.' + disable) :
26170 t('operations.straighten.description');
26173 operation.id = 'straighten';
26174 operation.keys = [t('operations.straighten.key')];
26175 operation.title = t('operations.straighten.title');
26179 iD.Connection = function(useHttps) {
26180 if (typeof useHttps !== 'boolean') {
26181 useHttps = window.location.protocol === 'https:';
26184 var event = d3.dispatch('authenticating', 'authenticated', 'auth', 'loading', 'loaded'),
26185 protocol = useHttps ? 'https:' : 'http:',
26186 url = protocol + '//www.openstreetmap.org',
26192 url: protocol + '//www.openstreetmap.org',
26193 oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
26194 oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
26195 loading: authenticating,
26196 done: authenticated
26200 memberStr = 'member',
26203 relationStr = 'relation',
26208 connection.changesetURL = function(changesetId) {
26209 return url + '/changeset/' + changesetId;
26212 connection.changesetsURL = function(center, zoom) {
26213 var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
26214 return url + '/history#map=' +
26215 Math.floor(zoom) + '/' +
26216 center[1].toFixed(precision) + '/' +
26217 center[0].toFixed(precision);
26220 connection.entityURL = function(entity) {
26221 return url + '/' + entity.type + '/' + entity.osmId();
26224 connection.userURL = function(username) {
26225 return url + '/user/' + username;
26228 connection.loadFromURL = function(url, callback) {
26229 function done(err, dom) {
26230 return callback(err, parse(dom));
26232 return d3.xml(url).get(done);
26235 connection.loadEntity = function(id, callback) {
26236 var type = iD.Entity.id.type(id),
26237 osmID = iD.Entity.id.toOSM(id);
26239 connection.loadFromURL(
26240 url + '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
26241 function(err, entities) {
26242 if (callback) callback(err, {data: entities});
26246 connection.loadEntityVersion = function(id, version, callback) {
26247 var type = iD.Entity.id.type(id),
26248 osmID = iD.Entity.id.toOSM(id);
26250 connection.loadFromURL(
26251 url + '/api/0.6/' + type + '/' + osmID + '/' + version,
26252 function(err, entities) {
26253 if (callback) callback(err, {data: entities});
26257 connection.loadMultiple = function(ids, callback) {
26258 _.each(_.groupBy(_.uniq(ids), iD.Entity.id.type), function(v, k) {
26259 var type = k + 's',
26260 osmIDs = _.map(v, iD.Entity.id.toOSM);
26262 _.each(_.chunk(osmIDs, 150), function(arr) {
26263 connection.loadFromURL(
26264 url + '/api/0.6/' + type + '?' + type + '=' + arr.join(),
26265 function(err, entities) {
26266 if (callback) callback(err, {data: entities});
26272 function authenticating() {
26273 event.authenticating();
26276 function authenticated() {
26277 event.authenticated();
26280 function getLoc(attrs) {
26281 var lon = attrs.lon && attrs.lon.value,
26282 lat = attrs.lat && attrs.lat.value;
26283 return [parseFloat(lon), parseFloat(lat)];
26286 function getNodes(obj) {
26287 var elems = obj.getElementsByTagName(ndStr),
26288 nodes = new Array(elems.length);
26289 for (var i = 0, l = elems.length; i < l; i++) {
26290 nodes[i] = 'n' + elems[i].attributes.ref.value;
26295 function getTags(obj) {
26296 var elems = obj.getElementsByTagName(tagStr),
26298 for (var i = 0, l = elems.length; i < l; i++) {
26299 var attrs = elems[i].attributes;
26300 tags[attrs.k.value] = attrs.v.value;
26305 function getMembers(obj) {
26306 var elems = obj.getElementsByTagName(memberStr),
26307 members = new Array(elems.length);
26308 for (var i = 0, l = elems.length; i < l; i++) {
26309 var attrs = elems[i].attributes;
26311 id: attrs.type.value[0] + attrs.ref.value,
26312 type: attrs.type.value,
26313 role: attrs.role.value
26319 function getVisible(attrs) {
26320 return (!attrs.visible || attrs.visible.value !== 'false');
26324 node: function nodeData(obj) {
26325 var attrs = obj.attributes;
26326 return new iD.Node({
26327 id: iD.Entity.id.fromOSM(nodeStr, attrs.id.value),
26328 loc: getLoc(attrs),
26329 version: attrs.version.value,
26330 user: attrs.user && attrs.user.value,
26331 tags: getTags(obj),
26332 visible: getVisible(attrs)
26336 way: function wayData(obj) {
26337 var attrs = obj.attributes;
26338 return new iD.Way({
26339 id: iD.Entity.id.fromOSM(wayStr, attrs.id.value),
26340 version: attrs.version.value,
26341 user: attrs.user && attrs.user.value,
26342 tags: getTags(obj),
26343 nodes: getNodes(obj),
26344 visible: getVisible(attrs)
26348 relation: function relationData(obj) {
26349 var attrs = obj.attributes;
26350 return new iD.Relation({
26351 id: iD.Entity.id.fromOSM(relationStr, attrs.id.value),
26352 version: attrs.version.value,
26353 user: attrs.user && attrs.user.value,
26354 tags: getTags(obj),
26355 members: getMembers(obj),
26356 visible: getVisible(attrs)
26361 function parse(dom) {
26362 if (!dom || !dom.childNodes) return;
26364 var root = dom.childNodes[0],
26365 children = root.childNodes,
26368 for (var i = 0, l = children.length; i < l; i++) {
26369 var child = children[i],
26370 parser = parsers[child.nodeName];
26372 entities.push(parser(child));
26379 connection.authenticated = function() {
26380 return oauth.authenticated();
26383 // Generate Changeset XML. Returns a string.
26384 connection.changesetJXON = function(tags) {
26388 tag: _.map(tags, function(value, key) {
26389 return { '@k': key, '@v': value };
26398 // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
26399 // XML. Returns a string.
26400 connection.osmChangeJXON = function(changeset_id, changes) {
26401 function nest(x, order) {
26403 for (var i = 0; i < x.length; i++) {
26404 var tagName = Object.keys(x[i])[0];
26405 if (!groups[tagName]) groups[tagName] = [];
26406 groups[tagName].push(x[i][tagName]);
26409 order.forEach(function(o) {
26410 if (groups[o]) ordered[o] = groups[o];
26415 function rep(entity) {
26416 return entity.asJXON(changeset_id);
26422 '@generator': 'iD',
26423 'create': nest(changes.created.map(rep), ['node', 'way', 'relation']),
26424 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
26425 'delete': _.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {'@if-unused': true})
26430 connection.changesetTags = function(comment, imageryUsed) {
26431 var detected = iD.detect(),
26433 created_by: 'iD ' + iD.version,
26434 imagery_used: imageryUsed.join(';').substr(0, 255),
26435 host: (window.location.origin + window.location.pathname).substr(0, 255),
26436 locale: detected.locale
26440 tags.comment = comment.substr(0, 255);
26446 connection.putChangeset = function(changes, comment, imageryUsed, callback) {
26449 path: '/api/0.6/changeset/create',
26450 options: { header: { 'Content-Type': 'text/xml' } },
26451 content: JXON.stringify(connection.changesetJXON(connection.changesetTags(comment, imageryUsed)))
26452 }, function(err, changeset_id) {
26453 if (err) return callback(err);
26456 path: '/api/0.6/changeset/' + changeset_id + '/upload',
26457 options: { header: { 'Content-Type': 'text/xml' } },
26458 content: JXON.stringify(connection.osmChangeJXON(changeset_id, changes))
26460 if (err) return callback(err);
26461 // POST was successful, safe to call the callback.
26462 // Still attempt to close changeset, but ignore response because #2667
26463 // Add delay to allow for postgres replication #1646 #2678
26464 window.setTimeout(function() { callback(null, changeset_id); }, 2500);
26467 path: '/api/0.6/changeset/' + changeset_id + '/close',
26468 options: { header: { 'Content-Type': 'text/xml' } }
26469 }, d3.functor(true));
26474 connection.userDetails = function(callback) {
26476 callback(undefined, userDetails);
26480 function done(err, user_details) {
26481 if (err) return callback(err);
26483 var u = user_details.getElementsByTagName('user')[0],
26484 img = u.getElementsByTagName('img'),
26487 if (img && img[0] && img[0].getAttribute('href')) {
26488 image_url = img[0].getAttribute('href');
26492 display_name: u.attributes.display_name.value,
26493 image_url: image_url,
26494 id: u.attributes.id.value
26497 callback(undefined, userDetails);
26500 oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
26503 connection.userChangesets = function(callback) {
26504 connection.userDetails(function(err, user) {
26505 if (err) return callback(err);
26507 function done(changesets) {
26508 callback(undefined, Array.prototype.map.call(changesets.getElementsByTagName('changeset'),
26509 function (changeset) {
26510 return { tags: getTags(changeset) };
26514 d3.xml(url + '/api/0.6/changesets?user=' + user.id).get()
26516 .on('error', callback);
26520 connection.status = function(callback) {
26521 function done(capabilities) {
26522 var apiStatus = capabilities.getElementsByTagName('status');
26523 callback(undefined, apiStatus[0].getAttribute('api'));
26525 d3.xml(url + '/api/capabilities').get()
26527 .on('error', callback);
26530 function abortRequest(i) { i.abort(); }
26532 connection.tileZoom = function(_) {
26533 if (!arguments.length) return tileZoom;
26538 connection.loadTiles = function(projection, dimensions, callback) {
26542 var s = projection.scale() * 2 * Math.PI,
26543 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
26544 ts = 256 * Math.pow(2, z - tileZoom),
26546 s / 2 - projection.translate()[0],
26547 s / 2 - projection.translate()[1]];
26549 var tiles = d3.geo.tile()
26550 .scaleExtent([tileZoom, tileZoom])
26553 .translate(projection.translate())()
26554 .map(function(tile) {
26555 var x = tile[0] * ts - origin[0],
26556 y = tile[1] * ts - origin[1];
26559 id: tile.toString(),
26560 extent: iD.geo.Extent(
26561 projection.invert([x, y + ts]),
26562 projection.invert([x + ts, y]))
26566 function bboxUrl(tile) {
26567 return url + '/api/0.6/map?bbox=' + tile.extent.toParam();
26570 _.filter(inflight, function(v, i) {
26571 var wanted = _.find(tiles, function(tile) {
26572 return i === tile.id;
26574 if (!wanted) delete inflight[i];
26576 }).map(abortRequest);
26578 tiles.forEach(function(tile) {
26581 if (loadedTiles[id] || inflight[id]) return;
26583 if (_.isEmpty(inflight)) {
26587 inflight[id] = connection.loadFromURL(bboxUrl(tile), function(err, parsed) {
26588 loadedTiles[id] = true;
26589 delete inflight[id];
26591 if (callback) callback(err, _.extend({data: parsed}, tile));
26593 if (_.isEmpty(inflight)) {
26600 connection.switch = function(options) {
26602 oauth.options(_.extend({
26603 loading: authenticating,
26604 done: authenticated
26607 connection.flush();
26611 connection.toggle = function(_) {
26616 connection.flush = function() {
26617 userDetails = undefined;
26618 _.forEach(inflight, abortRequest);
26624 connection.loadedTiles = function(_) {
26625 if (!arguments.length) return loadedTiles;
26630 connection.logout = function() {
26631 userDetails = undefined;
26637 connection.authenticate = function(callback) {
26638 userDetails = undefined;
26639 function done(err, res) {
26641 if (callback) callback(err, res);
26643 return oauth.authenticate(done);
26646 return d3.rebind(connection, event, 'on');
26649 iD.Difference represents the difference between two graphs.
26650 It knows how to calculate the set of entities that were
26651 created, modified, or deleted, and also contains the logic
26652 for recursively extending a difference to the complete set
26653 of entities that will require a redraw, taking into account
26654 child and parent relationships.
26656 iD.Difference = function(base, head) {
26657 var changes = {}, length = 0;
26659 function changed(h, b) {
26660 return h !== b && !_.isEqual(_.omit(h, 'v'), _.omit(b, 'v'));
26663 _.each(head.entities, function(h, id) {
26664 var b = base.entities[id];
26665 if (changed(h, b)) {
26666 changes[id] = {base: b, head: h};
26671 _.each(base.entities, function(b, id) {
26672 var h = head.entities[id];
26673 if (!changes[id] && changed(h, b)) {
26674 changes[id] = {base: b, head: h};
26679 function addParents(parents, result) {
26680 for (var i = 0; i < parents.length; i++) {
26681 var parent = parents[i];
26683 if (parent.id in result)
26686 result[parent.id] = parent;
26687 addParents(head.parentRelations(parent), result);
26691 var difference = {};
26693 difference.length = function() {
26697 difference.changes = function() {
26701 difference.extantIDs = function() {
26703 _.each(changes, function(change, id) {
26704 if (change.head) result.push(id);
26709 difference.modified = function() {
26711 _.each(changes, function(change) {
26712 if (change.base && change.head) result.push(change.head);
26717 difference.created = function() {
26719 _.each(changes, function(change) {
26720 if (!change.base && change.head) result.push(change.head);
26725 difference.deleted = function() {
26727 _.each(changes, function(change) {
26728 if (change.base && !change.head) result.push(change.base);
26733 difference.summary = function() {
26736 function addEntity(entity, graph, changeType) {
26737 relevant[entity.id] = {
26740 changeType: changeType
26744 function addParents(entity) {
26745 var parents = head.parentWays(entity);
26746 for (var j = parents.length - 1; j >= 0; j--) {
26747 var parent = parents[j];
26748 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
26752 _.each(changes, function(change) {
26753 if (change.head && change.head.geometry(head) !== 'vertex') {
26754 addEntity(change.head, head, change.base ? 'modified' : 'created');
26756 } else if (change.base && change.base.geometry(base) !== 'vertex') {
26757 addEntity(change.base, base, 'deleted');
26759 } else if (change.base && change.head) { // modified vertex
26760 var moved = !_.isEqual(change.base.loc, change.head.loc),
26761 retagged = !_.isEqual(change.base.tags, change.head.tags);
26764 addParents(change.head);
26767 if (retagged || (moved && change.head.hasInterestingTags())) {
26768 addEntity(change.head, head, 'modified');
26771 } else if (change.head && change.head.hasInterestingTags()) { // created vertex
26772 addEntity(change.head, head, 'created');
26774 } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
26775 addEntity(change.base, base, 'deleted');
26779 return d3.values(relevant);
26782 difference.complete = function(extent) {
26783 var result = {}, id, change;
26785 for (id in changes) {
26786 change = changes[id];
26788 var h = change.head,
26793 (!h || !h.intersects(extent, head)) &&
26794 (!b || !b.intersects(extent, base)))
26799 if (entity.type === 'way') {
26800 var nh = h ? h.nodes : [],
26801 nb = b ? b.nodes : [],
26804 diff = _.difference(nh, nb);
26805 for (i = 0; i < diff.length; i++) {
26806 result[diff[i]] = head.hasEntity(diff[i]);
26809 diff = _.difference(nb, nh);
26810 for (i = 0; i < diff.length; i++) {
26811 result[diff[i]] = head.hasEntity(diff[i]);
26815 addParents(head.parentWays(entity), result);
26816 addParents(head.parentRelations(entity), result);
26824 iD.Entity = function(attrs) {
26825 // For prototypal inheritance.
26826 if (this instanceof iD.Entity) return;
26828 // Create the appropriate subtype.
26829 if (attrs && attrs.type) {
26830 return iD.Entity[attrs.type].apply(this, arguments);
26831 } else if (attrs && attrs.id) {
26832 return iD.Entity[iD.Entity.id.type(attrs.id)].apply(this, arguments);
26835 // Initialize a generic Entity (used only in tests).
26836 return (new iD.Entity()).initialize(arguments);
26839 iD.Entity.id = function(type) {
26840 return iD.Entity.id.fromOSM(type, iD.Entity.id.next[type]--);
26843 iD.Entity.id.next = {node: -1, way: -1, relation: -1};
26845 iD.Entity.id.fromOSM = function(type, id) {
26846 return type[0] + id;
26849 iD.Entity.id.toOSM = function(id) {
26850 return id.slice(1);
26853 iD.Entity.id.type = function(id) {
26854 return {'n': 'node', 'w': 'way', 'r': 'relation'}[id[0]];
26857 // A function suitable for use as the second argument to d3.selection#data().
26858 iD.Entity.key = function(entity) {
26859 return entity.id + 'v' + (entity.v || 0);
26862 iD.Entity.prototype = {
26865 initialize: function(sources) {
26866 for (var i = 0; i < sources.length; ++i) {
26867 var source = sources[i];
26868 for (var prop in source) {
26869 if (Object.prototype.hasOwnProperty.call(source, prop)) {
26870 if (source[prop] === undefined) {
26873 this[prop] = source[prop];
26879 if (!this.id && this.type) {
26880 this.id = iD.Entity.id(this.type);
26882 if (!this.hasOwnProperty('visible')) {
26883 this.visible = true;
26887 Object.freeze(this);
26888 Object.freeze(this.tags);
26890 if (this.loc) Object.freeze(this.loc);
26891 if (this.nodes) Object.freeze(this.nodes);
26892 if (this.members) Object.freeze(this.members);
26898 copy: function(resolver, copies) {
26899 if (copies[this.id])
26900 return copies[this.id];
26902 var copy = iD.Entity(this, {id: undefined, user: undefined, version: undefined});
26903 copies[this.id] = copy;
26908 osmId: function() {
26909 return iD.Entity.id.toOSM(this.id);
26912 isNew: function() {
26913 return this.osmId() < 0;
26916 update: function(attrs) {
26917 return iD.Entity(this, attrs, {v: 1 + (this.v || 0)});
26920 mergeTags: function(tags) {
26921 var merged = _.clone(this.tags), changed = false;
26922 for (var k in tags) {
26923 var t1 = merged[k],
26928 } else if (t1 !== t2) {
26930 merged[k] = _.union(t1.split(/;\s*/), t2.split(/;\s*/)).join(';');
26933 return changed ? this.update({tags: merged}) : this;
26936 intersects: function(extent, resolver) {
26937 return this.extent(resolver).intersects(extent);
26940 isUsed: function(resolver) {
26941 return _.without(Object.keys(this.tags), 'area').length > 0 ||
26942 resolver.parentRelations(this).length > 0;
26945 hasInterestingTags: function() {
26946 return _.keys(this.tags).some(iD.interestingTag);
26949 isHighwayIntersection: function() {
26953 deprecatedTags: function() {
26954 var tags = _.pairs(this.tags);
26955 var deprecated = {};
26957 iD.data.deprecated.forEach(function(d) {
26958 var match = _.pairs(d.old)[0];
26959 tags.forEach(function(t) {
26960 if (t[0] === match[0] &&
26961 (t[1] === match[1] || match[1] === '*')) {
26962 deprecated[t[0]] = t[1];
26970 iD.Graph = function(other, mutable) {
26971 if (!(this instanceof iD.Graph)) return new iD.Graph(other, mutable);
26973 if (other instanceof iD.Graph) {
26974 var base = other.base();
26975 this.entities = _.assign(Object.create(base.entities), other.entities);
26976 this._parentWays = _.assign(Object.create(base.parentWays), other._parentWays);
26977 this._parentRels = _.assign(Object.create(base.parentRels), other._parentRels);
26980 this.entities = Object.create({});
26981 this._parentWays = Object.create({});
26982 this._parentRels = Object.create({});
26983 this.rebase(other || [], [this]);
26986 this.transients = {};
26987 this._childNodes = {};
26988 this.frozen = !mutable;
26991 iD.Graph.prototype = {
26992 hasEntity: function(id) {
26993 return this.entities[id];
26996 entity: function(id) {
26997 var entity = this.entities[id];
26999 throw new Error('entity ' + id + ' not found');
27004 transient: function(entity, key, fn) {
27005 var id = entity.id,
27006 transients = this.transients[id] ||
27007 (this.transients[id] = {});
27009 if (transients[key] !== undefined) {
27010 return transients[key];
27013 transients[key] = fn.call(entity);
27015 return transients[key];
27018 parentWays: function(entity) {
27019 var parents = this._parentWays[entity.id],
27023 for (var i = 0; i < parents.length; i++) {
27024 result.push(this.entity(parents[i]));
27030 isPoi: function(entity) {
27031 var parentWays = this._parentWays[entity.id];
27032 return !parentWays || parentWays.length === 0;
27035 isShared: function(entity) {
27036 var parentWays = this._parentWays[entity.id];
27037 return parentWays && parentWays.length > 1;
27040 parentRelations: function(entity) {
27041 var parents = this._parentRels[entity.id],
27045 for (var i = 0; i < parents.length; i++) {
27046 result.push(this.entity(parents[i]));
27052 childNodes: function(entity) {
27053 if (this._childNodes[entity.id]) return this._childNodes[entity.id];
27054 if (!entity.nodes) return [];
27057 for (var i = 0; i < entity.nodes.length; i++) {
27058 nodes[i] = this.entity(entity.nodes[i]);
27061 if (iD.debug) Object.freeze(nodes);
27063 this._childNodes[entity.id] = nodes;
27064 return this._childNodes[entity.id];
27069 'entities': iD.util.getPrototypeOf(this.entities),
27070 'parentWays': iD.util.getPrototypeOf(this._parentWays),
27071 'parentRels': iD.util.getPrototypeOf(this._parentRels)
27075 // Unlike other graph methods, rebase mutates in place. This is because it
27076 // is used only during the history operation that merges newly downloaded
27077 // data into each state. To external consumers, it should appear as if the
27078 // graph always contained the newly downloaded data.
27079 rebase: function(entities, stack, force) {
27080 var base = this.base(),
27083 for (i = 0; i < entities.length; i++) {
27084 var entity = entities[i];
27086 if (!entity.visible || (!force && base.entities[entity.id]))
27089 // Merging data into the base graph
27090 base.entities[entity.id] = entity;
27091 this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
27093 // Restore provisionally-deleted nodes that are discovered to have an extant parent
27094 if (entity.type === 'way') {
27095 for (j = 0; j < entity.nodes.length; j++) {
27096 id = entity.nodes[j];
27097 for (k = 1; k < stack.length; k++) {
27098 var ents = stack[k].entities;
27099 if (ents.hasOwnProperty(id) && ents[id] === undefined) {
27107 for (i = 0; i < stack.length; i++) {
27108 stack[i]._updateRebased();
27112 _updateRebased: function() {
27113 var base = this.base(),
27114 i, k, child, id, keys;
27116 keys = Object.keys(this._parentWays);
27117 for (i = 0; i < keys.length; i++) {
27119 if (base.parentWays[child]) {
27120 for (k = 0; k < base.parentWays[child].length; k++) {
27121 id = base.parentWays[child][k];
27122 if (!this.entities.hasOwnProperty(id) && !_.contains(this._parentWays[child], id)) {
27123 this._parentWays[child].push(id);
27129 keys = Object.keys(this._parentRels);
27130 for (i = 0; i < keys.length; i++) {
27132 if (base.parentRels[child]) {
27133 for (k = 0; k < base.parentRels[child].length; k++) {
27134 id = base.parentRels[child][k];
27135 if (!this.entities.hasOwnProperty(id) && !_.contains(this._parentRels[child], id)) {
27136 this._parentRels[child].push(id);
27142 this.transients = {};
27144 // this._childNodes is not updated, under the assumption that
27145 // ways are always downloaded with their child nodes.
27148 // Updates calculated properties (parentWays, parentRels) for the specified change
27149 _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
27151 parentWays = parentWays || this._parentWays;
27152 parentRels = parentRels || this._parentRels;
27154 var type = entity && entity.type || oldentity && oldentity.type,
27155 removed, added, ways, rels, i;
27158 if (type === 'way') {
27160 // Update parentWays
27161 if (oldentity && entity) {
27162 removed = _.difference(oldentity.nodes, entity.nodes);
27163 added = _.difference(entity.nodes, oldentity.nodes);
27164 } else if (oldentity) {
27165 removed = oldentity.nodes;
27167 } else if (entity) {
27169 added = entity.nodes;
27171 for (i = 0; i < removed.length; i++) {
27172 parentWays[removed[i]] = _.without(parentWays[removed[i]], oldentity.id);
27174 for (i = 0; i < added.length; i++) {
27175 ways = _.without(parentWays[added[i]], entity.id);
27176 ways.push(entity.id);
27177 parentWays[added[i]] = ways;
27180 } else if (type === 'relation') {
27182 // Update parentRels
27183 if (oldentity && entity) {
27184 removed = _.difference(oldentity.members, entity.members);
27185 added = _.difference(entity.members, oldentity);
27186 } else if (oldentity) {
27187 removed = oldentity.members;
27189 } else if (entity) {
27191 added = entity.members;
27193 for (i = 0; i < removed.length; i++) {
27194 parentRels[removed[i].id] = _.without(parentRels[removed[i].id], oldentity.id);
27196 for (i = 0; i < added.length; i++) {
27197 rels = _.without(parentRels[added[i].id], entity.id);
27198 rels.push(entity.id);
27199 parentRels[added[i].id] = rels;
27204 replace: function(entity) {
27205 if (this.entities[entity.id] === entity)
27208 return this.update(function() {
27209 this._updateCalculated(this.entities[entity.id], entity);
27210 this.entities[entity.id] = entity;
27214 remove: function(entity) {
27215 return this.update(function() {
27216 this._updateCalculated(entity, undefined);
27217 this.entities[entity.id] = undefined;
27221 revert: function(id) {
27222 var baseEntity = this.base().entities[id],
27223 headEntity = this.entities[id];
27225 if (headEntity === baseEntity)
27228 return this.update(function() {
27229 this._updateCalculated(headEntity, baseEntity);
27230 delete this.entities[id];
27234 update: function() {
27235 var graph = this.frozen ? iD.Graph(this, true) : this;
27237 for (var i = 0; i < arguments.length; i++) {
27238 arguments[i].call(graph, graph);
27241 if (this.frozen) graph.frozen = true;
27246 // Obliterates any existing entities
27247 load: function(entities) {
27248 var base = this.base();
27249 this.entities = Object.create(base.entities);
27251 for (var i in entities) {
27252 this.entities[i] = entities[i];
27253 this._updateCalculated(base.entities[i], this.entities[i]);
27259 iD.History = function(context) {
27260 var stack, index, tree,
27261 imageryUsed = ['Bing'],
27262 dispatch = d3.dispatch('change', 'undone', 'redone'),
27263 lock = iD.util.SessionMutex('lock');
27265 function perform(actions) {
27266 actions = Array.prototype.slice.call(actions);
27270 if (!_.isFunction(_.last(actions))) {
27271 annotation = actions.pop();
27274 var graph = stack[index].graph;
27275 for (var i = 0; i < actions.length; i++) {
27276 graph = actions[i](graph);
27281 annotation: annotation,
27282 imageryUsed: imageryUsed
27286 function change(previous) {
27287 var difference = iD.Difference(previous, history.graph());
27288 dispatch.change(difference);
27292 // iD uses namespaced keys so multiple installations do not conflict
27293 function getKey(n) {
27294 return 'iD_' + window.location.origin + '_' + n;
27298 graph: function() {
27299 return stack[index].graph;
27303 return stack[0].graph;
27306 merge: function(entities, extent) {
27307 stack[0].graph.rebase(entities, _.pluck(stack, 'graph'), false);
27308 tree.rebase(entities, false);
27310 dispatch.change(undefined, extent);
27313 perform: function() {
27314 var previous = stack[index].graph;
27316 stack = stack.slice(0, index + 1);
27317 stack.push(perform(arguments));
27320 return change(previous);
27323 replace: function() {
27324 var previous = stack[index].graph;
27326 // assert(index == stack.length - 1)
27327 stack[index] = perform(arguments);
27329 return change(previous);
27333 var previous = stack[index].graph;
27338 return change(previous);
27342 // Same as calling pop and then perform
27343 overwrite: function() {
27344 var previous = stack[index].graph;
27350 stack = stack.slice(0, index + 1);
27351 stack.push(perform(arguments));
27354 return change(previous);
27358 var previous = stack[index].graph;
27360 // Pop to the next annotated state.
27361 while (index > 0) {
27363 if (stack[index].annotation) break;
27367 return change(previous);
27371 var previous = stack[index].graph;
27373 while (index < stack.length - 1) {
27375 if (stack[index].annotation) break;
27379 return change(previous);
27382 undoAnnotation: function() {
27385 if (stack[i].annotation) return stack[i].annotation;
27390 redoAnnotation: function() {
27392 while (i <= stack.length - 1) {
27393 if (stack[i].annotation) return stack[i].annotation;
27398 intersects: function(extent) {
27399 return tree.intersects(extent, stack[index].graph);
27402 difference: function() {
27403 var base = stack[0].graph,
27404 head = stack[index].graph;
27405 return iD.Difference(base, head);
27408 changes: function(action) {
27409 var base = stack[0].graph,
27410 head = stack[index].graph;
27413 head = action(head);
27416 var difference = iD.Difference(base, head);
27419 modified: difference.modified(),
27420 created: difference.created(),
27421 deleted: difference.deleted()
27425 validate: function(changes) {
27426 return _(iD.validations)
27427 .map(function(fn) { return fn()(changes, stack[index].graph); })
27432 hasChanges: function() {
27433 return this.difference().length() > 0;
27436 imageryUsed: function(sources) {
27438 imageryUsed = sources;
27441 return _(stack.slice(1, index + 1))
27442 .pluck('imageryUsed')
27445 .without(undefined, 'Custom')
27450 reset: function() {
27451 stack = [{graph: iD.Graph()}];
27453 tree = iD.Tree(stack[0].graph);
27458 toJSON: function() {
27459 if (!this.hasChanges()) return;
27461 var allEntities = {},
27465 var s = stack.map(function(i) {
27466 var modified = [], deleted = [];
27468 _.forEach(i.graph.entities, function(entity, id) {
27470 var key = iD.Entity.key(entity);
27471 allEntities[key] = entity;
27472 modified.push(key);
27477 // make sure that the originals of changed or deleted entities get merged
27478 // into the base of the stack after restoring the data from JSON.
27479 if (id in base.graph.entities) {
27480 baseEntities[id] = base.graph.entities[id];
27482 // get originals of parent entities too
27483 _.forEach(base.graph._parentWays[id], function(parentId) {
27484 if (parentId in base.graph.entities) {
27485 baseEntities[parentId] = base.graph.entities[parentId];
27492 if (modified.length) x.modified = modified;
27493 if (deleted.length) x.deleted = deleted;
27494 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
27495 if (i.annotation) x.annotation = i.annotation;
27500 return JSON.stringify({
27502 entities: _.values(allEntities),
27503 baseEntities: _.values(baseEntities),
27505 nextIDs: iD.Entity.id.next,
27510 fromJSON: function(json, loadChildNodes) {
27511 var h = JSON.parse(json),
27512 loadComplete = true;
27514 iD.Entity.id.next = h.nextIDs;
27517 if (h.version === 2 || h.version === 3) {
27518 var allEntities = {};
27520 h.entities.forEach(function(entity) {
27521 allEntities[iD.Entity.key(entity)] = iD.Entity(entity);
27524 if (h.version === 3) {
27525 // This merges originals for changed entities into the base of
27526 // the stack even if the current stack doesn't have them (for
27527 // example when iD has been restarted in a different region)
27528 var baseEntities = h.baseEntities.map(function(d) { return iD.Entity(d); });
27529 stack[0].graph.rebase(baseEntities, _.pluck(stack, 'graph'), true);
27530 tree.rebase(baseEntities, true);
27532 // When we restore a modified way, we also need to fetch any missing
27533 // childnodes that would normally have been downloaded with it.. #2142
27534 if (loadChildNodes) {
27535 var missing = _(baseEntities)
27536 .filter('type', 'way')
27540 .reject(function(n) { return stack[0].graph.hasEntity(n); })
27543 if (!_.isEmpty(missing)) {
27544 loadComplete = false;
27545 context.redrawEnable(false);
27547 var loading = iD.ui.Loading(context).blocking(true);
27548 context.container().call(loading);
27550 var childNodesLoaded = function(err, result) {
27552 var visible = _.groupBy(result.data, 'visible');
27553 if (!_.isEmpty(visible.true)) {
27554 missing = _.difference(missing, _.pluck(visible.true, 'id'));
27555 stack[0].graph.rebase(visible.true, _.pluck(stack, 'graph'), true);
27556 tree.rebase(visible.true, true);
27559 // fetch older versions of nodes that were deleted..
27560 _.each(visible.false, function(entity) {
27561 context.connection()
27562 .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
27566 if (err || _.isEmpty(missing)) {
27568 context.redrawEnable(true);
27573 context.connection().loadMultiple(missing, childNodesLoaded);
27578 stack = h.stack.map(function(d) {
27579 var entities = {}, entity;
27582 d.modified.forEach(function(key) {
27583 entity = allEntities[key];
27584 entities[entity.id] = entity;
27589 d.deleted.forEach(function(id) {
27590 entities[id] = undefined;
27595 graph: iD.Graph(stack[0].graph).load(entities),
27596 annotation: d.annotation,
27597 imageryUsed: d.imageryUsed
27601 } else { // original version
27602 stack = h.stack.map(function(d) {
27605 for (var i in d.entities) {
27606 var entity = d.entities[i];
27607 entities[i] = entity === 'undefined' ? undefined : iD.Entity(entity);
27610 d.graph = iD.Graph(stack[0].graph).load(entities);
27615 if (loadComplete) {
27623 if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
27627 clearSaved: function() {
27628 context.debouncedSave.cancel();
27629 if (lock.locked()) context.storage(getKey('saved_history'), null);
27634 return lock.lock();
27637 unlock: function() {
27641 // is iD not open in another window and it detects that
27642 // there's a history stored in localStorage that's recoverable?
27643 restorableChanges: function() {
27644 return lock.locked() && !!context.storage(getKey('saved_history'));
27647 // load history from a version stored in localStorage
27648 restore: function() {
27649 if (!lock.locked()) return;
27651 var json = context.storage(getKey('saved_history'));
27652 if (json) history.fromJSON(json, true);
27661 return d3.rebind(history, dispatch, 'on');
27663 iD.Node = iD.Entity.node = function iD_Node() {
27664 if (!(this instanceof iD_Node)) {
27665 return (new iD_Node()).initialize(arguments);
27666 } else if (arguments.length) {
27667 this.initialize(arguments);
27671 iD.Node.prototype = Object.create(iD.Entity.prototype);
27673 _.extend(iD.Node.prototype, {
27676 extent: function() {
27677 return new iD.geo.Extent(this.loc);
27680 geometry: function(graph) {
27681 return graph.transient(this, 'geometry', function() {
27682 return graph.isPoi(this) ? 'point' : 'vertex';
27686 move: function(loc) {
27687 return this.update({loc: loc});
27690 isIntersection: function(resolver) {
27691 return resolver.transient(this, 'isIntersection', function() {
27692 return resolver.parentWays(this).filter(function(parent) {
27693 return (parent.tags.highway ||
27694 parent.tags.waterway ||
27695 parent.tags.railway ||
27696 parent.tags.aeroway) &&
27697 parent.geometry(resolver) === 'line';
27702 isHighwayIntersection: function(resolver) {
27703 return resolver.transient(this, 'isHighwayIntersection', function() {
27704 return resolver.parentWays(this).filter(function(parent) {
27705 return parent.tags.highway && parent.geometry(resolver) === 'line';
27710 asJXON: function(changeset_id) {
27713 '@id': this.osmId(),
27714 '@lon': this.loc[0],
27715 '@lat': this.loc[1],
27716 '@version': (this.version || 0),
27717 tag: _.map(this.tags, function(v, k) {
27718 return { keyAttributes: { k: k, v: v } };
27722 if (changeset_id) r.node['@changeset'] = changeset_id;
27726 asGeoJSON: function() {
27729 coordinates: this.loc
27733 iD.Relation = iD.Entity.relation = function iD_Relation() {
27734 if (!(this instanceof iD_Relation)) {
27735 return (new iD_Relation()).initialize(arguments);
27736 } else if (arguments.length) {
27737 this.initialize(arguments);
27741 iD.Relation.prototype = Object.create(iD.Entity.prototype);
27743 iD.Relation.creationOrder = function(a, b) {
27744 var aId = parseInt(iD.Entity.id.toOSM(a.id), 10);
27745 var bId = parseInt(iD.Entity.id.toOSM(b.id), 10);
27747 if (aId < 0 || bId < 0) return aId - bId;
27751 _.extend(iD.Relation.prototype, {
27755 copy: function(resolver, copies) {
27756 if (copies[this.id])
27757 return copies[this.id];
27759 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
27761 var members = this.members.map(function(member) {
27762 return _.extend({}, member, {id: resolver.entity(member.id).copy(resolver, copies).id});
27765 copy = copy.update({members: members});
27766 copies[this.id] = copy;
27771 extent: function(resolver, memo) {
27772 return resolver.transient(this, 'extent', function() {
27773 if (memo && memo[this.id]) return iD.geo.Extent();
27775 memo[this.id] = true;
27777 var extent = iD.geo.Extent();
27778 for (var i = 0; i < this.members.length; i++) {
27779 var member = resolver.hasEntity(this.members[i].id);
27781 extent._extend(member.extent(resolver, memo));
27788 geometry: function(graph) {
27789 return graph.transient(this, 'geometry', function() {
27790 return this.isMultipolygon() ? 'area' : 'relation';
27794 isDegenerate: function() {
27795 return this.members.length === 0;
27798 // Return an array of members, each extended with an 'index' property whose value
27799 // is the member index.
27800 indexedMembers: function() {
27801 var result = new Array(this.members.length);
27802 for (var i = 0; i < this.members.length; i++) {
27803 result[i] = _.extend({}, this.members[i], {index: i});
27808 // Return the first member with the given role. A copy of the member object
27809 // is returned, extended with an 'index' property whose value is the member index.
27810 memberByRole: function(role) {
27811 for (var i = 0; i < this.members.length; i++) {
27812 if (this.members[i].role === role) {
27813 return _.extend({}, this.members[i], {index: i});
27818 // Return the first member with the given id. A copy of the member object
27819 // is returned, extended with an 'index' property whose value is the member index.
27820 memberById: function(id) {
27821 for (var i = 0; i < this.members.length; i++) {
27822 if (this.members[i].id === id) {
27823 return _.extend({}, this.members[i], {index: i});
27828 // Return the first member with the given id and role. A copy of the member object
27829 // is returned, extended with an 'index' property whose value is the member index.
27830 memberByIdAndRole: function(id, role) {
27831 for (var i = 0; i < this.members.length; i++) {
27832 if (this.members[i].id === id && this.members[i].role === role) {
27833 return _.extend({}, this.members[i], {index: i});
27838 addMember: function(member, index) {
27839 var members = this.members.slice();
27840 members.splice(index === undefined ? members.length : index, 0, member);
27841 return this.update({members: members});
27844 updateMember: function(member, index) {
27845 var members = this.members.slice();
27846 members.splice(index, 1, _.extend({}, members[index], member));
27847 return this.update({members: members});
27850 removeMember: function(index) {
27851 var members = this.members.slice();
27852 members.splice(index, 1);
27853 return this.update({members: members});
27856 removeMembersWithID: function(id) {
27857 var members = _.reject(this.members, function(m) { return m.id === id; });
27858 return this.update({members: members});
27861 // Wherever a member appears with id `needle.id`, replace it with a member
27862 // with id `replacement.id`, type `replacement.type`, and the original role,
27863 // unless a member already exists with that id and role. Return an updated
27865 replaceMember: function(needle, replacement) {
27866 if (!this.memberById(needle.id))
27871 for (var i = 0; i < this.members.length; i++) {
27872 var member = this.members[i];
27873 if (member.id !== needle.id) {
27874 members.push(member);
27875 } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
27876 members.push({id: replacement.id, type: replacement.type, role: member.role});
27880 return this.update({members: members});
27883 asJXON: function(changeset_id) {
27886 '@id': this.osmId(),
27887 '@version': this.version || 0,
27888 member: _.map(this.members, function(member) {
27889 return { keyAttributes: { type: member.type, role: member.role, ref: iD.Entity.id.toOSM(member.id) } };
27891 tag: _.map(this.tags, function(v, k) {
27892 return { keyAttributes: { k: k, v: v } };
27896 if (changeset_id) r.relation['@changeset'] = changeset_id;
27900 asGeoJSON: function(resolver) {
27901 return resolver.transient(this, 'GeoJSON', function () {
27902 if (this.isMultipolygon()) {
27904 type: 'MultiPolygon',
27905 coordinates: this.multipolygon(resolver)
27909 type: 'FeatureCollection',
27910 properties: this.tags,
27911 features: this.members.map(function (member) {
27912 return _.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
27919 area: function(resolver) {
27920 return resolver.transient(this, 'area', function() {
27921 return d3.geo.area(this.asGeoJSON(resolver));
27925 isMultipolygon: function() {
27926 return this.tags.type === 'multipolygon';
27929 isComplete: function(resolver) {
27930 for (var i = 0; i < this.members.length; i++) {
27931 if (!resolver.hasEntity(this.members[i].id)) {
27938 isRestriction: function() {
27939 return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
27942 // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
27943 // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
27945 // This corresponds to the structure needed for rendering a multipolygon path using a
27946 // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
27948 // In the case of invalid geometries, this function will still return a result which
27949 // includes the nodes of all way members, but some Nds may be unclosed and some inner
27950 // rings not matched with the intended outer ring.
27952 multipolygon: function(resolver) {
27953 var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
27954 inners = this.members.filter(function(m) { return 'inner' === m.role; });
27956 outers = iD.geo.joinWays(outers, resolver);
27957 inners = iD.geo.joinWays(inners, resolver);
27959 outers = outers.map(function(outer) { return _.pluck(outer.nodes, 'loc'); });
27960 inners = inners.map(function(inner) { return _.pluck(inner.nodes, 'loc'); });
27962 var result = outers.map(function(o) {
27963 // Heuristic for detecting counterclockwise winding order. Assumes
27964 // that OpenStreetMap polygons are not hemisphere-spanning.
27965 return [d3.geo.area({type: 'Polygon', coordinates: [o]}) > 2 * Math.PI ? o.reverse() : o];
27968 function findOuter(inner) {
27971 for (o = 0; o < outers.length; o++) {
27973 if (iD.geo.polygonContainsPolygon(outer, inner))
27977 for (o = 0; o < outers.length; o++) {
27979 if (iD.geo.polygonIntersectsPolygon(outer, inner))
27984 for (var i = 0; i < inners.length; i++) {
27985 var inner = inners[i];
27987 if (d3.geo.area({type: 'Polygon', coordinates: [inner]}) < 2 * Math.PI) {
27988 inner = inner.reverse();
27991 var o = findOuter(inners[i]);
27992 if (o !== undefined)
27993 result[o].push(inners[i]);
27995 result.push([inners[i]]); // Invalid geometry
28003 'chair_lift': true,
28004 'mixed_lift': true,
28009 'magic_carpet': true,
28014 'motorway_link': true
28020 'piste:halfpipe': true
28044 iD.interestingTag = function (key) {
28045 return key !== 'attribution' &&
28046 key !== 'created_by' &&
28047 key !== 'source' &&
28049 key.indexOf('tiger:') !== 0;
28052 iD.Tree = function(head) {
28053 var rtree = rbush(),
28056 function entityRectangle(entity) {
28057 var rect = entity.extent(head).rectangle();
28058 rect.id = entity.id;
28059 rectangles[entity.id] = rect;
28063 function updateParents(entity, insertions, memo) {
28064 head.parentWays(entity).forEach(function(way) {
28065 if (rectangles[way.id]) {
28066 rtree.remove(rectangles[way.id]);
28067 insertions[way.id] = way;
28069 updateParents(way, insertions, memo);
28072 head.parentRelations(entity).forEach(function(relation) {
28073 if (memo[entity.id]) return;
28074 memo[entity.id] = true;
28075 if (rectangles[relation.id]) {
28076 rtree.remove(rectangles[relation.id]);
28077 insertions[relation.id] = relation;
28079 updateParents(relation, insertions, memo);
28085 tree.rebase = function(entities, force) {
28086 var insertions = {};
28088 for (var i = 0; i < entities.length; i++) {
28089 var entity = entities[i];
28091 if (!entity.visible)
28094 if (head.entities.hasOwnProperty(entity.id) || rectangles[entity.id]) {
28097 } else if (rectangles[entity.id]) {
28098 rtree.remove(rectangles[entity.id]);
28102 insertions[entity.id] = entity;
28103 updateParents(entity, insertions, {});
28106 rtree.load(_.map(insertions, entityRectangle));
28111 tree.intersects = function(extent, graph) {
28112 if (graph !== head) {
28113 var diff = iD.Difference(head, graph),
28118 diff.deleted().forEach(function(entity) {
28119 rtree.remove(rectangles[entity.id]);
28120 delete rectangles[entity.id];
28123 diff.modified().forEach(function(entity) {
28124 rtree.remove(rectangles[entity.id]);
28125 insertions[entity.id] = entity;
28126 updateParents(entity, insertions, {});
28129 diff.created().forEach(function(entity) {
28130 insertions[entity.id] = entity;
28133 rtree.load(_.map(insertions, entityRectangle));
28136 return rtree.search(extent.rectangle()).map(function(rect) {
28137 return head.entity(rect.id);
28143 iD.Way = iD.Entity.way = function iD_Way() {
28144 if (!(this instanceof iD_Way)) {
28145 return (new iD_Way()).initialize(arguments);
28146 } else if (arguments.length) {
28147 this.initialize(arguments);
28151 iD.Way.prototype = Object.create(iD.Entity.prototype);
28153 _.extend(iD.Way.prototype, {
28157 copy: function(resolver, copies) {
28158 if (copies[this.id])
28159 return copies[this.id];
28161 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
28163 var nodes = this.nodes.map(function(id) {
28164 return resolver.entity(id).copy(resolver, copies).id;
28167 copy = copy.update({nodes: nodes});
28168 copies[this.id] = copy;
28173 extent: function(resolver) {
28174 return resolver.transient(this, 'extent', function() {
28175 var extent = iD.geo.Extent();
28176 for (var i = 0; i < this.nodes.length; i++) {
28177 var node = resolver.hasEntity(this.nodes[i]);
28179 extent._extend(node.extent());
28186 first: function() {
28187 return this.nodes[0];
28191 return this.nodes[this.nodes.length - 1];
28194 contains: function(node) {
28195 return this.nodes.indexOf(node) >= 0;
28198 affix: function(node) {
28199 if (this.nodes[0] === node) return 'prefix';
28200 if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
28203 layer: function() {
28204 // explicit layer tag, clamp between -10, 10..
28205 if (this.tags.layer !== undefined) {
28206 return Math.max(-10, Math.min(+(this.tags.layer), 10));
28209 // implied layer tag..
28210 if (this.tags.location === 'overground') return 1;
28211 if (this.tags.location === 'underground') return -1;
28212 if (this.tags.location === 'underwater') return -10;
28214 if (this.tags.power === 'line') return 10;
28215 if (this.tags.power === 'minor_line') return 10;
28216 if (this.tags.aerialway) return 10;
28217 if (this.tags.bridge) return 1;
28218 if (this.tags.cutting) return -1;
28219 if (this.tags.tunnel) return -1;
28220 if (this.tags.waterway) return -1;
28221 if (this.tags.man_made === 'pipeline') return -10;
28222 if (this.tags.boundary) return -10;
28226 isOneWay: function() {
28227 // explicit oneway tag..
28228 if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
28229 if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
28231 // implied oneway tag..
28232 for (var key in this.tags) {
28233 if (key in iD.oneWayTags && (this.tags[key] in iD.oneWayTags[key]))
28239 isClosed: function() {
28240 return this.nodes.length > 0 && this.first() === this.last();
28243 isConvex: function(resolver) {
28244 if (!this.isClosed() || this.isDegenerate()) return null;
28246 var nodes = _.uniq(resolver.childNodes(this)),
28247 coords = _.pluck(nodes, 'loc'),
28248 curr = 0, prev = 0;
28250 for (var i = 0; i < coords.length; i++) {
28251 var o = coords[(i+1) % coords.length],
28253 b = coords[(i+2) % coords.length],
28254 res = iD.geo.cross(o, a, b);
28256 curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
28259 } else if (prev && curr !== prev) {
28267 isArea: function() {
28268 if (this.tags.area === 'yes')
28270 if (!this.isClosed() || this.tags.area === 'no')
28272 for (var key in this.tags)
28273 if (key in iD.areaKeys && !(this.tags[key] in iD.areaKeys[key]))
28278 isDegenerate: function() {
28279 return _.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
28282 areAdjacent: function(n1, n2) {
28283 for (var i = 0; i < this.nodes.length; i++) {
28284 if (this.nodes[i] === n1) {
28285 if (this.nodes[i - 1] === n2) return true;
28286 if (this.nodes[i + 1] === n2) return true;
28292 geometry: function(graph) {
28293 return graph.transient(this, 'geometry', function() {
28294 return this.isArea() ? 'area' : 'line';
28298 addNode: function(id, index) {
28299 var nodes = this.nodes.slice();
28300 nodes.splice(index === undefined ? nodes.length : index, 0, id);
28301 return this.update({nodes: nodes});
28304 updateNode: function(id, index) {
28305 var nodes = this.nodes.slice();
28306 nodes.splice(index, 1, id);
28307 return this.update({nodes: nodes});
28310 replaceNode: function(needle, replacement) {
28311 if (this.nodes.indexOf(needle) < 0)
28314 var nodes = this.nodes.slice();
28315 for (var i = 0; i < nodes.length; i++) {
28316 if (nodes[i] === needle) {
28317 nodes[i] = replacement;
28320 return this.update({nodes: nodes});
28323 removeNode: function(id) {
28326 for (var i = 0; i < this.nodes.length; i++) {
28327 var node = this.nodes[i];
28328 if (node !== id && nodes[nodes.length - 1] !== node) {
28333 // Preserve circularity
28334 if (this.nodes.length > 1 && this.first() === id && this.last() === id && nodes[nodes.length - 1] !== nodes[0]) {
28335 nodes.push(nodes[0]);
28338 return this.update({nodes: nodes});
28341 asJXON: function(changeset_id) {
28344 '@id': this.osmId(),
28345 '@version': this.version || 0,
28346 nd: _.map(this.nodes, function(id) {
28347 return { keyAttributes: { ref: iD.Entity.id.toOSM(id) } };
28349 tag: _.map(this.tags, function(v, k) {
28350 return { keyAttributes: { k: k, v: v } };
28354 if (changeset_id) r.way['@changeset'] = changeset_id;
28358 asGeoJSON: function(resolver) {
28359 return resolver.transient(this, 'GeoJSON', function() {
28360 var coordinates = _.pluck(resolver.childNodes(this), 'loc');
28361 if (this.isArea() && this.isClosed()) {
28364 coordinates: [coordinates]
28368 type: 'LineString',
28369 coordinates: coordinates
28375 area: function(resolver) {
28376 return resolver.transient(this, 'area', function() {
28377 var nodes = resolver.childNodes(this);
28381 coordinates: [_.pluck(nodes, 'loc')]
28384 if (!this.isClosed() && nodes.length) {
28385 json.coordinates[0].push(nodes[0].loc);
28388 var area = d3.geo.area(json);
28390 // Heuristic for detecting counterclockwise winding order. Assumes
28391 // that OpenStreetMap polygons are not hemisphere-spanning.
28392 if (area > 2 * Math.PI) {
28393 json.coordinates[0] = json.coordinates[0].reverse();
28394 area = d3.geo.area(json);
28397 return isNaN(area) ? 0 : area;
28401 iD.Background = function(context) {
28402 var dispatch = d3.dispatch('change'),
28403 baseLayer = iD.TileLayer().projection(context.projection),
28404 overlayLayers = [],
28408 function findSource(id) {
28409 return _.find(backgroundSources, function(d) {
28410 return d.id && d.id === id;
28415 function background(selection) {
28416 var base = selection.selectAll('.layer-background')
28420 .insert('div', '.layer-data')
28421 .attr('class', 'layer layer-background');
28423 base.call(baseLayer);
28425 var overlays = selection.selectAll('.layer-overlay')
28426 .data(overlayLayers, function(d) { return d.source().name(); });
28429 .insert('div', '.layer-data')
28430 .attr('class', 'layer layer-overlay');
28432 overlays.each(function(layer) {
28433 d3.select(this).call(layer);
28441 background.updateImagery = function() {
28442 var b = background.baseLayerSource(),
28443 o = overlayLayers.map(function (d) { return d.source().id; }).join(','),
28444 q = iD.util.stringQs(location.hash.substring(1));
28447 if (id === 'custom') {
28448 id = 'custom:' + b.template;
28454 delete q.background;
28463 location.replace('#' + iD.util.qsString(q, true));
28465 var imageryUsed = [b.imageryUsed()];
28467 overlayLayers.forEach(function (d) {
28468 var source = d.source();
28469 if (!source.isLocatorOverlay()) {
28470 imageryUsed.push(source.imageryUsed());
28474 var gpx = context.layers().layer('gpx');
28475 if (gpx && gpx.enabled() && gpx.hasGpx()) {
28476 imageryUsed.push('Local GPX');
28479 context.history().imageryUsed(imageryUsed);
28482 background.sources = function(extent) {
28483 return backgroundSources.filter(function(source) {
28484 return source.intersects(extent);
28488 background.dimensions = function(_) {
28489 baseLayer.dimensions(_);
28491 overlayLayers.forEach(function(layer) {
28492 layer.dimensions(_);
28496 background.baseLayerSource = function(d) {
28497 if (!arguments.length) return baseLayer.source();
28499 baseLayer.source(d);
28501 background.updateImagery();
28506 background.bing = function() {
28507 background.baseLayerSource(findSource('Bing'));
28510 background.showsLayer = function(d) {
28511 return d === baseLayer.source() ||
28512 (d.id === 'custom' && baseLayer.source().id === 'custom') ||
28513 overlayLayers.some(function(l) { return l.source() === d; });
28516 background.overlayLayerSources = function() {
28517 return overlayLayers.map(function (l) { return l.source(); });
28520 background.toggleOverlayLayer = function(d) {
28523 for (var i = 0; i < overlayLayers.length; i++) {
28524 layer = overlayLayers[i];
28525 if (layer.source() === d) {
28526 overlayLayers.splice(i, 1);
28528 background.updateImagery();
28533 layer = iD.TileLayer()
28535 .projection(context.projection)
28536 .dimensions(baseLayer.dimensions());
28538 overlayLayers.push(layer);
28540 background.updateImagery();
28543 background.nudge = function(d, zoom) {
28544 baseLayer.source().nudge(d, zoom);
28549 background.offset = function(d) {
28550 if (!arguments.length) return baseLayer.source().offset();
28551 baseLayer.source().offset(d);
28556 background.load = function(imagery) {
28557 function parseMap(qmap) {
28558 if (!qmap) return false;
28559 var args = qmap.split('/').map(Number);
28560 if (args.length < 3 || args.some(isNaN)) return false;
28561 return iD.geo.Extent([args[1], args[2]]);
28564 var q = iD.util.stringQs(location.hash.substring(1)),
28565 chosen = q.background || q.layer,
28566 extent = parseMap(q.map),
28569 backgroundSources = imagery.map(function(source) {
28570 if (source.type === 'bing') {
28571 return iD.BackgroundSource.Bing(source, dispatch);
28573 return iD.BackgroundSource(source);
28577 backgroundSources.unshift(iD.BackgroundSource.None());
28579 if (!chosen && extent) {
28580 best = _.find(this.sources(extent), function(s) { return s.best(); });
28583 if (chosen && chosen.indexOf('custom:') === 0) {
28584 background.baseLayerSource(iD.BackgroundSource.Custom(chosen.replace(/^custom:/, '')));
28586 background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
28589 var locator = _.find(backgroundSources, function(d) {
28590 return d.overlay && d.default;
28594 background.toggleOverlayLayer(locator);
28597 var overlays = (q.overlays || '').split(',');
28598 overlays.forEach(function(overlay) {
28599 overlay = findSource(overlay);
28600 if (overlay) background.toggleOverlayLayer(overlay);
28604 var gpx = context.layers().layer('gpx');
28605 if (gpx) { gpx.url(q.gpx); }
28609 return d3.rebind(background, dispatch, 'on');
28611 iD.BackgroundSource = function(data) {
28612 var source = _.clone(data),
28614 name = source.name,
28615 best = !!source.best;
28617 source.scaleExtent = data.scaleExtent || [0, 20];
28618 source.overzoom = data.overzoom !== false;
28620 source.offset = function(_) {
28621 if (!arguments.length) return offset;
28626 source.nudge = function(_, zoomlevel) {
28627 offset[0] += _[0] / Math.pow(2, zoomlevel);
28628 offset[1] += _[1] / Math.pow(2, zoomlevel);
28632 source.name = function() {
28636 source.best = function() {
28640 source.imageryUsed = function() {
28641 return source.id || name;
28644 source.url = function(coord) {
28645 return data.template
28646 .replace('{x}', coord[0])
28647 .replace('{y}', coord[1])
28648 // TMS-flipped y coordinate
28649 .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
28650 .replace(/\{z(oom)?\}/, coord[2])
28651 .replace(/\{switch:([^}]+)\}/, function(s, r) {
28652 var subdomains = r.split(',');
28653 return subdomains[(coord[0] + coord[1]) % subdomains.length];
28655 .replace('{u}', function() {
28657 for (var zoom = coord[2]; zoom > 0; zoom--) {
28659 var mask = 1 << (zoom - 1);
28660 if ((coord[0] & mask) !== 0) b++;
28661 if ((coord[1] & mask) !== 0) b += 2;
28668 source.intersects = function(extent) {
28669 extent = extent.polygon();
28670 return !data.polygon || data.polygon.some(function(polygon) {
28671 return iD.geo.polygonIntersectsPolygon(polygon, extent, true);
28675 source.validZoom = function(z) {
28676 return source.scaleExtent[0] <= z &&
28677 (source.overzoom || source.scaleExtent[1] > z);
28680 source.isLocatorOverlay = function() {
28681 return name === 'Locator Overlay';
28684 source.copyrightNotices = function() {};
28689 iD.BackgroundSource.Bing = function(data, dispatch) {
28690 // http://msdn.microsoft.com/en-us/library/ff701716.aspx
28691 // http://msdn.microsoft.com/en-us/library/ff701701.aspx
28693 data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
28695 var bing = iD.BackgroundSource(data),
28696 key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
28697 url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
28698 key + '&jsonp={callback}',
28701 d3.jsonp(url, function(json) {
28702 providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
28704 attribution: provider.attribution,
28705 areas: provider.coverageAreas.map(function(area) {
28707 zoom: [area.zoomMin, area.zoomMax],
28708 extent: iD.geo.Extent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
28716 bing.copyrightNotices = function(zoom, extent) {
28717 zoom = Math.min(zoom, 21);
28718 return providers.filter(function(provider) {
28719 return _.any(provider.areas, function(area) {
28720 return extent.intersects(area.extent) &&
28721 area.zoom[0] <= zoom &&
28722 area.zoom[1] >= zoom;
28724 }).map(function(provider) {
28725 return provider.attribution;
28729 bing.logo = 'bing_maps.png';
28730 bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
28735 iD.BackgroundSource.None = function() {
28736 var source = iD.BackgroundSource({id: 'none', template: ''});
28738 source.name = function() {
28739 return t('background.none');
28742 source.imageryUsed = function() {
28749 iD.BackgroundSource.Custom = function(template) {
28750 var source = iD.BackgroundSource({id: 'custom', template: template});
28752 source.name = function() {
28753 return t('background.custom');
28756 source.imageryUsed = function() {
28757 return 'Custom (' + template + ')';
28762 iD.Features = function(context) {
28763 var traffic_roads = {
28765 'motorway_link': true,
28767 'trunk_link': true,
28769 'primary_link': true,
28771 'secondary_link': true,
28773 'tertiary_link': true,
28774 'residential': true,
28775 'unclassified': true,
28776 'living_street': true
28779 var service_roads = {
28791 'pedestrian': true,
28795 var past_futures = {
28797 'construction': true,
28799 'dismantled': true,
28802 'demolished': true,
28803 'obliterated': true
28806 var dispatch = d3.dispatch('change', 'redraw'),
28814 function update() {
28815 _hidden = features.hidden();
28820 function defineFeature(k, filter, max) {
28824 enabled: true, // whether the user wants it enabled..
28826 currentMax: (max || Infinity),
28827 defaultMax: (max || Infinity),
28828 enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
28829 disable: function() { this.enabled = false; this.currentMax = 0; },
28830 hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
28831 autoHidden: function() { return this.hidden() && this.currentMax > 0; }
28836 defineFeature('points', function isPoint(entity, resolver, geometry) {
28837 return geometry === 'point';
28840 defineFeature('traffic_roads', function isTrafficRoad(entity) {
28841 return traffic_roads[entity.tags.highway];
28844 defineFeature('service_roads', function isServiceRoad(entity) {
28845 return service_roads[entity.tags.highway];
28848 defineFeature('paths', function isPath(entity) {
28849 return paths[entity.tags.highway];
28852 defineFeature('buildings', function isBuilding(entity) {
28854 !!entity.tags['building:part'] ||
28855 (!!entity.tags.building && entity.tags.building !== 'no') ||
28856 entity.tags.amenity === 'shelter' ||
28857 entity.tags.parking === 'multi-storey' ||
28858 entity.tags.parking === 'sheds' ||
28859 entity.tags.parking === 'carports' ||
28860 entity.tags.parking === 'garage_boxes'
28864 defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
28865 return geometry === 'area' &&
28866 !_features.buildings.filter(entity) &&
28867 !_features.water.filter(entity);
28870 defineFeature('boundaries', function isBoundary(entity) {
28871 return !!entity.tags.boundary;
28874 defineFeature('water', function isWater(entity) {
28876 !!entity.tags.waterway ||
28877 entity.tags.natural === 'water' ||
28878 entity.tags.natural === 'coastline' ||
28879 entity.tags.natural === 'bay' ||
28880 entity.tags.landuse === 'pond' ||
28881 entity.tags.landuse === 'basin' ||
28882 entity.tags.landuse === 'reservoir' ||
28883 entity.tags.landuse === 'salt_pond'
28887 defineFeature('rail', function isRail(entity) {
28889 !!entity.tags.railway ||
28890 entity.tags.landuse === 'railway'
28892 traffic_roads[entity.tags.highway] ||
28893 service_roads[entity.tags.highway] ||
28894 paths[entity.tags.highway]
28898 defineFeature('power', function isPower(entity) {
28899 return !!entity.tags.power;
28902 // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
28903 defineFeature('past_future', function isPastFuture(entity) {
28905 traffic_roads[entity.tags.highway] ||
28906 service_roads[entity.tags.highway] ||
28907 paths[entity.tags.highway]
28908 ) { return false; }
28910 var strings = Object.keys(entity.tags);
28912 for (var i = 0; i < strings.length; i++) {
28913 var s = strings[i];
28914 if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
28919 // Lines or areas that don't match another feature filter.
28920 // IMPORTANT: The 'others' feature must be the last one defined,
28921 // so that code in getMatches can skip this test if `hasMatch = true`
28922 defineFeature('others', function isOther(entity, resolver, geometry) {
28923 return (geometry === 'line' || geometry === 'area');
28927 function features() {}
28929 features.features = function() {
28933 features.keys = function() {
28937 features.enabled = function(k) {
28938 if (!arguments.length) {
28939 return _.filter(_keys, function(k) { return _features[k].enabled; });
28941 return _features[k] && _features[k].enabled;
28944 features.disabled = function(k) {
28945 if (!arguments.length) {
28946 return _.reject(_keys, function(k) { return _features[k].enabled; });
28948 return _features[k] && !_features[k].enabled;
28951 features.hidden = function(k) {
28952 if (!arguments.length) {
28953 return _.filter(_keys, function(k) { return _features[k].hidden(); });
28955 return _features[k] && _features[k].hidden();
28958 features.autoHidden = function(k) {
28959 if (!arguments.length) {
28960 return _.filter(_keys, function(k) { return _features[k].autoHidden(); });
28962 return _features[k] && _features[k].autoHidden();
28965 features.enable = function(k) {
28966 if (_features[k] && !_features[k].enabled) {
28967 _features[k].enable();
28972 features.disable = function(k) {
28973 if (_features[k] && _features[k].enabled) {
28974 _features[k].disable();
28979 features.toggle = function(k) {
28980 if (_features[k]) {
28981 (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
28986 features.resetStats = function() {
28987 _.each(_features, function(f) { f.count = 0; });
28991 features.gatherStats = function(d, resolver, dimensions) {
28992 var needsRedraw = false,
28993 type = _.groupBy(d, function(ent) { return ent.type; }),
28994 entities = [].concat(type.relation || [], type.way || [], type.node || []),
28995 currHidden, geometry, matches;
28997 _.each(_features, function(f) { f.count = 0; });
28999 // adjust the threshold for point/building culling based on viewport size..
29000 // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
29001 _cullFactor = dimensions[0] * dimensions[1] / 1000000;
29003 for (var i = 0; i < entities.length; i++) {
29004 geometry = entities[i].geometry(resolver);
29005 if (!(geometry === 'vertex' || geometry === 'relation')) {
29006 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
29007 for (var j = 0; j < matches.length; j++) {
29008 _features[matches[j]].count++;
29013 currHidden = features.hidden();
29014 if (currHidden !== _hidden) {
29015 _hidden = currHidden;
29016 needsRedraw = true;
29020 return needsRedraw;
29023 features.stats = function() {
29024 _.each(_keys, function(k) { _stats[k] = _features[k].count; });
29028 features.clear = function(d) {
29029 for (var i = 0; i < d.length; i++) {
29030 features.clearEntity(d[i]);
29034 features.clearEntity = function(entity) {
29035 delete _cache[iD.Entity.key(entity)];
29038 features.reset = function() {
29042 features.getMatches = function(entity, resolver, geometry) {
29043 if (geometry === 'vertex' || geometry === 'relation') return {};
29045 var ent = iD.Entity.key(entity);
29046 if (!_cache[ent]) {
29050 if (!_cache[ent].matches) {
29054 for (var i = 0; i < _keys.length; i++) {
29055 if (_keys[i] === 'others') {
29056 if (hasMatch) continue;
29058 // Multipolygon members:
29060 // 1. is a way that hasn't matched other "interesting" feature rules,
29061 // 2. and it belongs to a single parent multipolygon relation
29062 // ...then match whatever feature rules the parent multipolygon has matched.
29063 // see #2548, #2887
29066 // For this to work, getMatches must be called on relations before ways.
29068 if (entity.type === 'way') {
29069 var parents = features.getParents(entity, resolver, geometry);
29070 if (parents.length === 1 && parents[0].isMultipolygon()) {
29071 var pkey = iD.Entity.key(parents[0]);
29072 if (_cache[pkey] && _cache[pkey].matches) {
29073 matches = _.clone(_cache[pkey].matches);
29080 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
29081 matches[_keys[i]] = hasMatch = true;
29084 _cache[ent].matches = matches;
29087 return _cache[ent].matches;
29090 features.getParents = function(entity, resolver, geometry) {
29091 if (geometry === 'point') return [];
29093 var ent = iD.Entity.key(entity);
29094 if (!_cache[ent]) {
29098 if (!_cache[ent].parents) {
29100 if (geometry === 'vertex') {
29101 parents = resolver.parentWays(entity);
29102 } else { // 'line', 'area', 'relation'
29103 parents = resolver.parentRelations(entity);
29105 _cache[ent].parents = parents;
29107 return _cache[ent].parents;
29110 features.isHiddenFeature = function(entity, resolver, geometry) {
29111 if (!_hidden.length) return false;
29112 if (!entity.version) return false;
29114 var matches = features.getMatches(entity, resolver, geometry);
29116 for (var i = 0; i < _hidden.length; i++) {
29117 if (matches[_hidden[i]]) return true;
29122 features.isHiddenChild = function(entity, resolver, geometry) {
29123 if (!_hidden.length) return false;
29124 if (!entity.version || geometry === 'point') return false;
29126 var parents = features.getParents(entity, resolver, geometry);
29127 if (!parents.length) return false;
29129 for (var i = 0; i < parents.length; i++) {
29130 if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
29137 features.hasHiddenConnections = function(entity, resolver) {
29138 if (!_hidden.length) return false;
29139 var childNodes, connections;
29141 if (entity.type === 'midpoint') {
29142 childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
29145 childNodes = entity.nodes ? resolver.childNodes(entity) : [];
29146 connections = features.getParents(entity, resolver, entity.geometry(resolver));
29149 // gather ways connected to child nodes..
29150 connections = _.reduce(childNodes, function(result, e) {
29151 return resolver.isShared(e) ? _.union(result, resolver.parentWays(e)) : result;
29154 return connections.length ? _.any(connections, function(e) {
29155 return features.isHidden(e, resolver, e.geometry(resolver));
29159 features.isHidden = function(entity, resolver, geometry) {
29160 if (!_hidden.length) return false;
29161 if (!entity.version) return false;
29163 var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
29164 return fn(entity, resolver, geometry);
29167 features.filter = function(d, resolver) {
29168 if (!_hidden.length) return d;
29171 for (var i = 0; i < d.length; i++) {
29173 if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
29174 result.push(entity);
29180 return d3.rebind(features, dispatch, 'on');
29182 iD.Map = function(context) {
29183 var dimensions = [1, 1],
29184 dispatch = d3.dispatch('move', 'drawn'),
29185 projection = context.projection,
29186 zoom = d3.behavior.zoom()
29187 .translate(projection.translate())
29188 .scale(projection.scale() * 2 * Math.PI)
29189 .scaleExtent([1024, 256 * Math.pow(2, 24)])
29190 .on('zoom', zoomPan),
29191 dblclickEnabled = true,
29192 redrawEnabled = true,
29194 transformed = false,
29196 drawLayers = iD.svg.Layers(projection, context),
29197 drawPoints = iD.svg.Points(projection, context),
29198 drawVertices = iD.svg.Vertices(projection, context),
29199 drawLines = iD.svg.Lines(projection),
29200 drawAreas = iD.svg.Areas(projection),
29201 drawMidpoints = iD.svg.Midpoints(projection, context),
29202 drawLabels = iD.svg.Labels(projection, context),
29209 function map(selection) {
29211 .on('change.map', redraw);
29212 context.background()
29213 .on('change.map', redraw);
29215 .on('redraw.map', redraw);
29217 .on('change.map', function() {
29218 context.background().updateImagery();
29223 .on('dblclick.map', dblClick)
29226 supersurface = selection.append('div')
29227 .attr('id', 'supersurface')
29228 .call(iD.util.setTransform, 0, 0);
29230 // Need a wrapper div because Opera can't cope with an absolutely positioned
29231 // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
29232 wrapper = supersurface
29234 .attr('class', 'layer layer-data');
29236 map.surface = surface = wrapper
29238 .selectAll('.surface')
29239 .attr('id', 'surface');
29242 .on('mousedown.zoom', function() {
29243 if (d3.event.button === 2) {
29244 d3.event.stopPropagation();
29247 .on('mouseup.zoom', function() {
29248 if (resetTransform()) redraw();
29250 .on('mousemove.map', function() {
29251 mousemove = d3.event;
29253 .on('mouseover.vertices', function() {
29254 if (map.editable() && !transformed) {
29255 var hover = d3.event.target.__data__;
29256 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
29257 dispatch.drawn({full: false});
29260 .on('mouseout.vertices', function() {
29261 if (map.editable() && !transformed) {
29262 var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__;
29263 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
29264 dispatch.drawn({full: false});
29270 .call(context.background());
29273 context.on('enter.map', function() {
29274 if (map.editable() && !transformed) {
29275 var all = context.intersects(map.extent()),
29276 filter = d3.functor(true),
29277 graph = context.graph();
29279 all = context.features().filter(all, graph);
29281 .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
29282 .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
29283 dispatch.drawn({full: false});
29287 map.dimensions(selection.dimensions());
29289 drawLabels.supersurface(supersurface);
29292 function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }
29294 function drawVector(difference, extent) {
29295 var graph = context.graph(),
29296 features = context.features(),
29297 all = context.intersects(map.extent()),
29301 var complete = difference.complete(map.extent());
29302 data = _.compact(_.values(complete));
29303 filter = function(d) { return d.id in complete; };
29304 features.clear(data);
29307 // force a full redraw if gatherStats detects that a feature
29308 // should be auto-hidden (e.g. points or buildings)..
29309 if (features.gatherStats(all, graph, dimensions)) {
29310 extent = undefined;
29314 data = context.intersects(map.extent().intersection(extent));
29315 var set = d3.set(_.pluck(data, 'id'));
29316 filter = function(d) { return set.has(d.id); };
29320 filter = d3.functor(true);
29324 data = features.filter(data, graph);
29327 .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
29328 .call(drawLines, graph, data, filter)
29329 .call(drawAreas, graph, data, filter)
29330 .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
29331 .call(drawLabels, graph, data, filter, dimensions, !difference && !extent)
29332 .call(drawPoints, graph, data, filter);
29334 dispatch.drawn({full: true});
29337 function editOff() {
29338 context.features().resetStats();
29339 surface.selectAll('.layer-osm *').remove();
29340 dispatch.drawn({full: true});
29343 function dblClick() {
29344 if (!dblclickEnabled) {
29345 d3.event.preventDefault();
29346 d3.event.stopImmediatePropagation();
29350 function zoomPan() {
29351 if (Math.log(d3.event.scale) / Math.LN2 - 8 < minzoom) {
29352 surface.interrupt();
29353 iD.ui.flash(context.container())
29354 .select('.content')
29355 .text(t('cannot_zoom'));
29356 setZoom(context.minEditableZoom(), true);
29358 dispatch.move(map);
29363 .translate(d3.event.translate)
29364 .scale(d3.event.scale / (2 * Math.PI));
29366 var scale = d3.event.scale / transformStart[0],
29367 tX = (d3.event.translate[0] / scale - transformStart[1][0]) * scale,
29368 tY = (d3.event.translate[1] / scale - transformStart[1][1]) * scale;
29370 transformed = true;
29371 iD.util.setTransform(supersurface, tX, tY, scale);
29374 dispatch.move(map);
29377 function resetTransform() {
29378 if (!transformed) return false;
29380 surface.selectAll('.radial-menu').interrupt().remove();
29381 iD.util.setTransform(supersurface, 0, 0);
29382 transformed = false;
29386 function redraw(difference, extent) {
29387 if (!surface || !redrawEnabled) return;
29389 clearTimeout(timeoutId);
29391 // If we are in the middle of a zoom/pan, we can't do differenced redraws.
29392 // It would result in artifacts where differenced entities are redrawn with
29393 // one transform and unchanged entities with another.
29394 if (resetTransform()) {
29395 difference = extent = undefined;
29398 var zoom = String(~~map.zoom());
29399 if (surface.attr('data-zoom') !== zoom) {
29400 surface.attr('data-zoom', zoom)
29401 .classed('low-zoom', zoom <= 16);
29405 supersurface.call(context.background());
29409 if (map.editable()) {
29410 context.loadTiles(projection, dimensions);
29411 drawVector(difference, extent);
29420 projection.scale() * 2 * Math.PI,
29421 projection.translate().slice()];
29427 function queueRedraw() {
29428 clearTimeout(timeoutId);
29429 timeoutId = setTimeout(function() { redraw(); }, 300);
29432 function pointLocation(p) {
29433 var translate = projection.translate(),
29434 scale = projection.scale() * 2 * Math.PI;
29435 return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
29438 function locationPoint(l) {
29439 var translate = projection.translate(),
29440 scale = projection.scale() * 2 * Math.PI;
29441 return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
29444 map.mouse = function() {
29445 var e = mousemove || d3.event, s;
29446 while ((s = e.sourceEvent)) e = s;
29450 map.mouseCoordinates = function() {
29451 return projection.invert(map.mouse());
29454 map.dblclickEnable = function(_) {
29455 if (!arguments.length) return dblclickEnabled;
29456 dblclickEnabled = _;
29460 map.redrawEnable = function(_) {
29461 if (!arguments.length) return redrawEnabled;
29466 function interpolateZoom(_) {
29467 var k = projection.scale(),
29468 t = projection.translate();
29470 surface.node().__chart__ = {
29477 projection.scale(k).translate(t); // undo setZoom projection changes
29479 zoom.event(surface.transition());
29482 function setZoom(_, force) {
29483 if (_ === map.zoom() && !force)
29485 var scale = 256 * Math.pow(2, _),
29486 center = pxCenter(),
29487 l = pointLocation(center);
29488 scale = Math.max(1024, Math.min(256 * Math.pow(2, 24), scale));
29489 projection.scale(scale / (2 * Math.PI));
29491 var t = projection.translate();
29492 l = locationPoint(l);
29493 t[0] += center[0] - l[0];
29494 t[1] += center[1] - l[1];
29495 projection.translate(t);
29496 zoom.translate(projection.translate());
29500 function setCenter(_) {
29501 var c = map.center();
29502 if (_[0] === c[0] && _[1] === c[1])
29504 var t = projection.translate(),
29506 ll = projection(_);
29507 projection.translate([
29508 t[0] - ll[0] + pxC[0],
29509 t[1] - ll[1] + pxC[1]]);
29510 zoom.translate(projection.translate());
29514 map.pan = function(d) {
29515 var t = projection.translate();
29518 projection.translate(t);
29519 zoom.translate(projection.translate());
29520 dispatch.move(map);
29524 map.dimensions = function(_) {
29525 if (!arguments.length) return dimensions;
29526 var center = map.center();
29528 drawLayers.dimensions(dimensions);
29529 context.background().dimensions(dimensions);
29530 projection.clipExtent([[0, 0], dimensions]);
29531 mouse = iD.util.fastMouse(supersurface.node());
29536 function zoomIn(integer) {
29537 interpolateZoom(~~map.zoom() + integer);
29540 function zoomOut(integer) {
29541 interpolateZoom(~~map.zoom() - integer);
29544 map.zoomIn = function() { zoomIn(1); };
29545 map.zoomInFurther = function() { zoomIn(4); };
29547 map.zoomOut = function() { zoomOut(1); };
29548 map.zoomOutFurther = function() { zoomOut(4); };
29550 map.center = function(loc) {
29551 if (!arguments.length) {
29552 return projection.invert(pxCenter());
29555 if (setCenter(loc)) {
29556 dispatch.move(map);
29562 map.zoom = function(z) {
29563 if (!arguments.length) {
29564 return Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8, 0);
29568 surface.interrupt();
29569 iD.ui.flash(context.container())
29570 .select('.content')
29571 .text(t('cannot_zoom'));
29572 z = context.minEditableZoom();
29576 dispatch.move(map);
29582 map.zoomTo = function(entity, zoomLimits) {
29583 var extent = entity.extent(context.graph());
29584 if (!isFinite(extent.area())) return;
29586 var zoom = map.trimmedExtentZoom(extent);
29587 zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
29588 map.centerZoom(extent.center(), Math.min(Math.max(zoom, zoomLimits[0]), zoomLimits[1]));
29591 map.centerZoom = function(loc, z) {
29592 var centered = setCenter(loc),
29593 zoomed = setZoom(z);
29595 if (centered || zoomed) {
29596 dispatch.move(map);
29602 map.centerEase = function(loc) {
29603 var from = map.center().slice(),
29607 surface.one('mousedown.ease', function() {
29611 d3.timer(function() {
29612 if (stop) return true;
29613 map.center(iD.geo.interp(from, loc, (t += 1) / 10));
29619 map.extent = function(_) {
29620 if (!arguments.length) {
29621 return new iD.geo.Extent(projection.invert([0, dimensions[1]]),
29622 projection.invert([dimensions[0], 0]));
29624 var extent = iD.geo.Extent(_);
29625 map.centerZoom(extent.center(), map.extentZoom(extent));
29629 map.trimmedExtent = function(_) {
29630 if (!arguments.length) {
29631 var headerY = 60, footerY = 30, pad = 10;
29632 return new iD.geo.Extent(projection.invert([pad, dimensions[1] - footerY - pad]),
29633 projection.invert([dimensions[0] - pad, headerY + pad]));
29635 var extent = iD.geo.Extent(_);
29636 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
29640 function calcZoom(extent, dim) {
29641 var tl = projection([extent[0][0], extent[1][1]]),
29642 br = projection([extent[1][0], extent[0][1]]);
29644 // Calculate maximum zoom that fits extent
29645 var hFactor = (br[0] - tl[0]) / dim[0],
29646 vFactor = (br[1] - tl[1]) / dim[1],
29647 hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
29648 vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
29649 newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
29654 map.extentZoom = function(_) {
29655 return calcZoom(iD.geo.Extent(_), dimensions);
29658 map.trimmedExtentZoom = function(_) {
29659 var trimY = 120, trimX = 40,
29660 trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
29661 return calcZoom(iD.geo.Extent(_), trimmed);
29664 map.editable = function() {
29665 return map.zoom() >= context.minEditableZoom();
29668 map.minzoom = function(_) {
29669 if (!arguments.length) return minzoom;
29674 map.layers = drawLayers;
29676 return d3.rebind(map, dispatch, 'on');
29678 iD.TileLayer = function() {
29679 var tileSize = 256,
29680 tile = d3.geo.tile(),
29685 transformProp = iD.util.prefixCSSProperty('Transform'),
29686 source = d3.functor('');
29688 function tileSizeAtZoom(d, z) {
29689 return (tileSize * Math.pow(2, z - d[2])) / tileSize;
29692 function atZoom(t, distance) {
29693 var power = Math.pow(2, distance);
29695 Math.floor(t[0] * power),
29696 Math.floor(t[1] * power),
29700 function lookUp(d) {
29701 for (var up = -1; up > -d[2]; up--) {
29702 var tile = atZoom(d, up);
29703 if (cache[source.url(tile)] !== false) {
29709 function uniqueBy(a, n) {
29710 var o = [], seen = {};
29711 for (var i = 0; i < a.length; i++) {
29712 if (seen[a[i][n]] === undefined) {
29714 seen[a[i][n]] = true;
29720 function addSource(d) {
29721 d.push(source.url(d));
29725 // Update tiles based on current state of `projection`.
29726 function background(selection) {
29727 tile.scale(projection.scale() * 2 * Math.PI)
29728 .translate(projection.translate());
29731 projection.scale() * Math.PI - projection.translate()[0],
29732 projection.scale() * Math.PI - projection.translate()[1]];
29734 z = Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
29739 // Derive the tiles onscreen, remove those offscreen and position them.
29740 // Important that this part not depend on `projection` because it's
29741 // rentered when tiles load/error (see #644).
29742 function render(selection) {
29745 if (source.validZoom(z)) {
29746 tile().forEach(function(d) {
29748 if (d[3] === '') return;
29749 if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
29751 if (cache[d[3]] === false && lookUp(d)) {
29752 requests.push(addSource(lookUp(d)));
29756 requests = uniqueBy(requests, 3).filter(function(r) {
29757 // don't re-request tiles which have failed in the past
29758 return cache[r[3]] !== false;
29762 var pixelOffset = [
29763 source.offset()[0] * Math.pow(2, z),
29764 source.offset()[1] * Math.pow(2, z)
29768 cache[d[3]] = true;
29772 .classed('tile-loaded', true);
29776 function error(d) {
29777 cache[d[3]] = false;
29785 function imageTransform(d) {
29786 var _ts = tileSize * Math.pow(2, z - d[2]);
29787 var scale = tileSizeAtZoom(d, z);
29788 return 'translate(' +
29789 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
29790 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
29791 'scale(' + scale + ',' + scale + ')';
29794 var image = selection
29796 .data(requests, function(d) { return d[3]; });
29799 .style(transformProp, imageTransform)
29800 .classed('tile-removing', true)
29802 var tile = d3.select(this);
29803 window.setTimeout(function() {
29804 if (tile.classed('tile-removing')) {
29810 image.enter().append('img')
29811 .attr('class', 'tile')
29812 .attr('src', function(d) { return d[3]; })
29813 .on('error', error)
29817 .style(transformProp, imageTransform)
29818 .classed('tile-removing', false);
29821 background.projection = function(_) {
29822 if (!arguments.length) return projection;
29827 background.dimensions = function(_) {
29828 if (!arguments.length) return tile.size();
29833 background.source = function(_) {
29834 if (!arguments.length) return source;
29837 tile.scaleExtent(source.scaleExtent);
29844 PointTransform: function(projection) {
29845 return function(entity) {
29846 // http://jsperf.com/short-array-join
29847 var pt = projection(entity.loc);
29848 return 'translate(' + pt[0] + ',' + pt[1] + ')';
29852 Path: function(projection, graph, polygon) {
29854 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
29855 project = projection.stream,
29856 path = d3.geo.path()
29857 .projection({stream: function(output) { return polygon ? project(output) : project(clip(output)); }});
29859 return function(entity) {
29860 if (entity.id in cache) {
29861 return cache[entity.id];
29863 return cache[entity.id] = path(entity.asGeoJSON(graph));
29868 OneWaySegments: function(projection, graph, dt) {
29869 return function(entity) {
29875 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
29876 coordinates = graph.childNodes(entity).map(function(n) {
29880 if (entity.tags.oneway === '-1') coordinates.reverse();
29883 type: 'LineString',
29884 coordinates: coordinates
29885 }, projection.stream(clip({
29886 lineStart: function() {},
29887 lineEnd: function() {
29890 point: function(x, y) {
29894 var span = iD.geo.euclideanDistance(a, b) - offset;
29897 var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
29898 dx = dt * Math.cos(angle),
29899 dy = dt * Math.sin(angle),
29900 p = [a[0] + offset * Math.cos(angle),
29901 a[1] + offset * Math.sin(angle)];
29903 var segment = 'M' + a[0] + ',' + a[1] +
29904 'L' + p[0] + ',' + p[1];
29906 for (span -= dt; span >= 0; span -= dt) {
29909 segment += 'L' + p[0] + ',' + p[1];
29912 segment += 'L' + b[0] + ',' + b[1];
29913 segments.push({id: entity.id, index: i, d: segment});
29928 RelationMemberTags: function(graph) {
29929 return function(entity) {
29930 var tags = entity.tags;
29931 graph.parentRelations(entity).forEach(function(relation) {
29932 var type = relation.tags.type;
29933 if (type === 'multipolygon' || type === 'boundary') {
29934 tags = _.extend({}, relation.tags, tags);
29941 iD.svg.Areas = function(projection) {
29942 // Patterns only work in Firefox when set directly on element.
29943 // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
29945 wetland: 'wetland',
29948 construction: 'construction',
29949 military: 'construction',
29950 cemetery: 'cemetery',
29951 grave_yard: 'cemetery',
29954 farmland: 'farmland',
29958 var patternKeys = ['landuse', 'natural', 'amenity'];
29960 function setPattern(d) {
29961 for (var i = 0; i < patternKeys.length; i++) {
29962 if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
29963 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
29967 this.style.fill = this.style.stroke = '';
29970 return function drawAreas(surface, graph, entities, filter) {
29971 var path = iD.svg.Path(projection, graph, true),
29975 for (var i = 0; i < entities.length; i++) {
29976 var entity = entities[i];
29977 if (entity.geometry(graph) !== 'area') continue;
29979 multipolygon = iD.geo.isSimpleMultipolygonOuterMember(entity, graph);
29980 if (multipolygon) {
29981 areas[multipolygon.id] = {
29982 entity: multipolygon.mergeTags(entity.tags),
29983 area: Math.abs(entity.area(graph))
29985 } else if (!areas[entity.id]) {
29986 areas[entity.id] = {
29988 area: Math.abs(entity.area(graph))
29993 areas = d3.values(areas).filter(function hasPath(a) { return path(a.entity); });
29994 areas.sort(function areaSort(a, b) { return b.area - a.area; });
29995 areas = _.pluck(areas, 'entity');
29997 var strokes = areas.filter(function(area) {
29998 return area.type === 'way';
30008 var clipPaths = surface.selectAll('defs').selectAll('.clipPath')
30010 .data(data.clip, iD.Entity.key);
30013 .append('clipPath')
30014 .attr('class', 'clipPath')
30015 .attr('id', function(entity) { return entity.id + '-clippath'; })
30018 clipPaths.selectAll('path')
30024 var areagroup = surface
30025 .selectAll('.layer-areas')
30026 .selectAll('g.areagroup')
30027 .data(['fill', 'shadow', 'stroke']);
30031 .attr('class', function(d) { return 'layer areagroup area-' + d; });
30033 var paths = areagroup
30036 .data(function(layer) { return data[layer]; }, iD.Entity.key);
30038 // Remove exiting areas first, so they aren't included in the `fills`
30039 // array used for sorting below (https://github.com/openstreetmap/iD/issues/1903).
30043 var fills = surface.selectAll('.area-fill path.area')[0];
30045 var bisect = d3.bisector(function(node) {
30046 return -node.__data__.area(graph);
30049 function sortedByArea(entity) {
30050 if (this.__data__ === 'fill') {
30051 return fills[bisect(fills, -entity.area(graph))];
30056 .insert('path', sortedByArea)
30057 .each(function(entity) {
30058 var layer = this.parentNode.__data__;
30060 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
30062 if (layer === 'fill') {
30063 this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
30064 setPattern.apply(this, arguments);
30067 .call(iD.svg.TagClasses());
30074 A standalone SVG element that contains only a `defs` sub-element. To be
30075 used once globally, since defs IDs must be unique within a document.
30077 iD.svg.Defs = function(context) {
30079 function SVGSpriteDefinition(id, href) {
30080 return function(defs) {
30081 d3.xml(href, 'image/svg+xml', function(err, svg) {
30083 defs.node().appendChild(
30084 d3.select(svg.documentElement).attr('id', id).node()
30090 return function drawDefs(selection) {
30091 var defs = selection.append('defs');
30094 defs.append('marker')
30096 id: 'oneway-marker',
30097 viewBox: '0 0 10 10',
30102 markerUnits: 'strokeWidth',
30106 .attr('class', 'oneway')
30107 .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')
30108 .attr('stroke', 'none')
30109 .attr('fill', '#000')
30110 .attr('opacity', '0.5');
30113 var patterns = defs.selectAll('pattern')
30115 // pattern name, pattern image name
30116 ['wetland', 'wetland'],
30117 ['construction', 'construction'],
30118 ['cemetery', 'cemetery'],
30119 ['orchard', 'orchard'],
30120 ['farmland', 'farmland'],
30129 return 'pattern-' + d[0];
30133 patternUnits: 'userSpaceOnUse'
30136 patterns.append('rect')
30142 'class': function (d) {
30143 return 'pattern-color-' + d[0];
30147 patterns.append('image')
30154 .attr('xlink:href', function (d) {
30155 return context.imagePath('pattern/' + d[1] + '.png');
30160 .data([12, 18, 20, 32, 45])
30161 .enter().append('clipPath')
30162 .attr('id', function (d) {
30163 return 'clip-square-' + d;
30168 .attr('width', function (d) {
30171 .attr('height', function (d) {
30175 defs.call(SVGSpriteDefinition(
30177 context.imagePath('iD-sprite.svg')));
30179 defs.call(SVGSpriteDefinition(
30181 context.imagePath('maki-sprite.svg')));
30184 iD.svg.Gpx = function(projection, context, dispatch) {
30185 var showLabels = true,
30189 if (iD.svg.Gpx.initialized) return; // run once
30191 iD.svg.Gpx.geojson = {};
30192 iD.svg.Gpx.enabled = true;
30195 d3.event.stopPropagation();
30196 d3.event.preventDefault();
30197 d3.event.dataTransfer.dropEffect = 'copy';
30201 .attr('dropzone', 'copy')
30202 .on('drop.localgpx', function() {
30203 d3.event.stopPropagation();
30204 d3.event.preventDefault();
30205 if (!iD.detect().filedrop) return;
30206 drawGpx.files(d3.event.dataTransfer.files);
30208 .on('dragenter.localgpx', over)
30209 .on('dragexit.localgpx', over)
30210 .on('dragover.localgpx', over);
30212 iD.svg.Gpx.initialized = true;
30216 function drawGpx(surface) {
30217 var geojson = iD.svg.Gpx.geojson,
30218 enabled = iD.svg.Gpx.enabled;
30220 layer = surface.selectAll('.layer-gpx')
30221 .data(enabled ? [0] : []);
30225 .attr('class', 'layer-gpx');
30237 .attr('class', 'gpx');
30242 var path = d3.geo.path()
30243 .projection(projection);
30249 var labels = layer.selectAll('text')
30250 .data(showLabels && geojson.features ? geojson.features : []);
30254 .attr('class', 'gpx');
30260 .text(function(d) {
30261 return d.properties.desc || d.properties.name;
30263 .attr('x', function(d) {
30264 var centroid = path.centroid(d);
30265 return centroid[0] + 7;
30267 .attr('y', function(d) {
30268 var centroid = path.centroid(d);
30269 return centroid[1];
30274 function toDom(x) {
30275 return (new DOMParser()).parseFromString(x, 'text/xml');
30278 drawGpx.showLabels = function(_) {
30279 if (!arguments.length) return showLabels;
30284 drawGpx.enabled = function(_) {
30285 if (!arguments.length) return iD.svg.Gpx.enabled;
30286 iD.svg.Gpx.enabled = _;
30291 drawGpx.hasGpx = function() {
30292 var geojson = iD.svg.Gpx.geojson;
30293 return (!(_.isEmpty(geojson) || _.isEmpty(geojson.features)));
30296 drawGpx.geojson = function(gj) {
30297 if (!arguments.length) return iD.svg.Gpx.geojson;
30298 if (_.isEmpty(gj) || _.isEmpty(gj.features)) return this;
30299 iD.svg.Gpx.geojson = gj;
30304 drawGpx.url = function(url) {
30305 d3.text(url, function(err, data) {
30307 drawGpx.geojson(toGeoJSON.gpx(toDom(data)));
30313 drawGpx.files = function(fileList) {
30314 var f = fileList[0],
30315 reader = new FileReader();
30317 reader.onload = function(e) {
30318 drawGpx.geojson(toGeoJSON.gpx(toDom(e.target.result))).fitZoom();
30321 reader.readAsText(f);
30325 drawGpx.fitZoom = function() {
30326 if (!this.hasGpx()) return this;
30327 var geojson = iD.svg.Gpx.geojson;
30329 var map = context.map(),
30330 viewport = map.trimmedExtent().polygon(),
30331 coords = _.reduce(geojson.features, function(coords, feature) {
30332 var c = feature.geometry.coordinates;
30333 return _.union(coords, feature.geometry.type === 'Point' ? [c] : c);
30336 if (!iD.geo.polygonIntersectsPolygon(viewport, coords, true)) {
30337 var extent = iD.geo.Extent(d3.geo.bounds(geojson));
30338 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
30347 iD.svg.Icon = function(name, svgklass, useklass) {
30348 return function drawIcon(selection) {
30349 selection.selectAll('svg')
30353 .attr('class', 'icon ' + (svgklass || ''))
30355 .attr('xlink:href', name)
30356 .attr('class', useklass);
30359 iD.svg.Labels = function(projection, context) {
30360 var path = d3.geo.path().projection(projection);
30362 // Replace with dict and iterate over entities tags instead?
30363 var label_stack = [
30364 ['line', 'aeroway'],
30365 ['line', 'highway'],
30366 ['line', 'railway'],
30367 ['line', 'waterway'],
30368 ['area', 'aeroway'],
30369 ['area', 'amenity'],
30370 ['area', 'building'],
30371 ['area', 'historic'],
30372 ['area', 'leisure'],
30373 ['area', 'man_made'],
30374 ['area', 'natural'],
30376 ['area', 'tourism'],
30377 ['point', 'aeroway'],
30378 ['point', 'amenity'],
30379 ['point', 'building'],
30380 ['point', 'historic'],
30381 ['point', 'leisure'],
30382 ['point', 'man_made'],
30383 ['point', 'natural'],
30385 ['point', 'tourism'],
30391 var default_size = 12;
30393 var font_sizes = label_stack.map(function(d) {
30394 var style = iD.util.getStyle('text.' + d[0] + '.tag-' + d[1]),
30395 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
30396 if (m) return parseInt(m[1], 10);
30398 style = iD.util.getStyle('text.' + d[0]);
30399 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
30400 if (m) return parseInt(m[1], 10);
30402 return default_size;
30407 var pointOffsets = [
30408 [15, -11, 'start'], // right
30409 [10, -11, 'start'], // unused right now
30413 var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25,
30414 75, 20, 80, 15, 95, 10, 90, 5, 95];
30417 var noIcons = ['building', 'landuse', 'natural'];
30418 function blacklisted(preset) {
30419 return _.any(noIcons, function(s) {
30420 return preset.id.indexOf(s) >= 0;
30424 function get(array, prop) {
30425 return function(d, i) { return array[i][prop]; };
30428 var textWidthCache = {};
30430 function textWidth(text, size, elem) {
30431 var c = textWidthCache[size];
30432 if (!c) c = textWidthCache[size] = {};
30438 c[text] = elem.getComputedTextLength();
30442 var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
30443 if (str === null) {
30444 return size / 3 * 2 * text.length;
30446 return size / 3 * (2 * text.length + str.length);
30451 function drawLineLabels(group, entities, filter, classes, labels) {
30452 var texts = group.selectAll('text.' + classes)
30454 .data(entities, iD.Entity.key);
30458 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
30459 .append('textPath')
30460 .attr('class', 'textpath');
30463 texts.selectAll('.textpath')
30465 .data(entities, iD.Entity.key)
30467 'startOffset': '50%',
30468 'xlink:href': function(d) { return '#labelpath-' + d.id; }
30470 .text(iD.util.displayName);
30472 texts.exit().remove();
30475 function drawLinePaths(group, entities, filter, classes, labels) {
30476 var halos = group.selectAll('path')
30478 .data(entities, iD.Entity.key);
30482 .style('stroke-width', get(labels, 'font-size'))
30483 .attr('id', function(d) { return 'labelpath-' + d.id; })
30484 .attr('class', classes);
30486 halos.attr('d', get(labels, 'lineString'));
30488 halos.exit().remove();
30491 function drawPointLabels(group, entities, filter, classes, labels) {
30492 var texts = group.selectAll('text.' + classes)
30494 .data(entities, iD.Entity.key);
30498 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; });
30500 texts.attr('x', get(labels, 'x'))
30501 .attr('y', get(labels, 'y'))
30502 .style('text-anchor', get(labels, 'textAnchor'))
30503 .text(iD.util.displayName)
30504 .each(function(d, i) { textWidth(iD.util.displayName(d), labels[i].height, this); });
30506 texts.exit().remove();
30510 function drawAreaLabels(group, entities, filter, classes, labels) {
30511 entities = entities.filter(hasText);
30512 labels = labels.filter(hasText);
30513 return drawPointLabels(group, entities, filter, classes, labels);
30515 function hasText(d, i) {
30516 return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
30520 function drawAreaIcons(group, entities, filter, classes, labels) {
30521 var icons = group.selectAll('use')
30523 .data(entities, iD.Entity.key);
30527 .attr('class', 'icon areaicon')
30528 .attr('width', '18px')
30529 .attr('height', '18px');
30531 icons.attr('transform', get(labels, 'transform'))
30532 .attr('xlink:href', function(d) {
30533 var icon = context.presets().match(d, context.graph()).icon;
30534 return '#' + icon + (icon === 'hairdresser' ? '-24': '-18'); // workaround: maki hairdresser-18 broken?
30538 icons.exit().remove();
30541 function reverse(p) {
30542 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
30543 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
30546 function lineString(nodes) {
30547 return 'M' + nodes.join('L');
30550 function subpath(nodes, from, to) {
30551 function segmentLength(i) {
30552 var dx = nodes[i][0] - nodes[i + 1][0];
30553 var dy = nodes[i][1] - nodes[i + 1][1];
30554 return Math.sqrt(dx * dx + dy * dy);
30558 start, end, i0, i1;
30559 for (var i = 0; i < nodes.length - 1; i++) {
30560 var current = segmentLength(i);
30562 if (!start && sofar + current >= from) {
30563 portion = (from - sofar) / current;
30565 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
30566 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
30570 if (!end && sofar + current >= to) {
30571 portion = (to - sofar) / current;
30573 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
30574 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
30581 var ret = nodes.slice(i0, i1);
30582 ret.unshift(start);
30588 function hideOnMouseover() {
30589 var layers = d3.select(this)
30590 .selectAll('.layer-label, .layer-halo');
30592 layers.selectAll('.proximate')
30593 .classed('proximate', false);
30595 var mouse = context.mouse(),
30597 rect = [mouse[0] - pad, mouse[1] - pad, mouse[0] + pad, mouse[1] + pad],
30598 ids = _.pluck(rtree.search(rect), 'id');
30600 if (!ids.length) return;
30601 layers.selectAll('.' + ids.join(', .'))
30602 .classed('proximate', true);
30605 var rtree = rbush(),
30608 function drawLabels(surface, graph, entities, filter, dimensions, fullRedraw) {
30609 var hidePoints = !surface.selectAll('.node.point').node();
30611 var labelable = [], i, k, entity;
30612 for (i = 0; i < label_stack.length; i++) labelable.push([]);
30618 for (i = 0; i < entities.length; i++) {
30619 rtree.remove(rectangles[entities[i].id]);
30623 // Split entities into groups specified by label_stack
30624 for (i = 0; i < entities.length; i++) {
30625 entity = entities[i];
30626 var geometry = entity.geometry(graph);
30628 if (geometry === 'vertex')
30630 if (hidePoints && geometry === 'point')
30633 var preset = geometry === 'area' && context.presets().match(entity, graph),
30634 icon = preset && !blacklisted(preset) && preset.icon;
30636 if (!icon && !iD.util.displayName(entity))
30639 for (k = 0; k < label_stack.length; k++) {
30640 if (geometry === label_stack[k][0] && entity.tags[label_stack[k][1]]) {
30641 labelable[k].push(entity);
30659 // Try and find a valid label for labellable entities
30660 for (k = 0; k < labelable.length; k++) {
30661 var font_size = font_sizes[k];
30662 for (i = 0; i < labelable[k].length; i++) {
30663 entity = labelable[k][i];
30664 var name = iD.util.displayName(entity),
30665 width = name && textWidth(name, font_size),
30667 if (entity.geometry(graph) === 'point') {
30668 p = getPointLabel(entity, width, font_size);
30669 } else if (entity.geometry(graph) === 'line') {
30670 p = getLineLabel(entity, width, font_size);
30671 } else if (entity.geometry(graph) === 'area') {
30672 p = getAreaLabel(entity, width, font_size);
30675 p.classes = entity.geometry(graph) + ' tag-' + label_stack[k][1];
30676 positions[entity.geometry(graph)].push(p);
30677 labelled[entity.geometry(graph)].push(entity);
30682 function getPointLabel(entity, width, height) {
30683 var coord = projection(entity.loc),
30685 offset = pointOffsets[0],
30689 x: coord[0] + offset[0],
30690 y: coord[1] + offset[1],
30691 textAnchor: offset[2]
30693 var rect = [p.x - m, p.y - m, p.x + width + m, p.y + height + m];
30694 if (tryInsert(rect, entity.id)) return p;
30698 function getLineLabel(entity, width, height) {
30699 var nodes = _.pluck(graph.childNodes(entity), 'loc').map(projection),
30700 length = iD.geo.pathLength(nodes);
30701 if (length < width + 20) return;
30703 for (var i = 0; i < lineOffsets.length; i++) {
30704 var offset = lineOffsets[i],
30705 middle = offset / 100 * length,
30706 start = middle - width/2;
30707 if (start < 0 || start + width > length) continue;
30708 var sub = subpath(nodes, start, start + width),
30709 rev = reverse(sub),
30711 Math.min(sub[0][0], sub[sub.length - 1][0]) - 10,
30712 Math.min(sub[0][1], sub[sub.length - 1][1]) - 10,
30713 Math.max(sub[0][0], sub[sub.length - 1][0]) + 20,
30714 Math.max(sub[0][1], sub[sub.length - 1][1]) + 30
30716 if (rev) sub = sub.reverse();
30717 if (tryInsert(rect, entity.id)) return {
30718 'font-size': height + 2,
30719 lineString: lineString(sub),
30720 startOffset: offset + '%'
30725 function getAreaLabel(entity, width, height) {
30726 var centroid = path.centroid(entity.asGeoJSON(graph, true)),
30727 extent = entity.extent(graph),
30728 entitywidth = projection(extent[1])[0] - projection(extent[0])[0],
30731 if (isNaN(centroid[0]) || entitywidth < 20) return;
30733 var iconX = centroid[0] - (iconSize/2),
30734 iconY = centroid[1] - (iconSize/2),
30735 textOffset = iconSize + 5;
30738 transform: 'translate(' + iconX + ',' + iconY + ')'
30741 if (width && entitywidth >= width + 20) {
30743 p.y = centroid[1] + textOffset;
30744 p.textAnchor = 'middle';
30746 rect = [p.x - width/2, p.y, p.x + width/2, p.y + height + textOffset];
30748 rect = [iconX, iconY, iconX + iconSize, iconY + iconSize];
30751 if (tryInsert(rect, entity.id)) return p;
30755 function tryInsert(rect, id) {
30756 // Check that label is visible
30757 if (rect[0] < 0 || rect[1] < 0 || rect[2] > dimensions[0] ||
30758 rect[3] > dimensions[1]) return false;
30759 var v = rtree.search(rect).length === 0;
30762 rtree.insert(rect);
30763 rectangles[id] = rect;
30768 var label = surface.selectAll('.layer-label'),
30769 halo = surface.selectAll('.layer-halo');
30772 drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
30773 drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
30776 drawLinePaths(halo, labelled.line, filter, '', positions.line);
30777 drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
30778 drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
30781 drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
30782 drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
30783 drawAreaIcons(label, labelled.area, filter, 'arealabel-icon', positions.area);
30786 drawLabels.supersurface = function(supersurface) {
30788 .on('mousemove.hidelabels', hideOnMouseover)
30789 .on('mousedown.hidelabels', function () {
30790 supersurface.on('mousemove.hidelabels', null);
30792 .on('mouseup.hidelabels', function () {
30793 supersurface.on('mousemove.hidelabels', hideOnMouseover);
30799 iD.svg.Layers = function(projection, context) {
30800 var dispatch = d3.dispatch('change'),
30801 svg = d3.select(null),
30803 { id: 'osm', layer: iD.svg.Osm(projection, context, dispatch) },
30804 { id: 'gpx', layer: iD.svg.Gpx(projection, context, dispatch) },
30805 { id: 'mapillary-images', layer: iD.svg.MapillaryImages(projection, context, dispatch) },
30806 { id: 'mapillary-signs', layer: iD.svg.MapillarySigns(projection, context, dispatch) }
30810 function drawLayers(selection) {
30811 svg = selection.selectAll('.surface')
30816 .attr('class', 'surface')
30819 var groups = svg.selectAll('.data-layer')
30824 .attr('class', function(d) { return 'data-layer data-layer-' + d.id; });
30827 .each(function(d) { d3.select(this).call(d.layer); });
30833 drawLayers.all = function() {
30837 drawLayers.layer = function(id) {
30838 var obj = _.find(layers, 'id', id);
30839 return obj && obj.layer;
30842 drawLayers.only = function(what) {
30843 var arr = [].concat(what);
30844 drawLayers.remove(_.difference(_.pluck(layers, 'id'), arr));
30848 drawLayers.remove = function(what) {
30849 var arr = [].concat(what);
30850 arr.forEach(function(id) {
30851 layers = _.reject(layers, 'id', id);
30857 drawLayers.add = function(what) {
30858 var arr = [].concat(what);
30859 arr.forEach(function(obj) {
30860 if ('id' in obj && 'layer' in obj) {
30868 drawLayers.dimensions = function(_) {
30869 if (!arguments.length) return svg.dimensions();
30871 layers.forEach(function(obj) {
30872 if (obj.layer.dimensions) {
30873 obj.layer.dimensions(_);
30880 return d3.rebind(drawLayers, dispatch, 'on');
30882 iD.svg.Lines = function(projection) {
30884 var highway_stack = {
30899 function waystack(a, b) {
30900 var as = 0, bs = 0;
30902 if (a.tags.highway) { as -= highway_stack[a.tags.highway]; }
30903 if (b.tags.highway) { bs -= highway_stack[b.tags.highway]; }
30907 return function drawLines(surface, graph, entities, filter) {
30908 var ways = [], pathdata = {}, onewaydata = {},
30909 getPath = iD.svg.Path(projection, graph);
30911 for (var i = 0; i < entities.length; i++) {
30912 var entity = entities[i],
30913 outer = iD.geo.simpleMultipolygonOuterMember(entity, graph);
30915 ways.push(entity.mergeTags(outer.tags));
30916 } else if (entity.geometry(graph) === 'line') {
30921 ways = ways.filter(getPath);
30923 pathdata = _.groupBy(ways, function(way) { return way.layer(); });
30925 _.forOwn(pathdata, function(v, k) {
30926 onewaydata[k] = _(v)
30927 .filter(function(d) { return d.isOneWay(); })
30928 .map(iD.svg.OneWaySegments(projection, graph, 35))
30933 var layergroup = surface
30934 .selectAll('.layer-lines')
30935 .selectAll('g.layergroup')
30936 .data(d3.range(-10, 11));
30940 .attr('class', function(d) { return 'layer layergroup layer' + String(d); });
30943 var linegroup = layergroup
30944 .selectAll('g.linegroup')
30945 .data(['shadow', 'casing', 'stroke']);
30949 .attr('class', function(d) { return 'layer linegroup line-' + d; });
30952 var lines = linegroup
30956 function() { return pathdata[this.parentNode.parentNode.__data__] || []; },
30960 // Optimization: call simple TagClasses only on enter selection. This
30961 // works because iD.Entity.key is defined to include the entity v attribute.
30964 .attr('class', function(d) { return 'way line ' + this.parentNode.__data__ + ' ' + d.id; })
30965 .call(iD.svg.TagClasses());
30969 .attr('d', getPath)
30970 .call(iD.svg.TagClasses().tags(iD.svg.RelationMemberTags(graph)));
30976 var onewaygroup = layergroup
30977 .selectAll('g.onewaygroup')
30980 onewaygroup.enter()
30982 .attr('class', 'layer onewaygroup');
30985 var oneways = onewaygroup
30989 function() { return onewaydata[this.parentNode.parentNode.__data__] || []; },
30990 function(d) { return [d.id, d.index]; }
30995 .attr('class', 'oneway')
30996 .attr('marker-mid', 'url(#oneway-marker)');
30999 .attr('d', function(d) { return d.d; });
31001 if (iD.detect().ie) {
31002 oneways.each(function() { this.parentNode.insertBefore(this, this); });
31010 iD.svg.MapillaryImages = function(projection, context, dispatch) {
31011 var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000),
31013 layer = d3.select(null),
31018 if (iD.svg.MapillaryImages.initialized) return; // run once
31019 iD.svg.MapillaryImages.enabled = false;
31020 iD.svg.MapillaryImages.initialized = true;
31023 function getMapillary() {
31024 if (iD.services.mapillary && !_mapillary) {
31025 _mapillary = iD.services.mapillary().on('loadedImages', debouncedRedraw);
31026 } else if (!iD.services.mapillary && _mapillary) {
31032 function showThumbnail(image) {
31033 var mapillary = getMapillary();
31034 if (!mapillary) return;
31036 var thumb = mapillary.selectedThumbnail(),
31037 posX = projection(image.loc)[0],
31038 width = layer.dimensions()[0],
31039 position = (posX < width / 2) ? 'right' : 'left';
31042 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31043 .classed('selected', function(d) { return d.key === thumb.key; });
31046 mapillary.showThumbnail(image.key, position);
31049 function hideThumbnail() {
31050 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31051 .classed('selected', false);
31053 var mapillary = getMapillary();
31055 mapillary.hideThumbnail();
31059 function showLayer() {
31062 .style('opacity', 0)
31065 .style('opacity', 1)
31066 .each('end', debouncedRedraw);
31069 function hideLayer() {
31070 debouncedRedraw.cancel();
31075 .style('opacity', 0)
31076 .each('end', editOff);
31079 function editOn() {
31080 layer.style('display', 'block');
31083 function editOff() {
31084 layer.selectAll('.viewfield-group').remove();
31085 layer.style('display', 'none');
31088 function transform(d) {
31089 var t = iD.svg.PointTransform(projection)(d);
31090 if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
31094 function update() {
31095 var mapillary = getMapillary(),
31096 data = (mapillary ? mapillary.images(projection, layer.dimensions()) : []);
31098 var markers = layer.selectAll('.viewfield-group')
31099 .data(data, function(d) { return d.key; });
31102 var enter = markers.enter()
31104 .attr('class', 'viewfield-group');
31106 enter.append('path')
31107 .attr('class', 'viewfield')
31108 .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
31109 .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');
31111 enter.append('circle')
31122 .attr('transform', transform);
31125 function drawImages(selection) {
31126 var enabled = iD.svg.MapillaryImages.enabled,
31127 mapillary = getMapillary();
31129 layer = selection.selectAll('.layer-mapillary-images')
31130 .data(mapillary ? [0] : []);
31134 .attr('class', 'layer-mapillary-images')
31135 .style('display', enabled ? 'block' : 'none')
31136 .on('click', function() { // deselect/select
31137 var mapillary = getMapillary();
31138 if (!mapillary) return;
31139 var d = d3.event.target.__data__,
31140 thumb = mapillary.selectedThumbnail();
31141 if (thumb && thumb.key === d.key) {
31144 mapillary.selectedThumbnail(d);
31145 context.map().centerEase(d.loc);
31149 .on('mouseover', function() {
31150 var mapillary = getMapillary();
31151 if (!mapillary) return;
31152 showThumbnail(d3.event.target.__data__);
31154 .on('mouseout', function() {
31155 var mapillary = getMapillary();
31156 if (!mapillary) return;
31157 var thumb = mapillary.selectedThumbnail();
31159 showThumbnail(thumb);
31169 if (mapillary && ~~context.map().zoom() >= minZoom) {
31172 mapillary.loadImages(projection, layer.dimensions());
31179 drawImages.enabled = function(_) {
31180 if (!arguments.length) return iD.svg.MapillaryImages.enabled;
31181 iD.svg.MapillaryImages.enabled = _;
31182 if (iD.svg.MapillaryImages.enabled) {
31191 drawImages.supported = function() {
31192 return !!getMapillary();
31195 drawImages.dimensions = function(_) {
31196 if (!arguments.length) return layer.dimensions();
31197 layer.dimensions(_);
31204 iD.svg.MapillarySigns = function(projection, context, dispatch) {
31205 var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000),
31207 layer = d3.select(null),
31212 if (iD.svg.MapillarySigns.initialized) return; // run once
31213 iD.svg.MapillarySigns.enabled = false;
31214 iD.svg.MapillarySigns.initialized = true;
31217 function getMapillary() {
31218 if (iD.services.mapillary && !_mapillary) {
31219 _mapillary = iD.services.mapillary().on('loadedSigns', debouncedRedraw);
31220 } else if (!iD.services.mapillary && _mapillary) {
31226 function showThumbnail(image) {
31227 var mapillary = getMapillary();
31228 if (!mapillary) return;
31230 var thumb = mapillary.selectedThumbnail(),
31231 posX = projection(image.loc)[0],
31232 width = layer.dimensions()[0],
31233 position = (posX < width / 2) ? 'right' : 'left';
31236 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31237 .classed('selected', function(d) { return d.key === thumb.key; });
31240 mapillary.showThumbnail(image.key, position);
31243 function hideThumbnail() {
31244 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31245 .classed('selected', false);
31247 var mapillary = getMapillary();
31249 mapillary.hideThumbnail();
31253 function showLayer() {
31258 function hideLayer() {
31259 debouncedRedraw.cancel();
31264 function editOn() {
31265 layer.style('display', 'block');
31268 function editOff() {
31269 layer.selectAll('.icon-sign').remove();
31270 layer.style('display', 'none');
31273 function update() {
31274 var mapillary = getMapillary(),
31275 data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []);
31277 var signs = layer.selectAll('.icon-sign')
31278 .data(data, function(d) { return d.key; });
31281 var enter = signs.enter()
31282 .append('foreignObject')
31283 .attr('class', 'icon-sign')
31284 .attr('width', '32px') // for Firefox
31285 .attr('height', '32px'); // for Firefox
31288 .append('xhtml:body')
31289 .html(mapillary.signHTML);
31292 .on('click', function(d) { // deselect/select
31293 var mapillary = getMapillary();
31294 if (!mapillary) return;
31295 var thumb = mapillary.selectedThumbnail();
31296 if (thumb && thumb.key === d.key) {
31299 mapillary.selectedThumbnail(d);
31300 context.map().centerEase(d.loc);
31304 .on('mouseover', showThumbnail)
31305 .on('mouseout', function() {
31306 var mapillary = getMapillary();
31307 if (!mapillary) return;
31308 var thumb = mapillary.selectedThumbnail();
31310 showThumbnail(thumb);
31322 .attr('transform', iD.svg.PointTransform(projection));
31325 function drawSigns(selection) {
31326 var enabled = iD.svg.MapillarySigns.enabled,
31327 mapillary = getMapillary();
31329 layer = selection.selectAll('.layer-mapillary-signs')
31330 .data(mapillary ? [0] : []);
31334 .attr('class', 'layer-mapillary-signs')
31335 .style('display', enabled ? 'block' : 'none')
31336 .attr('transform', 'translate(-16, -16)'); // center signs on loc
31342 if (mapillary && ~~context.map().zoom() >= minZoom) {
31345 mapillary.loadSigns(context, projection, layer.dimensions());
31352 drawSigns.enabled = function(_) {
31353 if (!arguments.length) return iD.svg.MapillarySigns.enabled;
31354 iD.svg.MapillarySigns.enabled = _;
31355 if (iD.svg.MapillarySigns.enabled) {
31364 drawSigns.supported = function() {
31365 var mapillary = getMapillary();
31366 return (mapillary && mapillary.signsSupported());
31369 drawSigns.dimensions = function(_) {
31370 if (!arguments.length) return layer.dimensions();
31371 layer.dimensions(_);
31378 iD.svg.Midpoints = function(projection, context) {
31379 return function drawMidpoints(surface, graph, entities, filter, extent) {
31380 var poly = extent.polygon(),
31383 for (var i = 0; i < entities.length; i++) {
31384 var entity = entities[i];
31386 if (entity.type !== 'way')
31388 if (!filter(entity))
31390 if (context.selectedIDs().indexOf(entity.id) < 0)
31393 var nodes = graph.childNodes(entity);
31394 for (var j = 0; j < nodes.length - 1; j++) {
31398 id = [a.id, b.id].sort().join('-');
31400 if (midpoints[id]) {
31401 midpoints[id].parents.push(entity);
31403 if (iD.geo.euclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
31404 var point = iD.geo.interp(a.loc, b.loc, 0.5),
31407 if (extent.intersects(point)) {
31410 for (var k = 0; k < 4; k++) {
31411 point = iD.geo.lineIntersection([a.loc, b.loc], [poly[k], poly[k+1]]);
31413 iD.geo.euclideanDistance(projection(a.loc), projection(point)) > 20 &&
31414 iD.geo.euclideanDistance(projection(b.loc), projection(point)) > 20)
31427 edge: [a.id, b.id],
31436 function midpointFilter(d) {
31437 if (midpoints[d.id])
31440 for (var i = 0; i < d.parents.length; i++)
31441 if (filter(d.parents[i]))
31447 var groups = surface.selectAll('.layer-hit').selectAll('g.midpoint')
31448 .filter(midpointFilter)
31449 .data(_.values(midpoints), function(d) { return d.id; });
31451 var enter = groups.enter()
31452 .insert('g', ':first-child')
31453 .attr('class', 'midpoint');
31455 enter.append('polygon')
31456 .attr('points', '-6,8 10,0 -6,-8')
31457 .attr('class', 'shadow');
31459 enter.append('polygon')
31460 .attr('points', '-3,4 5,0 -3,-4')
31461 .attr('class', 'fill');
31464 .attr('transform', function(d) {
31465 var translate = iD.svg.PointTransform(projection),
31466 a = context.entity(d.edge[0]),
31467 b = context.entity(d.edge[1]),
31468 angle = Math.round(iD.geo.angle(a, b, projection) * (180 / Math.PI));
31469 return translate(d) + ' rotate(' + angle + ')';
31471 .call(iD.svg.TagClasses().tags(
31472 function(d) { return d.parents[0].tags; }
31475 // Propagate data bindings.
31476 groups.select('polygon.shadow');
31477 groups.select('polygon.fill');
31483 iD.svg.Osm = function() {
31484 return function drawOsm(selection) {
31485 var layers = selection.selectAll('.layer-osm')
31486 .data(['areas', 'lines', 'hit', 'halo', 'label']);
31488 layers.enter().append('g')
31489 .attr('class', function(d) { return 'layer-osm layer-' + d; });
31492 iD.svg.Points = function(projection, context) {
31493 function markerPath(selection, klass) {
31495 .attr('class', klass)
31496 .attr('transform', 'translate(-8, -23)')
31497 .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');
31500 function sortY(a, b) {
31501 return b.loc[1] - a.loc[1];
31504 return function drawPoints(surface, graph, entities, filter) {
31505 var wireframe = surface.classed('fill-wireframe'),
31506 points = wireframe ? [] : _.filter(entities, function(e) {
31507 return e.geometry(graph) === 'point';
31510 points.sort(sortY);
31512 var groups = surface.selectAll('.layer-hit').selectAll('g.point')
31514 .data(points, iD.Entity.key);
31516 var group = groups.enter()
31518 .attr('class', function(d) { return 'node point ' + d.id; })
31521 group.append('path')
31522 .call(markerPath, 'shadow');
31524 group.append('path')
31525 .call(markerPath, 'stroke');
31527 group.append('use')
31528 .attr('transform', 'translate(-6, -20)')
31529 .attr('class', 'icon')
31530 .attr('width', '12px')
31531 .attr('height', '12px');
31533 groups.attr('transform', iD.svg.PointTransform(projection))
31534 .call(iD.svg.TagClasses());
31536 // Selecting the following implicitly
31537 // sets the data (point entity) on the element
31538 groups.select('.shadow');
31539 groups.select('.stroke');
31540 groups.select('.icon')
31541 .attr('xlink:href', function(entity) {
31542 var preset = context.presets().match(entity, graph);
31543 return preset.icon ? '#' + preset.icon + '-12' : '';
31550 iD.svg.TagClasses = function() {
31552 'building', 'highway', 'railway', 'waterway', 'aeroway',
31553 'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
31557 'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
31558 'razed', 'demolished', 'obliterated'
31561 'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
31562 'surface', 'tracktype', 'crossing'
31564 tagClassRe = /^tag-/,
31565 tags = function(entity) { return entity.tags; };
31568 var tagClasses = function(selection) {
31569 selection.each(function tagClassesEach(entity) {
31570 var value = this.className,
31571 classes, primary, status;
31573 if (value.baseVal !== undefined) value = value.baseVal;
31575 classes = value.trim().split(/\s+/).filter(function(name) {
31576 return name.length && !tagClassRe.test(name);
31579 var t = tags(entity), i, k, v;
31581 // pick at most one primary classification tag..
31582 for (i = 0; i < primaries.length; i++) {
31585 if (!v || v === 'no') continue;
31588 if (statuses.indexOf(v) !== -1) { // e.g. `railway=abandoned`
31590 classes += ' tag-' + k;
31592 classes += ' tag-' + k + ' tag-' + k + '-' + v;
31598 // add at most one status tag, only if relates to primary tag..
31600 for (i = 0; i < statuses.length; i++) {
31603 if (!v || v === 'no') continue;
31605 if (v === 'yes') { // e.g. `railway=rail + abandoned=yes`
31608 else if (primary && primary === v) { // e.g. `railway=rail + abandoned=railway`
31610 } else if (!primary && primaries.indexOf(v) !== -1) { // e.g. `abandoned=railway`
31613 classes += ' tag-' + v;
31614 } // else ignore e.g. `highway=path + abandoned=railway`
31621 classes += ' tag-status tag-status-' + status;
31624 // add any secondary (structure) tags
31625 for (i = 0; i < secondaries.length; i++) {
31626 k = secondaries[i];
31628 if (!v || v === 'no') continue;
31629 classes += ' tag-' + k + ' tag-' + k + '-' + v;
31632 // For highways, look for surface tagging..
31633 if (primary === 'highway') {
31634 var paved = (t.highway !== 'track');
31637 if (k in iD.pavedTags) {
31638 paved = !!iD.pavedTags[k][v];
31643 classes += ' tag-unpaved';
31647 classes = classes.trim();
31649 if (classes !== value) {
31650 d3.select(this).attr('class', classes);
31655 tagClasses.tags = function(_) {
31656 if (!arguments.length) return tags;
31663 iD.svg.Turns = function(projection) {
31664 return function drawTurns(surface, graph, turns) {
31665 function key(turn) {
31666 return [turn.from.node + turn.via.node + turn.to.node].join('-');
31669 function icon(turn) {
31670 var u = turn.u ? '-u' : '';
31671 if (!turn.restriction)
31672 return '#turn-yes' + u;
31673 var restriction = graph.entity(turn.restriction).tags.restriction;
31675 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
31678 var groups = surface.selectAll('.layer-hit').selectAll('g.turn')
31682 var enter = groups.enter().append('g')
31683 .attr('class', 'turn');
31685 var nEnter = enter.filter(function (turn) { return !turn.u; });
31687 nEnter.append('rect')
31688 .attr('transform', 'translate(-22, -12)')
31689 .attr('width', '44')
31690 .attr('height', '24');
31692 nEnter.append('use')
31693 .attr('transform', 'translate(-22, -12)')
31694 .attr('width', '44')
31695 .attr('height', '24');
31698 var uEnter = enter.filter(function (turn) { return turn.u; });
31700 uEnter.append('circle')
31703 uEnter.append('use')
31704 .attr('transform', 'translate(-16, -16)')
31705 .attr('width', '32')
31706 .attr('height', '32');
31711 .attr('transform', function (turn) {
31712 var v = graph.entity(turn.via.node),
31713 t = graph.entity(turn.to.node),
31714 a = iD.geo.angle(v, t, projection),
31715 p = projection(v.loc),
31716 r = turn.u ? 0 : 60;
31718 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
31719 'rotate(' + a * 180 / Math.PI + ')';
31722 groups.select('use')
31723 .attr('xlink:href', icon);
31725 groups.select('rect');
31726 groups.select('circle');
31736 iD.svg.Vertices = function(projection, context) {
31738 // z16-, z17, z18+, tagged
31739 shadow: [6, 7.5, 7.5, 11.5],
31740 stroke: [2.5, 3.5, 3.5, 7],
31741 fill: [1, 1.5, 1.5, 1.5]
31746 function siblingAndChildVertices(ids, graph, extent) {
31749 function addChildVertices(entity) {
31750 if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
31752 if (entity.type === 'way') {
31753 for (i = 0; i < entity.nodes.length; i++) {
31754 addChildVertices(graph.entity(entity.nodes[i]));
31756 } else if (entity.type === 'relation') {
31757 for (i = 0; i < entity.members.length; i++) {
31758 var member = context.hasEntity(entity.members[i].id);
31760 addChildVertices(member);
31763 } else if (entity.intersects(extent, graph)) {
31764 vertices[entity.id] = entity;
31769 ids.forEach(function(id) {
31770 var entity = context.hasEntity(id);
31771 if (entity && entity.type === 'node') {
31772 vertices[entity.id] = entity;
31773 context.graph().parentWays(entity).forEach(function(entity) {
31774 addChildVertices(entity);
31776 } else if (entity) {
31777 addChildVertices(entity);
31784 function draw(selection, vertices, klass, graph, zoom) {
31786 z = (zoom < 17 ? 0 : zoom < 18 ? 1 : 2);
31788 var groups = selection
31789 .data(vertices, iD.Entity.key);
31791 function icon(entity) {
31792 if (entity.id in icons) return icons[entity.id];
31794 entity.hasInterestingTags() &&
31795 context.presets().match(entity, graph).icon;
31796 return icons[entity.id];
31799 function setClass(klass) {
31800 return function(entity) {
31801 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
31805 function setAttributes(selection) {
31806 ['shadow','stroke','fill'].forEach(function(klass) {
31807 var rads = radiuses[klass];
31808 selection.selectAll('.' + klass)
31809 .each(function(entity) {
31810 var i = z && icon(entity),
31812 r = rads[i ? 3 : z];
31813 this.setAttribute('cx', c);
31814 this.setAttribute('cy', -c);
31815 this.setAttribute('r', r);
31816 if (i && klass === 'fill') {
31817 this.setAttribute('visibility', 'hidden');
31819 this.removeAttribute('visibility');
31824 selection.selectAll('use')
31827 this.removeAttribute('visibility');
31829 this.setAttribute('visibility', 'hidden');
31834 var enter = groups.enter()
31836 .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
31838 enter.append('circle')
31839 .each(setClass('shadow'));
31841 enter.append('circle')
31842 .each(setClass('stroke'));
31844 // Vertices with icons get a `use`.
31845 enter.filter(function(d) { return icon(d); })
31847 .attr('transform', 'translate(-6, -6)')
31848 .attr('xlink:href', function(d) { return '#' + icon(d) + '-12'; })
31849 .attr('width', '12px')
31850 .attr('height', '12px')
31851 .each(setClass('icon'));
31853 // Vertices with tags get a fill.
31854 enter.filter(function(d) { return d.hasInterestingTags(); })
31856 .each(setClass('fill'));
31859 .attr('transform', iD.svg.PointTransform(projection))
31860 .classed('shared', function(entity) { return graph.isShared(entity); })
31861 .call(setAttributes);
31867 function drawVertices(surface, graph, entities, filter, extent, zoom) {
31868 var selected = siblingAndChildVertices(context.selectedIDs(), graph, extent),
31869 wireframe = surface.classed('fill-wireframe'),
31872 for (var i = 0; i < entities.length; i++) {
31873 var entity = entities[i],
31874 geometry = entity.geometry(graph);
31876 if (wireframe && geometry === 'point') {
31877 vertices.push(entity);
31881 if (geometry !== 'vertex')
31884 if (entity.id in selected ||
31885 entity.hasInterestingTags() ||
31886 entity.isIntersection(graph)) {
31887 vertices.push(entity);
31891 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-persistent')
31893 .call(draw, vertices, 'vertex-persistent', graph, zoom);
31895 drawHover(surface, graph, extent, zoom);
31898 function drawHover(surface, graph, extent, zoom) {
31899 var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent) : {};
31901 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-hover')
31902 .call(draw, d3.values(hovered), 'vertex-hover', graph, zoom);
31905 drawVertices.drawHover = function(surface, graph, target, extent, zoom) {
31906 if (target === hover) return;
31908 drawHover(surface, graph, extent, zoom);
31911 return drawVertices;
31913 iD.ui = function(context) {
31914 function render(container) {
31915 var map = context.map();
31917 if (iD.detect().opera) container.classed('opera', true);
31919 var hash = iD.behavior.Hash(context);
31923 if (!hash.hadHash) {
31924 map.centerZoom([0, 0], 2);
31927 container.append('svg')
31928 .attr('id', 'defs')
31929 .call(iD.svg.Defs(context));
31931 container.append('div')
31932 .attr('id', 'sidebar')
31933 .attr('class', 'col4')
31936 var content = container.append('div')
31937 .attr('id', 'content');
31939 var bar = content.append('div')
31941 .attr('class', 'fillD');
31943 content.append('div')
31948 .call(iD.ui.MapInMap(context));
31950 content.append('div')
31951 .call(iD.ui.Info(context));
31954 .attr('class', 'spacer col4');
31956 var limiter = bar.append('div')
31957 .attr('class', 'limiter');
31959 limiter.append('div')
31960 .attr('class', 'button-wrap joined col3')
31961 .call(iD.ui.Modes(context), limiter);
31963 limiter.append('div')
31964 .attr('class', 'button-wrap joined col1')
31965 .call(iD.ui.UndoRedo(context));
31967 limiter.append('div')
31968 .attr('class', 'button-wrap col1')
31969 .call(iD.ui.Save(context));
31972 .attr('class', 'full-screen')
31973 .call(iD.ui.FullScreen(context));
31976 .attr('class', 'spinner')
31977 .call(iD.ui.Spinner(context));
31979 var controls = bar.append('div')
31980 .attr('class', 'map-controls');
31982 controls.append('div')
31983 .attr('class', 'map-control zoombuttons')
31984 .call(iD.ui.Zoom(context));
31986 controls.append('div')
31987 .attr('class', 'map-control geolocate-control')
31988 .call(iD.ui.Geolocate(context));
31990 controls.append('div')
31991 .attr('class', 'map-control background-control')
31992 .call(iD.ui.Background(context));
31994 controls.append('div')
31995 .attr('class', 'map-control map-data-control')
31996 .call(iD.ui.MapData(context));
31998 controls.append('div')
31999 .attr('class', 'map-control help-control')
32000 .call(iD.ui.Help(context));
32002 var about = content.append('div')
32003 .attr('id', 'about');
32005 about.append('div')
32006 .attr('id', 'attrib')
32007 .call(iD.ui.Attribution(context));
32009 var footer = about.append('div')
32010 .attr('id', 'footer')
32011 .attr('class', 'fillD');
32013 footer.append('div')
32014 .attr('class', 'api-status')
32015 .call(iD.ui.Status(context));
32017 footer.append('div')
32018 .attr('id', 'scale-block')
32019 .call(iD.ui.Scale(context));
32021 var aboutList = footer.append('div')
32022 .attr('id', 'info-block')
32024 .attr('id', 'about-list');
32026 if (!context.embed()) {
32027 aboutList.call(iD.ui.Account(context));
32030 aboutList.append('li')
32032 .attr('target', '_blank')
32033 .attr('tabindex', -1)
32034 .attr('href', 'https://github.com/openstreetmap/iD')
32037 var issueLinks = aboutList.append('li');
32039 issueLinks.append('a')
32040 .attr('target', '_blank')
32041 .attr('tabindex', -1)
32042 .attr('href', 'https://github.com/openstreetmap/iD/issues')
32043 .call(iD.svg.Icon('#icon-bug', 'light'))
32044 .call(bootstrap.tooltip()
32045 .title(t('report_a_bug'))
32049 issueLinks.append('a')
32050 .attr('target', '_blank')
32051 .attr('tabindex', -1)
32052 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
32053 .call(iD.svg.Icon('#icon-translate', 'light'))
32054 .call(bootstrap.tooltip()
32055 .title(t('help_translate'))
32059 aboutList.append('li')
32060 .attr('class', 'feature-warning')
32061 .attr('tabindex', -1)
32062 .call(iD.ui.FeatureInfo(context));
32064 aboutList.append('li')
32065 .attr('class', 'user-list')
32066 .attr('tabindex', -1)
32067 .call(iD.ui.Contributors(context));
32069 window.onbeforeunload = function() {
32070 return context.save();
32073 window.onunload = function() {
32074 context.history().unlock();
32077 var mapDimensions = map.dimensions();
32079 d3.select(window).on('resize.editor', function() {
32080 mapDimensions = content.dimensions(null);
32081 map.dimensions(mapDimensions);
32085 return function() {
32086 d3.event.preventDefault();
32087 if (!context.inIntro()) context.pan(d);
32094 var keybinding = d3.keybinding('main')
32095 .on('⌫', function() { d3.event.preventDefault(); })
32096 .on('←', pan([pa, 0]))
32097 .on('↑', pan([0, pa]))
32098 .on('→', pan([-pa, 0]))
32099 .on('↓', pan([0, -pa]))
32100 .on('⇧←', pan([mapDimensions[0], 0]))
32101 .on('⇧↑', pan([0, mapDimensions[1]]))
32102 .on('⇧→', pan([-mapDimensions[0], 0]))
32103 .on('⇧↓', pan([0, -mapDimensions[1]]))
32104 .on(iD.ui.cmd('⌘←'), pan([mapDimensions[0], 0]))
32105 .on(iD.ui.cmd('⌘↑'), pan([0, mapDimensions[1]]))
32106 .on(iD.ui.cmd('⌘→'), pan([-mapDimensions[0], 0]))
32107 .on(iD.ui.cmd('⌘↓'), pan([0, -mapDimensions[1]]));
32109 d3.select(document)
32112 context.enter(iD.modes.Browse(context));
32114 context.container()
32115 .call(iD.ui.Splash(context))
32116 .call(iD.ui.Restore(context));
32118 var authenticating = iD.ui.Loading(context)
32119 .message(t('loading_auth'));
32121 context.connection()
32122 .on('authenticating.ui', function() {
32123 context.container()
32124 .call(authenticating);
32126 .on('authenticated.ui', function() {
32127 authenticating.close();
32131 function ui(container) {
32132 context.container(container);
32133 context.loadLocale(function() {
32138 ui.sidebar = iD.ui.Sidebar(context);
32143 iD.ui.tooltipHtml = function(text, key) {
32144 var s = '<span>' + text + '</span>';
32146 s += '<div class="keyhint-wrap">' +
32147 '<span> ' + (t('tooltip_keyhint')) + ' </span>' +
32148 '<span class="keyhint"> ' + key + '</span></div>';
32152 iD.ui.Account = function(context) {
32153 var connection = context.connection();
32155 function update(selection) {
32156 if (!connection.authenticated()) {
32157 selection.selectAll('#userLink, #logoutLink')
32158 .classed('hide', true);
32162 connection.userDetails(function(err, details) {
32163 var userLink = selection.select('#userLink'),
32164 logoutLink = selection.select('#logoutLink');
32167 logoutLink.html('');
32171 selection.selectAll('#userLink, #logoutLink')
32172 .classed('hide', false);
32175 userLink.append('a')
32176 .attr('href', connection.userURL(details.display_name))
32177 .attr('target', '_blank');
32179 // Add thumbnail or dont
32180 if (details.image_url) {
32181 userLink.append('img')
32182 .attr('class', 'icon pre-text user-icon')
32183 .attr('src', details.image_url);
32186 .call(iD.svg.Icon('#icon-avatar', 'pre-text light'));
32190 userLink.append('span')
32191 .attr('class', 'label')
32192 .text(details.display_name);
32194 logoutLink.append('a')
32195 .attr('class', 'logout')
32198 .on('click.logout', function() {
32199 d3.event.preventDefault();
32200 connection.logout();
32205 return function(selection) {
32206 selection.append('li')
32207 .attr('id', 'logoutLink')
32208 .classed('hide', true);
32210 selection.append('li')
32211 .attr('id', 'userLink')
32212 .classed('hide', true);
32214 connection.on('auth.account', function() { update(selection); });
32218 iD.ui.Attribution = function(context) {
32221 function attribution(data, klass) {
32222 var div = selection.selectAll('.' + klass)
32227 .attr('class', klass);
32229 var background = div.selectAll('.attribution')
32230 .data(data, function(d) { return d.name(); });
32234 .attr('class', 'attribution')
32235 .each(function(d) {
32236 if (d.terms_html) {
32238 .html(d.terms_html);
32242 var source = d.terms_text || d.id || d.name();
32245 source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
32251 .attr('href', d.terms_url)
32252 .attr('target', '_blank')
32263 var copyright = background.selectAll('.copyright-notice')
32264 .data(function(d) {
32265 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
32266 return notice ? [notice] : [];
32271 .attr('class', 'copyright-notice');
32273 copyright.text(String);
32279 function update() {
32280 attribution([context.background().baseLayerSource()], 'base-layer-attribution');
32281 attribution(context.background().overlayLayerSources().filter(function (s) {
32282 return s.validZoom(context.map().zoom());
32283 }), 'overlay-layer-attribution');
32286 return function(select) {
32287 selection = select;
32289 context.background()
32290 .on('change.attribution', update);
32293 .on('move.attribution', _.throttle(update, 400, {leading: false}));
32298 iD.ui.Background = function(context) {
32300 opacities = [1, 0.75, 0.5, 0.25],
32304 ['right', [-1, 0]],
32305 ['bottom', [0, 1]]],
32306 opacityDefault = (context.storage('background-opacity') !== null) ?
32307 (+context.storage('background-opacity')) : 1.0,
32308 customTemplate = context.storage('background-custom-template') || '';
32310 // Can be 0 from <1.3.0 use or due to issue #1923.
32311 if (opacityDefault === 0) opacityDefault = 1.0;
32313 function background(selection) {
32315 function sortSources(a, b) {
32316 return a.best() ? -1
32318 : a.id === 'none' ? 1
32319 : b.id === 'none' ? -1
32320 : d3.ascending(a, b);
32323 function setOpacity(d) {
32324 var bg = context.container().selectAll('.layer-background')
32326 .style('opacity', d)
32327 .attr('data-opacity', d);
32329 if (!iD.detect().opera) {
32330 iD.util.setTransform(bg, 0, 0);
32333 opacityList.selectAll('li')
32334 .classed('active', function(_) { return _ === d; });
32336 context.storage('background-opacity', d);
32339 function selectLayer() {
32340 function active(d) {
32341 return context.background().showsLayer(d);
32344 content.selectAll('.layer, .custom_layer')
32345 .classed('active', active)
32346 .selectAll('input')
32347 .property('checked', active);
32350 function clickSetSource(d) {
32351 d3.event.preventDefault();
32352 context.background().baseLayerSource(d);
32356 function editCustom() {
32357 d3.event.preventDefault();
32358 var template = window.prompt(t('background.custom_prompt'), customTemplate);
32360 template.indexOf('google.com') !== -1 ||
32361 template.indexOf('googleapis.com') !== -1 ||
32362 template.indexOf('google.ru') !== -1) {
32366 setCustom(template);
32369 function setCustom(template) {
32370 context.background().baseLayerSource(iD.BackgroundSource.Custom(template));
32372 context.storage('background-custom-template', template);
32375 function clickSetOverlay(d) {
32376 d3.event.preventDefault();
32377 context.background().toggleOverlayLayer(d);
32381 function drawList(layerList, type, change, filter) {
32382 var sources = context.background()
32383 .sources(context.map().extent())
32386 var layerLinks = layerList.selectAll('li.layer')
32387 .data(sources, function(d) { return d.name(); })
32388 .sort(sortSources);
32390 var enter = layerLinks.enter()
32391 .insert('li', '.custom_layer')
32392 .attr('class', 'layer')
32393 .classed('best', function(d) { return d.best(); });
32395 // only set tooltips for layers with tooltips
32396 enter.filter(function(d) { return d.description; })
32397 .call(bootstrap.tooltip()
32398 .title(function(d) { return d.description; })
32399 .placement('top'));
32401 enter.filter(function(d) { return d.best(); })
32403 .attr('class', 'best')
32404 .call(bootstrap.tooltip()
32405 .title(t('background.best_imagery'))
32406 .placement('left'))
32410 var label = enter.append('label');
32412 label.append('input')
32413 .attr('type', type)
32414 .attr('name', 'layers')
32415 .on('change', change);
32417 label.append('span')
32418 .text(function(d) { return d.name(); });
32423 layerList.style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
32426 function update() {
32427 backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
32428 overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
32432 var source = context.background().baseLayerSource();
32433 if (source.id === 'custom') {
32434 customTemplate = source.template;
32438 function clickNudge(d) {
32439 var timeout = window.setTimeout(function() {
32440 interval = window.setInterval(nudge, 100);
32444 d3.select(this).on('mouseup', function() {
32445 window.clearInterval(interval);
32446 window.clearTimeout(timeout);
32451 var offset = context.background()
32452 .nudge(d[1], context.map().zoom())
32454 resetButton.classed('disabled', offset[0] === 0 && offset[1] === 0);
32458 function hide() { setVisible(false); }
32460 function toggle() {
32461 if (d3.event) d3.event.preventDefault();
32462 tooltip.hide(button);
32463 setVisible(!button.classed('active'));
32466 function setVisible(show) {
32467 if (show !== shown) {
32468 button.classed('active', show);
32472 selection.on('mousedown.background-inside', function() {
32473 return d3.event.stopPropagation();
32475 content.style('display', 'block')
32476 .style('right', '-300px')
32479 .style('right', '0px');
32481 content.style('display', 'block')
32482 .style('right', '0px')
32485 .style('right', '-300px')
32486 .each('end', function() {
32487 d3.select(this).style('display', 'none');
32489 selection.on('mousedown.background-inside', null);
32495 var content = selection.append('div')
32496 .attr('class', 'fillL map-overlay col3 content hide'),
32497 tooltip = bootstrap.tooltip()
32500 .title(iD.ui.tooltipHtml(t('background.description'), key)),
32501 button = selection.append('button')
32502 .attr('tabindex', -1)
32503 .on('click', toggle)
32504 .call(iD.svg.Icon('#icon-layers', 'light'))
32508 var opa = content.append('div')
32509 .attr('class', 'opacity-options-wrapper');
32512 .text(t('background.title'));
32514 var opacityList = opa.append('ul')
32515 .attr('class', 'opacity-options');
32517 opacityList.selectAll('div.opacity')
32521 .attr('data-original-title', function(d) {
32522 return t('background.percent_brightness', { opacity: (d * 100) });
32524 .on('click.set-opacity', setOpacity)
32525 .html('<div class="select-box"></div>')
32526 .call(bootstrap.tooltip()
32527 .placement('left'))
32529 .attr('class', 'opacity')
32530 .style('opacity', function(d) { return 1.25 - d; });
32532 var backgroundList = content.append('ul')
32533 .attr('class', 'layer-list');
32535 var custom = backgroundList.append('li')
32536 .attr('class', 'custom_layer')
32537 .datum(iD.BackgroundSource.Custom());
32539 custom.append('button')
32540 .attr('class', 'layer-browse')
32541 .call(bootstrap.tooltip()
32542 .title(t('background.custom_button'))
32543 .placement('left'))
32544 .on('click', editCustom)
32545 .call(iD.svg.Icon('#icon-search'));
32547 var label = custom.append('label');
32549 label.append('input')
32550 .attr('type', 'radio')
32551 .attr('name', 'layers')
32552 .on('change', function () {
32553 if (customTemplate) {
32554 setCustom(customTemplate);
32560 label.append('span')
32561 .text(t('background.custom'));
32563 content.append('div')
32564 .attr('class', 'imagery-faq')
32566 .attr('target', '_blank')
32567 .attr('tabindex', -1)
32568 .call(iD.svg.Icon('#icon-out-link', 'inline'))
32569 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
32571 .text(t('background.imagery_source_faq'));
32573 var overlayList = content.append('ul')
32574 .attr('class', 'layer-list');
32576 var controls = content.append('div')
32577 .attr('class', 'controls-list');
32579 var minimapLabel = controls
32581 .call(bootstrap.tooltip()
32583 .title(iD.ui.tooltipHtml(t('background.minimap.tooltip'), '/'))
32587 minimapLabel.classed('minimap-toggle', true)
32589 .attr('type', 'checkbox')
32590 .on('change', function() {
32591 iD.ui.MapInMap.toggle();
32592 d3.event.preventDefault();
32595 minimapLabel.append('span')
32596 .text(t('background.minimap.description'));
32598 var adjustments = content.append('div')
32599 .attr('class', 'adjustments');
32601 adjustments.append('a')
32602 .text(t('background.fix_misalignment'))
32604 .classed('hide-toggle', true)
32605 .classed('expanded', false)
32606 .on('click', function() {
32607 var exp = d3.select(this).classed('expanded');
32608 nudgeContainer.style('display', exp ? 'none' : 'block');
32609 d3.select(this).classed('expanded', !exp);
32610 d3.event.preventDefault();
32613 var nudgeContainer = adjustments.append('div')
32614 .attr('class', 'nudge-container cf')
32615 .style('display', 'none');
32617 nudgeContainer.selectAll('button')
32618 .data(directions).enter()
32620 .attr('class', function(d) { return d[0] + ' nudge'; })
32621 .on('mousedown', clickNudge);
32623 var resetButton = nudgeContainer
32625 .attr('class', 'reset disabled')
32626 .on('click', function () {
32627 context.background().offset([0, 0]);
32628 resetButton.classed('disabled', true);
32630 .call(iD.svg.Icon('#icon-undo'));
32633 .on('move.background-update', _.debounce(update, 1000));
32635 context.background()
32636 .on('change.background-update', update);
32639 setOpacity(opacityDefault);
32641 var keybinding = d3.keybinding('background')
32646 d3.select(document)
32649 context.surface().on('mousedown.background-outside', hide);
32650 context.container().on('mousedown.background-outside', hide);
32655 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
32656 // For example, ⌘Z -> Ctrl+Z
32657 iD.ui.cmd = function(code) {
32658 if (iD.detect().os === 'mac') {
32662 if (iD.detect().os === 'win') {
32663 if (code === '⌘⇧Z') return 'Ctrl+Y';
32675 for (var i = 0; i < code.length; i++) {
32676 if (code[i] in replacements) {
32677 result += replacements[code[i]] + '+';
32685 iD.ui.Commit = function(context) {
32686 var dispatch = d3.dispatch('cancel', 'save');
32688 function commit(selection) {
32689 var changes = context.history().changes(),
32690 summary = context.history().difference().summary();
32692 function zoomToEntity(change) {
32693 var entity = change.entity;
32694 if (change.changeType !== 'deleted' &&
32695 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
32696 context.map().zoomTo(entity);
32697 context.surface().selectAll(
32698 iD.util.entityOrMemberSelector([entity.id], context.graph()))
32699 .classed('hover', true);
32703 var header = selection.append('div')
32704 .attr('class', 'header fillL');
32706 header.append('h3')
32707 .text(t('commit.title'));
32709 var body = selection.append('div')
32710 .attr('class', 'body');
32714 var commentSection = body.append('div')
32715 .attr('class', 'modal-section form-field commit-form');
32717 commentSection.append('label')
32718 .attr('class', 'form-label')
32719 .text(t('commit.message_label'));
32721 var commentField = commentSection.append('textarea')
32722 .attr('placeholder', t('commit.description_placeholder'))
32723 .attr('maxlength', 255)
32724 .property('value', context.storage('comment') || '')
32725 .on('input.save', enableDisableSaveButton)
32726 .on('change.save', enableDisableSaveButton)
32727 .on('blur.save', function() {
32728 context.storage('comment', this.value);
32731 function enableDisableSaveButton() {
32732 d3.selectAll('.save-section .save-button')
32733 .attr('disabled', (this.value.length ? null : true));
32736 commentField.node().select();
32738 context.connection().userChangesets(function (err, changesets) {
32743 for (var i = 0; i < changesets.length; i++) {
32744 if (changesets[i].tags.comment) {
32746 title: changesets[i].tags.comment,
32747 value: changesets[i].tags.comment
32752 commentField.call(d3.combobox().data(comments));
32755 var changeSetInfo = commentSection.append('div')
32756 .attr('class', 'changeset-info');
32758 changeSetInfo.append('a')
32759 .attr('target', '_blank')
32760 .attr('tabindex', -1)
32761 .call(iD.svg.Icon('#icon-out-link', 'inline'))
32762 .attr('href', t('commit.about_changeset_comments_link'))
32764 .text(t('commit.about_changeset_comments'));
32767 var warnings = body.selectAll('div.warning-section')
32768 .data([context.history().validate(changes)])
32771 .attr('class', 'modal-section warning-section fillL2')
32772 .style('display', function(d) { return _.isEmpty(d) ? 'none' : null; })
32773 .style('background', '#ffb');
32775 warnings.append('h3')
32776 .text(t('commit.warnings'));
32778 var warningLi = warnings.append('ul')
32779 .attr('class', 'changeset-list')
32781 .data(function(d) { return d; })
32785 .on('mouseover', mouseover)
32786 .on('mouseout', mouseout)
32787 .on('click', warningClick);
32790 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
32793 .append('strong').text(function(d) {
32797 warningLi.filter(function(d) { return d.tooltip; })
32798 .call(bootstrap.tooltip()
32799 .title(function(d) { return d.tooltip; })
32804 // Upload Explanation
32805 var saveSection = body.append('div')
32806 .attr('class','modal-section save-section fillL cf');
32808 var prose = saveSection.append('p')
32809 .attr('class', 'commit-info')
32810 .html(t('commit.upload_explanation'));
32812 context.connection().userDetails(function(err, user) {
32815 var userLink = d3.select(document.createElement('div'));
32817 if (user.image_url) {
32818 userLink.append('img')
32819 .attr('src', user.image_url)
32820 .attr('class', 'icon pre-text user-icon');
32823 userLink.append('a')
32824 .attr('class','user-info')
32825 .text(user.display_name)
32826 .attr('href', context.connection().userURL(user.display_name))
32827 .attr('tabindex', -1)
32828 .attr('target', '_blank');
32830 prose.html(t('commit.upload_explanation_with_user', {user: userLink.html()}));
32835 var buttonSection = saveSection.append('div')
32836 .attr('class','buttons fillL cf');
32838 var saveButton = buttonSection.append('button')
32839 .attr('class', 'action col5 button save-button')
32840 .attr('disabled', function() {
32841 var n = d3.select('.commit-form textarea').node();
32842 return (n && n.value.length) ? null : true;
32844 .on('click.save', function() {
32846 comment: commentField.node().value
32850 saveButton.append('span')
32851 .attr('class', 'label')
32852 .text(t('commit.save'));
32854 var cancelButton = buttonSection.append('button')
32855 .attr('class', 'action col5 button cancel-button')
32856 .on('click.cancel', function() { dispatch.cancel(); });
32858 cancelButton.append('span')
32859 .attr('class', 'label')
32860 .text(t('commit.cancel'));
32864 var changeSection = body.selectAll('div.commit-section')
32868 .attr('class', 'commit-section modal-section fillL2');
32870 changeSection.append('h3')
32871 .text(t('commit.changes', {count: summary.length}));
32873 var li = changeSection.append('ul')
32874 .attr('class', 'changeset-list')
32879 .on('mouseover', mouseover)
32880 .on('mouseout', mouseout)
32881 .on('click', zoomToEntity);
32883 li.each(function(d) {
32885 .call(iD.svg.Icon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
32889 .attr('class', 'change-type')
32890 .text(function(d) {
32891 return t('commit.' + d.changeType) + ' ';
32894 li.append('strong')
32895 .attr('class', 'entity-type')
32896 .text(function(d) {
32897 return context.presets().match(d.entity, d.graph).name();
32901 .attr('class', 'entity-name')
32902 .text(function(d) {
32903 var name = iD.util.displayName(d.entity) || '',
32905 if (name !== '') string += ':';
32906 return string += ' ' + name;
32909 li.style('opacity', 0)
32911 .style('opacity', 1);
32913 li.style('opacity', 0)
32915 .style('opacity', 1);
32917 function mouseover(d) {
32919 context.surface().selectAll(
32920 iD.util.entityOrMemberSelector([d.entity.id], context.graph())
32921 ).classed('hover', true);
32925 function mouseout() {
32926 context.surface().selectAll('.hover')
32927 .classed('hover', false);
32930 function warningClick(d) {
32932 context.map().zoomTo(d.entity);
32934 iD.modes.Select(context, [d.entity.id])
32935 .suppressMenu(true));
32940 return d3.rebind(commit, dispatch, 'on');
32942 iD.ui.confirm = function(selection) {
32943 var modal = iD.ui.modal(selection);
32945 modal.select('.modal')
32946 .classed('modal-alert', true);
32948 var section = modal.select('.content');
32950 section.append('div')
32951 .attr('class', 'modal-section header');
32953 section.append('div')
32954 .attr('class', 'modal-section message-text');
32956 var buttons = section.append('div')
32957 .attr('class', 'modal-section buttons cf');
32959 modal.okButton = function() {
32962 .attr('class', 'action col4')
32963 .on('click.confirm', function() {
32966 .text(t('confirm.okay'));
32973 iD.ui.Conflicts = function(context) {
32974 var dispatch = d3.dispatch('download', 'cancel', 'save'),
32977 function conflicts(selection) {
32978 var header = selection
32980 .attr('class', 'header fillL');
32984 .attr('class', 'fr')
32985 .on('click', function() { dispatch.cancel(); })
32986 .call(iD.svg.Icon('#icon-close'));
32990 .text(t('save.conflict.header'));
32992 var body = selection
32994 .attr('class', 'body fillL');
32998 .attr('class', 'conflicts-help')
32999 .text(t('save.conflict.help'))
33001 .attr('class', 'conflicts-download')
33002 .text(t('save.conflict.download_changes'))
33003 .on('click.download', function() { dispatch.download(); });
33007 .attr('class', 'conflict-container fillL3')
33008 .call(showConflict, 0);
33012 .attr('class', 'conflicts-done')
33013 .attr('opacity', 0)
33014 .style('display', 'none')
33015 .text(t('save.conflict.done'));
33019 .attr('class','buttons col12 joined conflicts-buttons');
33023 .attr('disabled', list.length > 1)
33024 .attr('class', 'action conflicts-button col6')
33025 .text(t('save.title'))
33026 .on('click.try_again', function() { dispatch.save(); });
33030 .attr('class', 'secondary-action conflicts-button col6')
33031 .text(t('confirm.cancel'))
33032 .on('click.cancel', function() { dispatch.cancel(); });
33036 function showConflict(selection, index) {
33037 if (index < 0 || index >= list.length) return;
33039 var parent = d3.select(selection.node().parentNode);
33041 // enable save button if this is the last conflict being reviewed..
33042 if (index === list.length - 1) {
33043 window.setTimeout(function() {
33044 parent.select('.conflicts-button')
33045 .attr('disabled', null);
33047 parent.select('.conflicts-done')
33049 .attr('opacity', 1)
33050 .style('display', 'block');
33054 var item = selection
33055 .selectAll('.conflict')
33056 .data([list[index]]);
33058 var enter = item.enter()
33060 .attr('class', 'conflict');
33064 .attr('class', 'conflict-count')
33065 .text(t('save.conflict.count', { num: index + 1, total: list.length }));
33069 .attr('class', 'conflict-description')
33071 .text(function(d) { return d.name; })
33072 .on('click', function(d) {
33073 zoomToEntity(d.id);
33074 d3.event.preventDefault();
33077 var details = enter
33079 .attr('class', 'conflict-detail-container');
33083 .attr('class', 'conflict-detail-list')
33085 .data(function(d) { return d.details || []; })
33088 .attr('class', 'conflict-detail-item')
33089 .html(function(d) { return d; });
33093 .attr('class', 'conflict-choices')
33098 .attr('class', 'conflict-nav-buttons joined cf')
33099 .selectAll('button')
33100 .data(['previous', 'next'])
33103 .text(function(d) { return t('save.conflict.' + d); })
33104 .attr('class', 'conflict-nav-button action col6')
33105 .attr('disabled', function(d, i) {
33106 return (i === 0 && index === 0) ||
33107 (i === 1 && index === list.length - 1) || null;
33109 .on('click', function(d, i) {
33110 var container = parent.select('.conflict-container'),
33111 sign = (i === 0 ? -1 : 1);
33114 .selectAll('.conflict')
33118 .call(showConflict, index + sign);
33120 d3.event.preventDefault();
33128 function addChoices(selection) {
33129 var choices = selection
33131 .attr('class', 'layer-list')
33133 .data(function(d) { return d.choices || []; });
33135 var enter = choices.enter()
33137 .attr('class', 'layer');
33144 .attr('type', 'radio')
33145 .attr('name', function(d) { return d.id; })
33146 .on('change', function(d, i) {
33147 var ul = this.parentNode.parentNode.parentNode;
33148 ul.__data__.chosen = i;
33154 .text(function(d) { return d.text; });
33157 .each(function(d, i) {
33158 var ul = this.parentNode;
33159 if (ul.__data__.chosen === i) choose(ul, d);
33163 function choose(ul, datum) {
33164 if (d3.event) d3.event.preventDefault();
33168 .classed('active', function(d) { return d === datum; })
33169 .selectAll('input')
33170 .property('checked', function(d) { return d === datum; });
33172 var extent = iD.geo.Extent(),
33175 entity = context.graph().hasEntity(datum.id);
33176 if (entity) extent._extend(entity.extent(context.graph()));
33180 entity = context.graph().hasEntity(datum.id);
33181 if (entity) extent._extend(entity.extent(context.graph()));
33183 zoomToEntity(datum.id, extent);
33186 function zoomToEntity(id, extent) {
33187 context.surface().selectAll('.hover')
33188 .classed('hover', false);
33190 var entity = context.graph().hasEntity(id);
33193 context.map().trimmedExtent(extent);
33195 context.map().zoomTo(entity);
33197 context.surface().selectAll(
33198 iD.util.entityOrMemberSelector([entity.id], context.graph()))
33199 .classed('hover', true);
33204 // The conflict list should be an array of objects like:
33207 // name: entityName(local),
33208 // details: merge.conflicts(),
33211 // choice(id, keepMine, forceLocal),
33212 // choice(id, keepTheirs, forceRemote)
33215 conflicts.list = function(_) {
33216 if (!arguments.length) return list;
33221 return d3.rebind(conflicts, dispatch, 'on');
33223 iD.ui.Contributors = function(context) {
33224 var debouncedUpdate = _.debounce(function() { update(); }, 1000),
33227 wrap = d3.select(null);
33229 function update() {
33231 entities = context.intersects(context.map().extent());
33233 entities.forEach(function(entity) {
33234 if (entity && entity.user) users[entity.user] = true;
33237 var u = Object.keys(users),
33238 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
33241 .call(iD.svg.Icon('#icon-nearby', 'pre-text light'));
33243 var userList = d3.select(document.createElement('span'));
33245 userList.selectAll()
33249 .attr('class', 'user-link')
33250 .attr('href', function(d) { return context.connection().userURL(d); })
33251 .attr('target', '_blank')
33252 .attr('tabindex', -1)
33255 if (u.length > limit) {
33256 var count = d3.select(document.createElement('span'));
33259 .attr('target', '_blank')
33260 .attr('tabindex', -1)
33261 .attr('href', function() {
33262 return context.connection().changesetsURL(context.map().center(), context.map().zoom());
33264 .text(u.length - limit + 1);
33266 wrap.append('span')
33267 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
33270 wrap.append('span')
33271 .html(t('contributors.list', { users: userList.html() }));
33278 .style('opacity', 0);
33280 } else if (hidden) {
33283 .style('opacity', 1);
33287 return function(selection) {
33291 context.connection().on('loaded.contributors', debouncedUpdate);
33292 context.map().on('move.contributors', debouncedUpdate);
33295 iD.ui.Disclosure = function() {
33296 var dispatch = d3.dispatch('toggled'),
33299 content = function () {};
33301 var disclosure = function(selection) {
33302 var $link = selection.selectAll('.hide-toggle')
33305 $link.enter().append('a')
33307 .attr('class', 'hide-toggle');
33310 .on('click', toggle)
33311 .classed('expanded', expanded);
33313 var $body = selection.selectAll('div')
33316 $body.enter().append('div');
33318 $body.classed('hide', !expanded)
33321 function toggle() {
33322 expanded = !expanded;
33323 $link.classed('expanded', expanded);
33324 $body.call(iD.ui.Toggle(expanded));
33325 dispatch.toggled(expanded);
33329 disclosure.title = function(_) {
33330 if (!arguments.length) return title;
33335 disclosure.expanded = function(_) {
33336 if (!arguments.length) return expanded;
33341 disclosure.content = function(_) {
33342 if (!arguments.length) return content;
33347 return d3.rebind(disclosure, dispatch, 'on');
33349 iD.ui.EntityEditor = function(context) {
33350 var dispatch = d3.dispatch('choose'),
33352 coalesceChanges = false,
33359 var presetEditor = iD.ui.preset(context)
33360 .on('change', changeTags);
33361 var rawTagEditor = iD.ui.RawTagEditor(context)
33362 .on('change', changeTags);
33364 function entityEditor(selection) {
33365 var entity = context.entity(id),
33366 tags = _.clone(entity.tags);
33368 var $header = selection.selectAll('.header')
33372 var $enter = $header.enter().append('div')
33373 .attr('class', 'header fillL cf');
33375 $enter.append('button')
33376 .attr('class', 'fl preset-reset preset-choose')
33380 $enter.append('button')
33381 .attr('class', 'fr preset-close')
33382 .call(iD.svg.Icon(modified ? '#icon-apply' : '#icon-close'));
33384 $enter.append('h3');
33387 $header.select('h3')
33388 .text(t('inspector.edit'));
33390 $header.select('.preset-close')
33391 .on('click', function() {
33392 context.enter(iD.modes.Browse(context));
33395 var $body = selection.selectAll('.inspector-body')
33399 $enter = $body.enter().append('div')
33400 .attr('class', 'inspector-body');
33402 $enter.append('div')
33403 .attr('class', 'preset-list-item inspector-inner')
33405 .attr('class', 'preset-list-button-wrap')
33407 .attr('class', 'preset-list-button preset-reset')
33408 .call(bootstrap.tooltip()
33409 .title(t('inspector.back_tooltip'))
33410 .placement('bottom'))
33412 .attr('class', 'label');
33414 $body.select('.preset-list-button-wrap')
33415 .call(reference.button);
33417 $body.select('.preset-list-item')
33418 .call(reference.body);
33420 $enter.append('div')
33421 .attr('class', 'inspector-border inspector-preset');
33423 $enter.append('div')
33424 .attr('class', 'inspector-border raw-tag-editor inspector-inner');
33426 $enter.append('div')
33427 .attr('class', 'inspector-border raw-member-editor inspector-inner');
33429 $enter.append('div')
33430 .attr('class', 'raw-membership-editor inspector-inner');
33432 selection.selectAll('.preset-reset')
33433 .on('click', function() {
33434 dispatch.choose(preset);
33438 $body.select('.preset-list-item button')
33439 .call(iD.ui.PresetIcon()
33440 .geometry(context.geometry(id))
33443 $body.select('.preset-list-item .label')
33444 .text(preset.name());
33446 $body.select('.inspector-preset')
33453 $body.select('.raw-tag-editor')
33460 if (entity.type === 'relation') {
33461 $body.select('.raw-member-editor')
33462 .style('display', 'block')
33463 .call(iD.ui.RawMemberEditor(context)
33466 $body.select('.raw-member-editor')
33467 .style('display', 'none');
33470 $body.select('.raw-membership-editor')
33471 .call(iD.ui.RawMembershipEditor(context)
33474 function historyChanged() {
33475 if (state === 'hide') return;
33477 var entity = context.hasEntity(id),
33478 graph = context.graph();
33479 if (!entity) return;
33481 entityEditor.preset(context.presets().match(entity, graph));
33482 entityEditor.modified(base !== graph);
33483 entityEditor(selection);
33487 .on('change.entity-editor', historyChanged);
33490 function clean(o) {
33492 function cleanVal(k, v) {
33493 function keepSpaces(k) {
33494 var whitelist = ['opening_hours', 'service_times', 'collection_times',
33495 'operating_times', 'smoking_hours', 'happy_hours'];
33496 return _.any(whitelist, function(s) { return k.indexOf(s) !== -1; });
33499 var blacklist = ['description', 'note', 'fixme'];
33500 if (_.any(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
33502 var cleaned = v.split(';')
33503 .map(function(s) { return s.trim(); })
33504 .join(keepSpaces(k) ? '; ' : ';');
33506 // The code below is not intended to validate websites and emails.
33507 // It is only intended to prevent obvious copy-paste errors. (#2323)
33509 // clean website- and email-like tags
33510 if (k.indexOf('website') !== -1 ||
33511 k.indexOf('email') !== -1 ||
33512 cleaned.indexOf('http') === 0) {
33514 .replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
33521 var out = {}, k, v;
33523 if (k && (v = o[k]) !== undefined) {
33524 out[k] = cleanVal(k, v);
33530 // Tag changes that fire on input can all get coalesced into a single
33531 // history operation when the user leaves the field. #2342
33532 function changeTags(changed, onInput) {
33533 var entity = context.entity(id),
33534 annotation = t('operations.change_tags.annotation'),
33535 tags = clean(_.extend({}, entity.tags, changed));
33537 if (!_.isEqual(entity.tags, tags)) {
33538 if (coalesceChanges) {
33539 context.overwrite(iD.actions.ChangeTags(id, tags), annotation);
33541 context.perform(iD.actions.ChangeTags(id, tags), annotation);
33542 coalesceChanges = !!onInput;
33547 entityEditor.modified = function(_) {
33548 if (!arguments.length) return modified;
33550 d3.selectAll('button.preset-close use')
33551 .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
33554 entityEditor.state = function(_) {
33555 if (!arguments.length) return state;
33557 return entityEditor;
33560 entityEditor.entityID = function(_) {
33561 if (!arguments.length) return id;
33563 base = context.graph();
33564 entityEditor.preset(context.presets().match(context.entity(id), base));
33565 entityEditor.modified(false);
33566 coalesceChanges = false;
33567 return entityEditor;
33570 entityEditor.preset = function(_) {
33571 if (!arguments.length) return preset;
33572 if (_ !== preset) {
33574 reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context)
33577 return entityEditor;
33580 return d3.rebind(entityEditor, dispatch, 'on');
33582 iD.ui.FeatureInfo = function(context) {
33583 function update(selection) {
33584 var features = context.features(),
33585 stats = features.stats(),
33587 hiddenList = _.compact(_.map(features.hidden(), function(k) {
33590 return String(stats[k]) + ' ' + t('feature.' + k + '.description');
33594 selection.html('');
33596 if (hiddenList.length) {
33597 var tooltip = bootstrap.tooltip()
33600 .title(function() {
33601 return iD.ui.tooltipHtml(hiddenList.join('<br/>'));
33604 var warning = selection.append('a')
33606 .attr('tabindex', -1)
33607 .html(t('feature_info.hidden_warning', { count: count }))
33609 .on('click', function() {
33610 tooltip.hide(warning);
33611 // open map data panel?
33612 d3.event.preventDefault();
33617 .classed('hide', !hiddenList.length);
33620 return function(selection) {
33623 context.features().on('change.feature_info', function() {
33628 iD.ui.FeatureList = function(context) {
33629 var geocodeResults;
33631 function featureList(selection) {
33632 var header = selection.append('div')
33633 .attr('class', 'header fillL cf');
33635 header.append('h3')
33636 .text(t('inspector.feature_list'));
33638 function keypress() {
33639 var q = search.property('value'),
33640 items = list.selectAll('.feature-list-item');
33641 if (d3.event.keyCode === 13 && q.length && items.size()) {
33642 click(items.datum());
33646 function inputevent() {
33647 geocodeResults = undefined;
33651 var searchWrap = selection.append('div')
33652 .attr('class', 'search-header');
33654 var search = searchWrap.append('input')
33655 .attr('placeholder', t('inspector.search'))
33656 .attr('type', 'search')
33657 .on('keypress', keypress)
33658 .on('input', inputevent);
33661 .call(iD.svg.Icon('#icon-search', 'pre-text'));
33663 var listWrap = selection.append('div')
33664 .attr('class', 'inspector-body');
33666 var list = listWrap.append('div')
33667 .attr('class', 'feature-list cf');
33670 .on('exit.feature-list', clearSearch);
33672 .on('drawn.feature-list', mapDrawn);
33674 function clearSearch() {
33675 search.property('value', '');
33679 function mapDrawn(e) {
33685 function features() {
33688 graph = context.graph(),
33689 q = search.property('value').toLowerCase();
33691 if (!q) return result;
33693 var idMatch = q.match(/^([nwr])([0-9]+)$/);
33698 geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
33699 type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
33704 var locationMatch = sexagesimal.pair(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
33706 if (locationMatch) {
33707 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
33711 type: t('inspector.location'),
33712 name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
33717 function addEntity(entity) {
33718 if (entity.id in entities || result.length > 200)
33721 entities[entity.id] = true;
33723 var name = iD.util.displayName(entity) || '';
33724 if (name.toLowerCase().indexOf(q) >= 0) {
33728 geometry: context.geometry(entity.id),
33729 type: context.presets().match(entity, graph).name(),
33734 graph.parentRelations(entity).forEach(function(parent) {
33739 var visible = context.surface().selectAll('.point, .line, .area')[0];
33740 for (var i = 0; i < visible.length && result.length <= 200; i++) {
33741 addEntity(visible[i].__data__);
33744 (geocodeResults || []).forEach(function(d) {
33745 // https://github.com/openstreetmap/iD/issues/1890
33746 if (d.osm_type && d.osm_id) {
33748 id: iD.Entity.id.fromOSM(d.osm_type, d.osm_id),
33749 geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
33750 type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
33751 : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
33752 name: d.display_name,
33753 extent: new iD.geo.Extent(
33754 [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
33755 [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
33763 function drawList() {
33764 var value = search.property('value'),
33765 results = features();
33767 list.classed('filtered', value.length);
33769 var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
33771 var resultsIndicator = list.selectAll('.no-results-item')
33773 .enter().append('button')
33774 .property('disabled', true)
33775 .attr('class', 'no-results-item')
33776 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
33778 resultsIndicator.append('span')
33779 .attr('class', 'entity-name');
33781 list.selectAll('.no-results-item .entity-name')
33782 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
33784 list.selectAll('.geocode-item')
33786 .enter().append('button')
33787 .attr('class', 'geocode-item')
33788 .on('click', geocode)
33790 .attr('class', 'label')
33792 .attr('class', 'entity-name')
33793 .text(t('geocoder.search'));
33795 list.selectAll('.no-results-item')
33796 .style('display', (value.length && !results.length) ? 'block' : 'none');
33798 list.selectAll('.geocode-item')
33799 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
33801 list.selectAll('.feature-list-item')
33805 var items = list.selectAll('.feature-list-item')
33806 .data(results, function(d) { return d.id; });
33808 var enter = items.enter()
33809 .insert('button', '.geocode-item')
33810 .attr('class', 'feature-list-item')
33811 .on('mouseover', mouseover)
33812 .on('mouseout', mouseout)
33813 .on('click', click);
33817 .attr('class', 'label');
33819 label.each(function(d) {
33821 .call(iD.svg.Icon('#icon-' + d.geometry, 'pre-text'));
33824 label.append('span')
33825 .attr('class', 'entity-type')
33826 .text(function(d) { return d.type; });
33828 label.append('span')
33829 .attr('class', 'entity-name')
33830 .text(function(d) { return d.name; });
33832 enter.style('opacity', 0)
33834 .style('opacity', 1);
33842 function mouseover(d) {
33843 if (d.id === -1) return;
33845 context.surface().selectAll(iD.util.entityOrMemberSelector([d.id], context.graph()))
33846 .classed('hover', true);
33849 function mouseout() {
33850 context.surface().selectAll('.hover')
33851 .classed('hover', false);
33854 function click(d) {
33855 d3.event.preventDefault();
33857 context.map().centerZoom([d.location[1], d.location[0]], 20);
33859 else if (d.entity) {
33860 if (d.entity.type === 'node') {
33861 context.map().center(d.entity.loc);
33862 } else if (d.entity.type === 'way') {
33863 var center = context.projection(context.map().center()),
33864 edge = iD.geo.chooseEdge(context.childNodes(d.entity), center, context.projection);
33865 context.map().center(edge.loc);
33867 context.enter(iD.modes.Select(context, [d.entity.id]).suppressMenu(true));
33869 context.zoomToEntity(d.id);
33873 function geocode() {
33874 var searchVal = encodeURIComponent(search.property('value'));
33875 d3.json('https://nominatim.openstreetmap.org/search/' + searchVal + '?limit=10&format=json', function(err, resp) {
33876 geocodeResults = resp || [];
33882 return featureList;
33884 iD.ui.flash = function(selection) {
33885 var modal = iD.ui.modal(selection);
33887 modal.select('.modal').classed('modal-flash', true);
33889 modal.select('.content')
33890 .classed('modal-section', true)
33892 .attr('class', 'description');
33894 modal.on('click.flash', function() { modal.remove(); });
33896 setTimeout(function() {
33903 iD.ui.FullScreen = function(context) {
33904 var element = context.container().node(),
33905 keybinding = d3.keybinding('full-screen');
33908 function getFullScreenFn() {
33909 if (element.requestFullscreen) {
33910 return element.requestFullscreen;
33911 } else if (element.msRequestFullscreen) {
33912 return element.msRequestFullscreen;
33913 } else if (element.mozRequestFullScreen) {
33914 return element.mozRequestFullScreen;
33915 } else if (element.webkitRequestFullscreen) {
33916 return element.webkitRequestFullscreen;
33920 function getExitFullScreenFn() {
33921 if (document.exitFullscreen) {
33922 return document.exitFullscreen;
33923 } else if (document.msExitFullscreen) {
33924 return document.msExitFullscreen;
33925 } else if (document.mozCancelFullScreen) {
33926 return document.mozCancelFullScreen;
33927 } else if (document.webkitExitFullscreen) {
33928 return document.webkitExitFullscreen;
33932 function isFullScreen() {
33933 return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement ||
33934 document.msFullscreenElement;
33937 function isSupported() {
33938 return !!getFullScreenFn();
33941 function fullScreen() {
33942 d3.event.preventDefault();
33943 if (!isFullScreen()) {
33944 // button.classed('active', true);
33945 getFullScreenFn().apply(element);
33947 // button.classed('active', false);
33948 getExitFullScreenFn().apply(document);
33952 return function() { // selection) {
33953 if (!isSupported())
33956 // var tooltip = bootstrap.tooltip()
33957 // .placement('left');
33959 // button = selection.append('button')
33960 // .attr('title', t('full_screen'))
33961 // .attr('tabindex', -1)
33962 // .on('click', fullScreen)
33965 // button.append('span')
33966 // .attr('class', 'icon full-screen');
33969 .on('f11', fullScreen)
33970 .on(iD.ui.cmd('⌘⇧F'), fullScreen);
33972 d3.select(document)
33976 iD.ui.Geolocate = function(context) {
33977 var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
33978 locating = iD.ui.Loading(context).message(t('geolocate.locating')).blocking(true),
33982 context.enter(iD.modes.Browse(context));
33983 context.container().call(locating);
33984 navigator.geolocation.getCurrentPosition(success, error, geoOptions);
33986 // This timeout ensures that we still call finish() even if
33987 // the user declines to share their location in Firefox
33988 timeoutId = setTimeout(finish, 10000 /* 10sec */ );
33991 function success(position) {
33992 var map = context.map(),
33993 extent = iD.geo.Extent([position.coords.longitude, position.coords.latitude])
33994 .padByMeters(position.coords.accuracy);
33996 map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
34004 function finish() {
34005 locating.close(); // unblock ui
34006 if (timeoutId) { clearTimeout(timeoutId); }
34007 timeoutId = undefined;
34010 return function(selection) {
34011 if (!navigator.geolocation) return;
34013 selection.append('button')
34014 .attr('tabindex', -1)
34015 .attr('title', t('geolocate.title'))
34016 .on('click', click)
34017 .call(iD.svg.Icon('#icon-geolocate', 'light'))
34018 .call(bootstrap.tooltip()
34019 .placement('left'));
34022 iD.ui.Help = function(context) {
34027 'help.editing_saving',
34036 var docs = docKeys.map(function(key) {
34039 title: text.split('\n')[0].replace('#', '').trim(),
34040 html: marked(text.split('\n').slice(1).join('\n'))
34044 function help(selection) {
34050 function toggle() {
34051 if (d3.event) d3.event.preventDefault();
34052 tooltip.hide(button);
34053 setVisible(!button.classed('active'));
34056 function setVisible(show) {
34057 if (show !== shown) {
34058 button.classed('active', show);
34062 selection.on('mousedown.help-inside', function() {
34063 return d3.event.stopPropagation();
34065 pane.style('display', 'block')
34066 .style('right', '-500px')
34069 .style('right', '0px');
34071 pane.style('right', '0px')
34074 .style('right', '-500px')
34075 .each('end', function() {
34076 d3.select(this).style('display', 'none');
34078 selection.on('mousedown.help-inside', null);
34083 function clickHelp(d, i) {
34084 pane.property('scrollTop', 0);
34085 doctitle.html(d.title);
34087 body.selectAll('a')
34088 .attr('target', '_blank');
34089 menuItems.classed('selected', function(m) {
34090 return m.title === d.title;
34096 var prevLink = nav.append('a')
34097 .attr('class', 'previous')
34098 .on('click', function() {
34099 clickHelp(docs[i - 1], i - 1);
34101 prevLink.append('span').html('◄ ' + docs[i - 1].title);
34103 if (i < docs.length - 1) {
34104 var nextLink = nav.append('a')
34105 .attr('class', 'next')
34106 .on('click', function() {
34107 clickHelp(docs[i + 1], i + 1);
34109 nextLink.append('span').html(docs[i + 1].title + ' ►');
34113 function clickWalkthrough() {
34114 d3.select(document.body).call(iD.ui.intro(context));
34119 var pane = selection.append('div')
34120 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
34121 tooltip = bootstrap.tooltip()
34124 .title(iD.ui.tooltipHtml(t('help.title'), key)),
34125 button = selection.append('button')
34126 .attr('tabindex', -1)
34127 .on('click', toggle)
34128 .call(iD.svg.Icon('#icon-help', 'light'))
34133 var toc = pane.append('ul')
34134 .attr('class', 'toc');
34136 var menuItems = toc.selectAll('li')
34141 .html(function(d) { return d.title; })
34142 .on('click', clickHelp);
34145 .attr('class','walkthrough')
34147 .text(t('splash.walkthrough'))
34148 .on('click', clickWalkthrough);
34150 var content = pane.append('div')
34151 .attr('class', 'left-content');
34153 var doctitle = content.append('h2')
34154 .text(t('help.title'));
34156 var body = content.append('div')
34157 .attr('class', 'body');
34159 var nav = content.append('div')
34160 .attr('class', 'nav');
34162 clickHelp(docs[0], 0);
34164 var keybinding = d3.keybinding('help')
34169 d3.select(document)
34172 context.surface().on('mousedown.help-outside', hide);
34173 context.container().on('mousedown.help-outside', hide);
34178 iD.ui.Info = function(context) {
34179 var key = iD.ui.cmd('⌘I'),
34180 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
34183 function info(selection) {
34184 function radiansToMeters(r) {
34185 // using WGS84 authalic radius (6371007.1809 m)
34186 return r * 6371007.1809;
34189 function steradiansToSqmeters(r) {
34190 // http://gis.stackexchange.com/a/124857/40446
34191 return r / 12.56637 * 510065621724000;
34194 function toLineString(feature) {
34195 if (feature.type === 'LineString') return feature;
34197 var result = { type: 'LineString', coordinates: [] };
34198 if (feature.type === 'Polygon') {
34199 result.coordinates = feature.coordinates[0];
34200 } else if (feature.type === 'MultiPolygon') {
34201 result.coordinates = feature.coordinates[0][0];
34207 function displayLength(m) {
34208 var d = m * (imperial ? 3.28084 : 1),
34227 // drop unnecessary precision
34228 p = d > 1000 ? 0 : d > 100 ? 1 : 2;
34230 return String(d.toFixed(p)) + ' ' + unit;
34233 function displayArea(m2) {
34234 var d = m2 * (imperial ? 10.7639111056 : 1),
34235 d1, d2, p1, p2, unit1, unit2;
34238 if (d >= 6969600) { // > 0.25mi² show mi²
34246 if (d > 4356 && d < 43560000) { // 0.1 - 1000 acres
34252 if (d >= 250000) { // > 0.25km² show km²
34260 if (d > 1000 && d < 10000000) { // 0.1 - 1000 hectares
34266 // drop unnecessary precision
34267 p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
34268 p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
34270 return String(d1.toFixed(p1)) + ' ' + unit1 +
34271 (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
34275 function redraw() {
34276 if (hidden) return;
34278 var resolver = context.graph(),
34279 selected = _.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
34280 singular = selected.length === 1 ? selected[0] : null,
34281 extent = iD.geo.Extent(),
34286 .attr('class', 'infobox-heading fillD')
34287 .text(singular || t('infobox.selected', { n: selected.length }));
34289 if (!selected.length) return;
34292 for (var i = 0; i < selected.length; i++) {
34293 entity = context.entity(selected[i]);
34294 extent._extend(entity.extent(resolver));
34296 center = extent.center();
34299 var list = wrap.append('ul');
34301 // multiple wrap, just display extent center..
34304 .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
34308 // single wrap, display details..
34309 if (!entity) return;
34310 var geometry = entity.geometry(resolver);
34312 if (geometry === 'line' || geometry === 'area') {
34313 var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
34314 feature = entity.asGeoJSON(resolver),
34315 length = radiansToMeters(d3.geo.length(toLineString(feature))),
34316 lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')),
34317 centroid = d3.geo.centroid(feature);
34320 .text(t('infobox.geometry') + ': ' +
34321 (closed ? t('infobox.closed') + ' ' : '') + t('geometry.' + geometry) );
34324 var area = steradiansToSqmeters(entity.area(resolver));
34326 .text(t('infobox.area') + ': ' + displayArea(area));
34330 .text(lengthLabel + ': ' + displayLength(length));
34333 .text(t('infobox.centroid') + ': ' + centroid[0].toFixed(5) + ', ' + centroid[1].toFixed(5));
34336 var toggle = imperial ? 'imperial' : 'metric';
34338 .text(t('infobox.' + toggle))
34340 .attr('class', 'button')
34341 .on('click', function() {
34342 d3.event.preventDefault();
34343 imperial = !imperial;
34348 var centerLabel = t('infobox.' + (entity.type === 'node' ? 'location' : 'center'));
34351 .text(t('infobox.geometry') + ': ' + t('geometry.' + geometry));
34354 .text(centerLabel + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
34359 function toggle() {
34360 if (d3.event) d3.event.preventDefault();
34366 .style('display', 'block')
34367 .style('opacity', 1)
34370 .style('opacity', 0)
34371 .each('end', function() {
34372 d3.select(this).style('display', 'none');
34376 .style('display', 'block')
34377 .style('opacity', 0)
34380 .style('opacity', 1);
34387 var wrap = selection.selectAll('.infobox')
34392 .attr('class', 'infobox fillD2')
34393 .style('display', (hidden ? 'none' : 'block'));
34396 .on('drawn.info', redraw);
34400 var keybinding = d3.keybinding('info')
34403 d3.select(document)
34409 iD.ui.Inspector = function(context) {
34410 var presetList = iD.ui.PresetList(context),
34411 entityEditor = iD.ui.EntityEditor(context),
34414 newFeature = false;
34416 function inspector(selection) {
34418 .entityID(entityID)
34419 .autofocus(newFeature)
34420 .on('choose', setPreset);
34424 .entityID(entityID)
34425 .on('choose', showList);
34427 var $wrap = selection.selectAll('.panewrap')
34430 var $enter = $wrap.enter().append('div')
34431 .attr('class', 'panewrap');
34433 $enter.append('div')
34434 .attr('class', 'preset-list-pane pane');
34436 $enter.append('div')
34437 .attr('class', 'entity-editor-pane pane');
34439 var $presetPane = $wrap.select('.preset-list-pane');
34440 var $editorPane = $wrap.select('.entity-editor-pane');
34442 var graph = context.graph(),
34443 entity = context.entity(entityID),
34444 showEditor = state === 'hover' ||
34445 entity.isUsed(graph) ||
34446 entity.isHighwayIntersection(graph);
34449 $wrap.style('right', '0%');
34450 $editorPane.call(entityEditor);
34452 $wrap.style('right', '-100%');
34453 $presetPane.call(presetList);
34456 var $footer = selection.selectAll('.footer')
34459 $footer.enter().append('div')
34460 .attr('class', 'footer');
34462 selection.select('.footer')
34463 .call(iD.ui.ViewOnOSM(context)
34464 .entityID(entityID));
34466 function showList(preset) {
34468 .styleTween('right', function() { return d3.interpolate('0%', '-100%'); });
34470 $presetPane.call(presetList
34475 function setPreset(preset) {
34477 .styleTween('right', function() { return d3.interpolate('-100%', '0%'); });
34479 $editorPane.call(entityEditor
34484 inspector.state = function(_) {
34485 if (!arguments.length) return state;
34487 entityEditor.state(state);
34491 inspector.entityID = function(_) {
34492 if (!arguments.length) return entityID;
34497 inspector.newFeature = function(_) {
34498 if (!arguments.length) return newFeature;
34505 iD.ui.intro = function(context) {
34508 function intro(selection) {
34510 function localizedName(id) {
34512 n2140018997: 'city_hall',
34513 n367813436: 'fire_department',
34514 w203988286: 'memory_isle_park',
34515 w203972937: 'riverwalk_trail',
34516 w203972938: 'riverwalk_trail',
34517 w203972940: 'riverwalk_trail',
34518 w41785752: 'w_michigan_ave',
34519 w134150789: 'w_michigan_ave',
34520 w134150795: 'w_michigan_ave',
34521 w134150800: 'w_michigan_ave',
34522 w134150811: 'w_michigan_ave',
34523 w134150802: 'e_michigan_ave',
34524 w134150836: 'e_michigan_ave',
34525 w41074896: 'e_michigan_ave',
34526 w17965834: 'spring_st',
34527 w203986457: 'scidmore_park',
34528 w203049587: 'petting_zoo',
34529 w17967397: 'n_andrews_st',
34530 w17967315: 's_andrews_st',
34531 w17967326: 'n_constantine_st',
34532 w17966400: 's_constantine_st',
34533 w170848823: 'rocky_river',
34534 w170848824: 'rocky_river',
34535 w170848331: 'rocky_river',
34536 w17967752: 'railroad_dr',
34537 w17965998: 'conrail_rr',
34538 w134150845: 'conrail_rr',
34539 w170989131: 'st_joseph_river',
34540 w143497377: 'n_main_st',
34541 w134150801: 's_main_st',
34542 w134150830: 's_main_st',
34543 w17966462: 's_main_st',
34544 w17967734: 'water_st',
34545 w17964996: 'foster_st',
34546 w170848330: 'portage_river',
34547 w17965351: 'flower_st',
34548 w17965502: 'elm_st',
34549 w17965402: 'walnut_st',
34550 w17964793: 'morris_ave',
34551 w17967444: 'east_st',
34552 w17966984: 'portage_ave'
34554 return features[id] && t('intro.graph.' + features[id]);
34557 context.enter(iD.modes.Browse(context));
34559 // Save current map state
34560 var history = context.history().toJSON(),
34561 hash = window.location.hash,
34562 center = context.map().center(),
34563 zoom = context.map().zoom(),
34564 background = context.background().baseLayerSource(),
34565 opacity = d3.selectAll('#map .layer-background').style('opacity'),
34566 loadedTiles = context.connection().loadedTiles(),
34567 baseEntities = context.history().graph().base().entities,
34571 context.inIntro(true);
34573 // Load semi-real data used in intro
34574 context.connection().toggle(false).flush();
34575 context.history().reset();
34577 introGraph = JSON.parse(iD.introGraph);
34578 for (var key in introGraph) {
34579 introGraph[key] = iD.Entity(introGraph[key]);
34580 name = localizedName(key);
34582 introGraph[key].tags.name = name;
34585 context.history().merge(d3.values(iD.Graph().load(introGraph).entities));
34586 context.background().bing();
34588 d3.selectAll('#map .layer-background').style('opacity', 1);
34590 var curtain = d3.curtain();
34591 selection.call(curtain);
34593 function reveal(box, text, options) {
34594 options = options || {};
34595 if (text) curtain.reveal(box, text, options.tooltipClass, options.duration);
34596 else curtain.reveal(box, '', '', options.duration);
34599 var steps = ['navigation', 'point', 'area', 'line', 'startEditing'].map(function(step, i) {
34600 var s = iD.ui.intro[step](context, reveal)
34601 .on('done', function() {
34602 entered.filter(function(d) {
34603 return d.title === s.title;
34604 }).classed('finished', true);
34605 enter(steps[i + 1]);
34610 steps[steps.length - 1].on('startEditing', function() {
34613 d3.selectAll('#map .layer-background').style('opacity', opacity);
34614 context.connection().toggle(true).flush().loadedTiles(loadedTiles);
34615 context.history().reset().merge(d3.values(baseEntities));
34616 context.background().baseLayerSource(background);
34617 if (history) context.history().fromJSON(history, false);
34618 context.map().centerZoom(center, zoom);
34619 window.location.replace(hash);
34620 context.inIntro(false);
34623 var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
34625 var buttonwrap = navwrap.append('div')
34626 .attr('class', 'joined')
34627 .selectAll('button.step');
34629 var entered = buttonwrap
34633 .attr('class', 'step')
34634 .on('click', enter);
34637 .call(iD.svg.Icon('#icon-apply', 'pre-text'));
34641 .text(function(d) { return t(d.title); });
34645 function enter (newStep) {
34646 if (step) { step.exit(); }
34648 context.enter(iD.modes.Browse(context));
34653 entered.classed('active', function(d) {
34654 return d.title === step.title;
34662 iD.ui.intro.pointBox = function(point, context) {
34663 var rect = context.surfaceRect();
34664 point = context.projection(point);
34666 left: point[0] + rect.left - 30,
34667 top: point[1] + rect.top - 50,
34673 iD.ui.intro.pad = function(box, padding, context) {
34674 if (box instanceof Array) {
34675 var rect = context.surfaceRect();
34676 box = context.projection(box);
34678 left: box[0] + rect.left,
34679 top: box[1] + rect.top
34683 left: box.left - padding,
34684 top: box.top - padding,
34685 width: (box.width || 0) + 2 * padding,
34686 height: (box.width || 0) + 2 * padding
34690 iD.ui.intro.icon = function(name, svgklass) {
34691 return '<svg class="icon ' + (svgklass || '') + '">' +
34692 '<use xlink:href="' + name + '"></use></svg>';
34694 iD.ui.Lasso = function(context) {
34695 var group, polygon;
34697 lasso.coordinates = [];
34699 function lasso(selection) {
34701 context.container().classed('lasso', true);
34703 group = selection.append('g')
34704 .attr('class', 'lasso hide');
34706 polygon = group.append('path')
34707 .attr('class', 'lasso-path');
34709 group.call(iD.ui.Toggle(true));
34715 polygon.data([lasso.coordinates])
34716 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
34720 lasso.extent = function () {
34721 return lasso.coordinates.reduce(function(extent, point) {
34722 return extent.extend(iD.geo.Extent(point));
34723 }, iD.geo.Extent());
34726 lasso.p = function(_) {
34727 if (!arguments.length) return lasso;
34728 lasso.coordinates.push(_);
34733 lasso.close = function() {
34735 group.call(iD.ui.Toggle(false, function() {
34736 d3.select(this).remove();
34739 context.container().classed('lasso', false);
34744 iD.ui.Loading = function(context) {
34749 var loading = function(selection) {
34750 modal = iD.ui.modal(selection, blocking);
34752 var loadertext = modal.select('.content')
34753 .classed('loading-modal', true)
34755 .attr('class', 'modal-section fillL');
34757 loadertext.append('img')
34758 .attr('class', 'loader')
34759 .attr('src', context.imagePath('loader-white.gif'));
34761 loadertext.append('h3')
34764 modal.select('button.close')
34765 .attr('class', 'hide');
34770 loading.message = function(_) {
34771 if (!arguments.length) return message;
34776 loading.blocking = function(_) {
34777 if (!arguments.length) return blocking;
34782 loading.close = function() {
34788 iD.ui.MapData = function(context) {
34790 features = context.features().keys(),
34791 layers = context.layers(),
34792 fills = ['wireframe', 'partial', 'full'],
34793 fillDefault = context.storage('area-fill') || 'partial',
34794 fillSelected = fillDefault;
34797 function map_data(selection) {
34799 function showsFeature(d) {
34800 return context.features().enabled(d);
34803 function autoHiddenFeature(d) {
34804 return context.features().autoHidden(d);
34807 function clickFeature(d) {
34808 context.features().toggle(d);
34812 function showsFill(d) {
34813 return fillSelected === d;
34816 function setFill(d) {
34817 _.each(fills, function(opt) {
34818 context.surface().classed('fill-' + opt, Boolean(opt === d));
34822 if (d !== 'wireframe') {
34824 context.storage('area-fill', d);
34829 function toggleLayer(which) {
34830 var layer = layers.layer(which);
34832 layer.enabled(!layer.enabled());
34837 function clickGpx() {
34838 toggleLayer('gpx');
34841 function clickMapillaryImages() {
34842 toggleLayer('mapillary-images');
34845 function clickMapillarySigns() {
34846 toggleLayer('mapillary-signs');
34850 function drawMapillaryItems(selection) {
34851 var mapillaryImages = layers.layer('mapillary-images'),
34852 mapillarySigns = layers.layer('mapillary-signs'),
34853 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
34854 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
34855 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
34856 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
34858 var mapillaryList = selection
34859 .selectAll('.layer-list-mapillary')
34866 .attr('class', 'layer-list layer-list-mapillary');
34868 var mapillaryImageLayerItem = mapillaryList
34869 .selectAll('.list-item-mapillary-images')
34870 .data(supportsMapillaryImages ? [0] : []);
34872 var enterImages = mapillaryImageLayerItem.enter()
34874 .attr('class', 'list-item-mapillary-images');
34876 var labelImages = enterImages.append('label')
34877 .call(bootstrap.tooltip()
34878 .title(t('mapillary_images.tooltip'))
34879 .placement('top'));
34881 labelImages.append('input')
34882 .attr('type', 'checkbox')
34883 .on('change', clickMapillaryImages);
34885 labelImages.append('span')
34886 .text(t('mapillary_images.title'));
34889 var mapillarySignLayerItem = mapillaryList
34890 .selectAll('.list-item-mapillary-signs')
34891 .data(supportsMapillarySigns ? [0] : []);
34893 var enterSigns = mapillarySignLayerItem.enter()
34895 .attr('class', 'list-item-mapillary-signs');
34897 var labelSigns = enterSigns.append('label')
34898 .call(bootstrap.tooltip()
34899 .title(t('mapillary_signs.tooltip'))
34900 .placement('top'));
34902 labelSigns.append('input')
34903 .attr('type', 'checkbox')
34904 .on('change', clickMapillarySigns);
34906 labelSigns.append('span')
34907 .text(t('mapillary_signs.title'));
34910 mapillaryImageLayerItem
34911 .classed('active', showsMapillaryImages)
34912 .selectAll('input')
34913 .property('checked', showsMapillaryImages);
34915 mapillarySignLayerItem
34916 .classed('active', showsMapillarySigns)
34917 .selectAll('input')
34918 .property('checked', showsMapillarySigns);
34921 mapillaryImageLayerItem.exit()
34923 mapillarySignLayerItem.exit()
34928 function drawGpxItem(selection) {
34929 var gpx = layers.layer('gpx'),
34930 hasGpx = gpx && gpx.hasGpx(),
34931 showsGpx = hasGpx && gpx.enabled();
34933 var gpxLayerItem = selection
34934 .selectAll('.layer-list-gpx')
34935 .data(gpx ? [0] : []);
34938 var enter = gpxLayerItem.enter()
34940 .attr('class', 'layer-list layer-list-gpx')
34942 .classed('list-item-gpx', true);
34944 enter.append('button')
34945 .attr('class', 'list-item-gpx-extent')
34946 .call(bootstrap.tooltip()
34947 .title(t('gpx.zoom'))
34948 .placement('left'))
34949 .on('click', function() {
34950 d3.event.preventDefault();
34951 d3.event.stopPropagation();
34954 .call(iD.svg.Icon('#icon-search'));
34956 enter.append('button')
34957 .attr('class', 'list-item-gpx-browse')
34958 .call(bootstrap.tooltip()
34959 .title(t('gpx.browse'))
34960 .placement('left'))
34961 .on('click', function() {
34962 d3.select(document.createElement('input'))
34963 .attr('type', 'file')
34964 .on('change', function() {
34965 gpx.files(d3.event.target.files);
34969 .call(iD.svg.Icon('#icon-geolocate'));
34971 var labelGpx = enter.append('label')
34972 .call(bootstrap.tooltip()
34973 .title(t('gpx.drag_drop'))
34974 .placement('top'));
34976 labelGpx.append('input')
34977 .attr('type', 'checkbox')
34978 .on('change', clickGpx);
34980 labelGpx.append('span')
34981 .text(t('gpx.local_layer'));
34985 .classed('active', showsGpx)
34986 .selectAll('input')
34987 .property('disabled', !hasGpx)
34988 .property('checked', showsGpx);
34991 gpxLayerItem.exit()
34996 function drawList(selection, data, type, name, change, active) {
34997 var items = selection.selectAll('li')
35001 var enter = items.enter()
35003 .attr('class', 'layer')
35004 .call(bootstrap.tooltip()
35006 .title(function(d) {
35007 var tip = t(name + '.' + d + '.tooltip'),
35008 key = (d === 'wireframe' ? 'W' : null);
35010 if (name === 'feature' && autoHiddenFeature(d)) {
35011 tip += '<div>' + t('map_data.autohidden') + '</div>';
35013 return iD.ui.tooltipHtml(tip, key);
35018 var label = enter.append('label');
35020 label.append('input')
35021 .attr('type', type)
35022 .attr('name', name)
35023 .on('change', change);
35025 label.append('span')
35026 .text(function(d) { return t(name + '.' + d + '.description'); });
35030 .classed('active', active)
35031 .selectAll('input')
35032 .property('checked', active)
35033 .property('indeterminate', function(d) {
35034 return (name === 'feature' && autoHiddenFeature(d));
35043 function update() {
35044 dataLayerContainer.call(drawMapillaryItems);
35045 dataLayerContainer.call(drawGpxItem);
35047 fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
35049 featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
35052 function hidePanel() {
35056 function togglePanel() {
35057 if (d3.event) d3.event.preventDefault();
35058 tooltip.hide(button);
35059 setVisible(!button.classed('active'));
35062 function toggleWireframe() {
35064 d3.event.preventDefault();
35065 d3.event.stopPropagation();
35067 setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
35068 context.map().pan([0,0]); // trigger a redraw
35071 function setVisible(show) {
35072 if (show !== shown) {
35073 button.classed('active', show);
35078 selection.on('mousedown.map_data-inside', function() {
35079 return d3.event.stopPropagation();
35081 content.style('display', 'block')
35082 .style('right', '-300px')
35085 .style('right', '0px');
35087 content.style('display', 'block')
35088 .style('right', '0px')
35091 .style('right', '-300px')
35092 .each('end', function() {
35093 d3.select(this).style('display', 'none');
35095 selection.on('mousedown.map_data-inside', null);
35101 var content = selection.append('div')
35102 .attr('class', 'fillL map-overlay col3 content hide'),
35103 tooltip = bootstrap.tooltip()
35106 .title(iD.ui.tooltipHtml(t('map_data.description'), key)),
35107 button = selection.append('button')
35108 .attr('tabindex', -1)
35109 .on('click', togglePanel)
35110 .call(iD.svg.Icon('#icon-data', 'light'))
35114 content.append('h4')
35115 .text(t('map_data.title'));
35119 content.append('a')
35120 .text(t('map_data.data_layers'))
35122 .classed('hide-toggle', true)
35123 .classed('expanded', true)
35124 .on('click', function() {
35125 var exp = d3.select(this).classed('expanded');
35126 dataLayerContainer.style('display', exp ? 'none' : 'block');
35127 d3.select(this).classed('expanded', !exp);
35128 d3.event.preventDefault();
35131 var dataLayerContainer = content.append('div')
35132 .attr('class', 'data-data-layers')
35133 .style('display', 'block');
35137 content.append('a')
35138 .text(t('map_data.fill_area'))
35140 .classed('hide-toggle', true)
35141 .classed('expanded', false)
35142 .on('click', function() {
35143 var exp = d3.select(this).classed('expanded');
35144 fillContainer.style('display', exp ? 'none' : 'block');
35145 d3.select(this).classed('expanded', !exp);
35146 d3.event.preventDefault();
35149 var fillContainer = content.append('div')
35150 .attr('class', 'data-area-fills')
35151 .style('display', 'none');
35153 var fillList = fillContainer.append('ul')
35154 .attr('class', 'layer-list layer-fill-list');
35158 content.append('a')
35159 .text(t('map_data.map_features'))
35161 .classed('hide-toggle', true)
35162 .classed('expanded', false)
35163 .on('click', function() {
35164 var exp = d3.select(this).classed('expanded');
35165 featureContainer.style('display', exp ? 'none' : 'block');
35166 d3.select(this).classed('expanded', !exp);
35167 d3.event.preventDefault();
35170 var featureContainer = content.append('div')
35171 .attr('class', 'data-feature-filters')
35172 .style('display', 'none');
35174 var featureList = featureContainer.append('ul')
35175 .attr('class', 'layer-list layer-feature-list');
35179 .on('change.map_data-update', update);
35181 setFill(fillDefault);
35183 var keybinding = d3.keybinding('features')
35184 .on(key, togglePanel)
35185 .on('W', toggleWireframe)
35186 .on('B', hidePanel)
35187 .on('H', hidePanel);
35189 d3.select(document)
35192 context.surface().on('mousedown.map_data-outside', hidePanel);
35193 context.container().on('mousedown.map_data-outside', hidePanel);
35198 iD.ui.MapInMap = function(context) {
35201 function map_in_map(selection) {
35202 var backgroundLayer = iD.TileLayer(),
35203 overlayLayers = {},
35204 projection = iD.geo.RawMercator(),
35205 gpxLayer = iD.svg.Gpx(projection, context).showLabels(false),
35206 zoom = d3.behavior.zoom()
35207 .scaleExtent([ztok(0.5), ztok(24)])
35208 .on('zoom', zoomPan),
35209 transformed = false,
35212 zDiff = 6, // by default, minimap renders at (main zoom - 6)
35213 tStart, tLast, tCurr, kLast, kCurr, tiles, svg, timeoutId;
35215 function ztok(z) { return 256 * Math.pow(2, z); }
35216 function ktoz(k) { return Math.log(k) / Math.LN2 - 8; }
35219 function startMouse() {
35220 context.surface().on('mouseup.map-in-map-outside', endMouse);
35221 context.container().on('mouseup.map-in-map-outside', endMouse);
35223 tStart = tLast = tCurr = projection.translate();
35228 function zoomPan() {
35229 var e = d3.event.sourceEvent,
35230 t = d3.event.translate,
35231 k = d3.event.scale,
35232 zMain = ktoz(context.projection.scale() * 2 * Math.PI),
35235 // restrict minimap zoom to < (main zoom - 3)
35236 if (zMini > zMain - 3) {
35238 zoom.scale(kCurr).translate(tCurr); // restore last good values
35244 zDiff = zMain - zMini;
35246 var scale = kCurr / kLast,
35247 tX = (tCurr[0] / scale - tLast[0]) * scale,
35248 tY = (tCurr[1] / scale - tLast[1]) * scale;
35250 iD.util.setTransform(tiles, tX, tY, scale);
35251 iD.util.setTransform(svg, 0, 0, scale);
35252 transformed = true;
35256 e.preventDefault();
35257 e.stopPropagation();
35261 function endMouse() {
35262 context.surface().on('mouseup.map-in-map-outside', null);
35263 context.container().on('mouseup.map-in-map-outside', null);
35265 updateProjection();
35268 if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) {
35269 var dMini = wrap.dimensions(),
35270 cMini = [ dMini[0] / 2, dMini[1] / 2 ];
35272 context.map().center(projection.invert(cMini));
35277 function updateProjection() {
35278 var loc = context.map().center(),
35279 dMini = wrap.dimensions(),
35280 cMini = [ dMini[0] / 2, dMini[1] / 2 ],
35281 tMain = context.projection.translate(),
35282 kMain = context.projection.scale(),
35283 zMain = ktoz(kMain * 2 * Math.PI),
35284 zMini = Math.max(zMain - zDiff, 0.5),
35285 kMini = ztok(zMini);
35289 .scale(kMini / (2 * Math.PI));
35291 var s = projection(loc),
35292 mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0],
35294 cMini[0] - s[0] + tMain[0] + mouse[0],
35295 cMini[1] - s[1] + tMain[1] + mouse[1]
35300 .clipExtent([[0, 0], dMini]);
35307 tLast = tCurr = tMini;
35308 kLast = kCurr = kMini;
35311 iD.util.setTransform(tiles, 0, 0);
35312 iD.util.setTransform(svg, 0, 0);
35313 transformed = false;
35318 function redraw() {
35319 if (hidden) return;
35321 updateProjection();
35323 var dMini = wrap.dimensions(),
35324 zMini = ktoz(projection.scale() * 2 * Math.PI);
35326 // setup tile container
35328 .selectAll('.map-in-map-tiles')
35334 .attr('class', 'map-in-map-tiles');
35336 // redraw background
35338 .source(context.background().baseLayerSource())
35339 .projection(projection)
35340 .dimensions(dMini);
35342 var background = tiles
35343 .selectAll('.map-in-map-background')
35348 .attr('class', 'map-in-map-background');
35351 .call(backgroundLayer);
35355 var overlaySources = context.background().overlayLayerSources();
35356 var activeOverlayLayers = [];
35357 for (var i = 0; i < overlaySources.length; i++) {
35358 if (overlaySources[i].validZoom(zMini)) {
35359 if (!overlayLayers[i]) overlayLayers[i] = iD.TileLayer();
35360 activeOverlayLayers.push(overlayLayers[i]
35361 .source(overlaySources[i])
35362 .projection(projection)
35363 .dimensions(dMini));
35367 var overlay = tiles
35368 .selectAll('.map-in-map-overlay')
35373 .attr('class', 'map-in-map-overlay');
35375 var overlays = overlay
35377 .data(activeOverlayLayers, function(d) { return d.source().name(); });
35379 overlays.enter().append('div');
35380 overlays.each(function(layer) {
35381 d3.select(this).call(layer);
35389 .selectAll('.map-in-map-gpx')
35390 .data(gpxLayer.enabled() ? [0] : []);
35394 .attr('class', 'map-in-map-gpx');
35399 gpx.call(gpxLayer);
35402 // redraw bounding box
35404 var getPath = d3.geo.path().projection(projection),
35405 bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
35407 svg = wrap.selectAll('.map-in-map-svg')
35412 .attr('class', 'map-in-map-svg');
35414 var path = svg.selectAll('.map-in-map-bbox')
35419 .attr('class', 'map-in-map-bbox');
35422 .attr('d', getPath)
35423 .classed('thick', function(d) { return getPath.area(d) < 30; });
35428 function queueRedraw() {
35429 clearTimeout(timeoutId);
35430 timeoutId = setTimeout(function() { redraw(); }, 300);
35434 function toggle() {
35435 if (d3.event) d3.event.preventDefault();
35439 var label = d3.select('.minimap-toggle');
35440 label.classed('active', !hidden)
35441 .select('input').property('checked', !hidden);
35445 .style('display', 'block')
35446 .style('opacity', 1)
35449 .style('opacity', 0)
35450 .each('end', function() {
35451 d3.select(this).style('display', 'none');
35455 .style('display', 'block')
35456 .style('opacity', 0)
35459 .style('opacity', 1);
35465 iD.ui.MapInMap.toggle = toggle;
35467 var wrap = selection.selectAll('.map-in-map')
35472 .attr('class', 'map-in-map')
35473 .style('display', (hidden ? 'none' : 'block'))
35474 .on('mousedown.map-in-map', startMouse)
35475 .on('mouseup.map-in-map', endMouse)
35477 .on('dblclick.zoom', null);
35480 .on('drawn.map-in-map', function(drawn) {
35481 if (drawn.full === true) redraw();
35486 var keybinding = d3.keybinding('map-in-map')
35489 d3.select(document)
35495 iD.ui.modal = function(selection, blocking) {
35497 var previous = selection.select('div.modal');
35498 var animate = previous.empty();
35500 previous.transition()
35502 .style('opacity', 0)
35505 var shaded = selection
35507 .attr('class', 'shaded')
35508 .style('opacity', 0);
35510 shaded.close = function() {
35514 .style('opacity',0)
35519 .style('top','0px');
35523 var keybinding = d3.keybinding('modal')
35524 .on('⌫', shaded.close)
35525 .on('⎋', shaded.close);
35527 d3.select(document).call(keybinding);
35529 var modal = shaded.append('div')
35530 .attr('class', 'modal fillL col6');
35532 shaded.on('click.remove-modal', function() {
35533 if (d3.event.target === this && !blocking) shaded.close();
35536 modal.append('button')
35537 .attr('class', 'close')
35538 .on('click', function() {
35539 if (!blocking) shaded.close();
35542 .attr('class','icon close');
35544 modal.append('div')
35545 .attr('class', 'content');
35548 shaded.transition().style('opacity', 1);
35550 shaded.style('opacity', 1);
35555 iD.ui.Modes = function(context) {
35557 iD.modes.AddPoint(context),
35558 iD.modes.AddLine(context),
35559 iD.modes.AddArea(context)];
35561 function editable() {
35562 return context.editable() && context.mode().id !== 'save';
35565 return function(selection) {
35566 var buttons = selection.selectAll('button.add-button')
35569 buttons.enter().append('button')
35570 .attr('tabindex', -1)
35571 .attr('class', function(mode) { return mode.id + ' add-button col4'; })
35572 .on('click.mode-buttons', function(mode) {
35573 if (mode.id === context.mode().id) {
35574 context.enter(iD.modes.Browse(context));
35576 context.enter(mode);
35579 .call(bootstrap.tooltip()
35580 .placement('bottom')
35582 .title(function(mode) {
35583 return iD.ui.tooltipHtml(mode.description, mode.key);
35587 .on('move.modes', _.debounce(update, 500));
35590 .on('enter.modes', update);
35592 buttons.each(function(d) {
35594 .call(iD.svg.Icon('#icon-' + d.button, 'pre-text'));
35597 buttons.append('span')
35598 .attr('class', 'label')
35599 .text(function(mode) { return mode.title; });
35601 context.on('enter.editor', function(entered) {
35602 buttons.classed('active', function(mode) { return entered.button === mode.button; });
35603 context.container()
35604 .classed('mode-' + entered.id, true);
35607 context.on('exit.editor', function(exited) {
35608 context.container()
35609 .classed('mode-' + exited.id, false);
35612 var keybinding = d3.keybinding('mode-buttons');
35614 modes.forEach(function(m) {
35615 keybinding.on(m.key, function() { if (editable()) context.enter(m); });
35618 d3.select(document)
35621 function update() {
35622 buttons.property('disabled', !editable());
35626 iD.ui.Notice = function(context) {
35627 return function(selection) {
35628 var div = selection.append('div')
35629 .attr('class', 'notice');
35631 var button = div.append('button')
35632 .attr('class', 'zoom-to notice')
35633 .on('click', function() { context.map().zoom(context.minEditableZoom()); });
35636 .call(iD.svg.Icon('#icon-plus', 'pre-text'))
35638 .attr('class', 'label')
35639 .text(t('zoom_in_edit'));
35641 function disableTooHigh() {
35642 div.style('display', context.editable() ? 'none' : 'block');
35646 .on('move.notice', _.debounce(disableTooHigh, 500));
35651 iD.ui.PresetIcon = function() {
35652 var preset, geometry;
35654 function presetIcon(selection) {
35655 selection.each(render);
35658 function render() {
35659 var selection = d3.select(this),
35660 p = preset.apply(this, arguments),
35661 geom = geometry.apply(this, arguments),
35662 icon = p.icon || (geom === 'line' ? 'other-line' : 'marker-stroked'),
35663 maki = iD.data.featureIcons.hasOwnProperty(icon + '-24');
35665 if (icon === 'dentist') maki = true; // workaround for dentist icon missing in `maki-sprite.json`
35667 function tag_classes(p) {
35669 for (var i in p.tags) {
35671 if (p.tags[i] !== '*') {
35672 s += ' tag-' + i + '-' + p.tags[i];
35678 var $fill = selection.selectAll('.preset-icon-fill')
35681 $fill.enter().append('div');
35683 $fill.attr('class', function() {
35684 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
35687 var $frame = selection.selectAll('.preset-icon-frame')
35692 .call(iD.svg.Icon('#preset-icon-frame'));
35694 $frame.attr('class', function() {
35695 return 'preset-icon-frame ' + (geom === 'area' ? '' : 'hide');
35699 var $icon = selection.selectAll('.preset-icon')
35704 .attr('class', 'preset-icon')
35705 .call(iD.svg.Icon(''));
35708 .attr('class', 'preset-icon preset-icon-' + (maki ? '32' : (geom === 'area' ? '44' : '60')));
35710 $icon.selectAll('svg')
35711 .attr('class', function() {
35712 return 'icon ' + icon + tag_classes(p);
35715 $icon.selectAll('use') // workaround: maki parking-24 broken?
35716 .attr('href', '#' + icon + (maki ? ( icon === 'parking' ? '-18' : '-24') : ''));
35719 presetIcon.preset = function(_) {
35720 if (!arguments.length) return preset;
35721 preset = d3.functor(_);
35725 presetIcon.geometry = function(_) {
35726 if (!arguments.length) return geometry;
35727 geometry = d3.functor(_);
35733 iD.ui.preset = function(context) {
35734 var event = d3.dispatch('change'),
35741 function UIField(field, entity, show) {
35742 field = _.clone(field);
35744 field.input = iD.ui.preset[field.type](field, context)
35745 .on('change', event.change);
35747 if (field.input.entity) field.input.entity(entity);
35749 field.keys = field.keys || [field.key];
35753 field.shown = function() {
35754 return field.id === 'name' || field.show || _.any(field.keys, function(key) { return !!tags[key]; });
35757 field.modified = function() {
35758 var original = context.graph().base().entities[entity.id];
35759 return _.any(field.keys, function(key) {
35760 return original ? tags[key] !== original.tags[key] : tags[key];
35764 field.revert = function() {
35765 var original = context.graph().base().entities[entity.id],
35767 field.keys.forEach(function(key) {
35768 t[key] = original ? original.tags[key] : undefined;
35773 field.present = function() {
35774 return _.any(field.keys, function(key) {
35779 field.remove = function() {
35781 field.keys.forEach(function(key) {
35782 t[key] = undefined;
35790 function fieldKey(field) {
35794 function presets(selection) {
35795 selection.call(iD.ui.Disclosure()
35796 .title(t('inspector.all_fields'))
35797 .expanded(context.storage('preset_fields.expanded') !== 'false')
35798 .on('toggled', toggled)
35799 .content(content));
35801 function toggled(expanded) {
35802 context.storage('preset_fields.expanded', expanded);
35806 function content(selection) {
35808 var entity = context.entity(id),
35809 geometry = context.geometry(id);
35811 fields = [UIField(context.presets().field('name'), entity)];
35813 preset.fields.forEach(function(field) {
35814 if (field.matchGeometry(geometry)) {
35815 fields.push(UIField(field, entity, true));
35819 if (entity.isHighwayIntersection(context.graph())) {
35820 fields.push(UIField(context.presets().field('restrictions'), entity, true));
35823 context.presets().universal().forEach(function(field) {
35824 if (preset.fields.indexOf(field) < 0) {
35825 fields.push(UIField(field, entity));
35830 var shown = fields.filter(function(field) { return field.shown(); }),
35831 notShown = fields.filter(function(field) { return !field.shown(); });
35833 var $form = selection.selectAll('.preset-form')
35836 $form.enter().append('div')
35837 .attr('class', 'preset-form inspector-inner fillL3');
35839 var $fields = $form.selectAll('.form-field')
35840 .data(shown, fieldKey);
35844 var $enter = $fields.enter()
35846 .attr('class', function(field) {
35847 return 'form-field form-field-' + field.id;
35850 var $label = $enter.append('label')
35851 .attr('class', 'form-label')
35852 .attr('for', function(field) { return 'preset-input-' + field.id; })
35853 .text(function(field) { return field.label(); });
35855 var wrap = $label.append('div')
35856 .attr('class', 'form-label-button-wrap');
35858 wrap.append('button')
35859 .attr('class', 'remove-icon')
35860 .call(iD.svg.Icon('#operation-delete'));
35862 wrap.append('button')
35863 .attr('class', 'modified-icon')
35864 .attr('tabindex', -1)
35865 .call(iD.svg.Icon('#icon-undo'));
35869 $fields.select('.form-label-button-wrap .remove-icon')
35870 .on('click', remove);
35872 $fields.select('.modified-icon')
35873 .on('click', revert);
35877 .classed('modified', function(field) {
35878 return field.modified();
35880 .classed('present', function(field) {
35881 return field.present();
35883 .each(function(field) {
35884 var reference = iD.ui.TagReference(field.reference || {key: field.key}, context);
35886 if (state === 'hover') {
35887 reference.showing(false);
35892 .selectAll('input')
35893 .on('keydown', function() {
35894 if (d3.event.keyCode === 13) { // enter
35895 context.enter(iD.modes.Browse(context));
35898 .call(reference.body)
35899 .select('.form-label-button-wrap')
35900 .call(reference.button);
35902 field.input.tags(tags);
35908 notShown = notShown.map(function(field) {
35910 title: field.label(),
35911 value: field.label(),
35916 var $more = selection.selectAll('.more-fields')
35917 .data((notShown.length > 0) ? [0] : []);
35919 $more.enter().append('div')
35920 .attr('class', 'more-fields')
35922 .text(t('inspector.add_fields'));
35924 var $input = $more.selectAll('.value')
35927 $input.enter().append('input')
35928 .attr('class', 'value')
35929 .attr('type', 'text');
35932 .attr('placeholder', function() {
35933 var placeholder = [];
35934 for (var field in notShown) {
35935 placeholder.push(notShown[field].title);
35937 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
35939 .call(d3.combobox().data(notShown)
35941 .on('accept', show));
35949 function show(field) {
35950 field = field.field;
35952 content(selection);
35953 field.input.focus();
35956 function revert(field) {
35957 d3.event.stopPropagation();
35958 d3.event.preventDefault();
35959 event.change(field.revert());
35962 function remove(field) {
35963 d3.event.stopPropagation();
35964 d3.event.preventDefault();
35965 event.change(field.remove());
35969 presets.preset = function(_) {
35970 if (!arguments.length) return preset;
35971 if (preset && preset.id === _.id) return presets;
35977 presets.state = function(_) {
35978 if (!arguments.length) return state;
35983 presets.tags = function(_) {
35984 if (!arguments.length) return tags;
35986 // Don't reset fields here.
35990 presets.entityID = function(_) {
35991 if (!arguments.length) return id;
35992 if (id === _) return presets;
35998 return d3.rebind(presets, event, 'on');
36000 iD.ui.PresetList = function(context) {
36001 var event = d3.dispatch('choose'),
36006 function presetList(selection) {
36007 var geometry = context.geometry(id),
36008 presets = context.presets().matchGeometry(geometry);
36010 selection.html('');
36012 var messagewrap = selection.append('div')
36013 .attr('class', 'header fillL cf');
36015 var message = messagewrap.append('h3')
36016 .text(t('inspector.choose'));
36018 if (context.entity(id).isUsed(context.graph())) {
36019 messagewrap.append('button')
36020 .attr('class', 'preset-choose')
36021 .on('click', function() { event.choose(currentPreset); })
36025 messagewrap.append('button')
36026 .attr('class', 'close')
36027 .on('click', function() {
36028 context.enter(iD.modes.Browse(context));
36030 .call(iD.svg.Icon('#icon-close'));
36033 function keydown() {
36034 // hack to let delete shortcut work when search is autofocused
36035 if (search.property('value').length === 0 &&
36036 (d3.event.keyCode === d3.keybinding.keyCodes['⌫'] ||
36037 d3.event.keyCode === d3.keybinding.keyCodes['⌦'])) {
36038 d3.event.preventDefault();
36039 d3.event.stopPropagation();
36040 iD.operations.Delete([id], context)();
36041 } else if (search.property('value').length === 0 &&
36042 (d3.event.ctrlKey || d3.event.metaKey) &&
36043 d3.event.keyCode === d3.keybinding.keyCodes.z) {
36044 d3.event.preventDefault();
36045 d3.event.stopPropagation();
36047 } else if (!d3.event.ctrlKey && !d3.event.metaKey) {
36048 d3.select(this).on('keydown', null);
36052 function keypress() {
36054 var value = search.property('value');
36055 if (d3.event.keyCode === 13 && value.length) {
36056 list.selectAll('.preset-list-item:first-child').datum().choose();
36060 function inputevent() {
36061 var value = search.property('value');
36062 list.classed('filtered', value.length);
36063 if (value.length) {
36064 var results = presets.search(value, geometry);
36065 message.text(t('inspector.results', {
36066 n: results.collection.length,
36069 list.call(drawList, results);
36071 list.call(drawList, context.presets().defaults(geometry, 36));
36072 message.text(t('inspector.choose'));
36076 var searchWrap = selection.append('div')
36077 .attr('class', 'search-header');
36079 var search = searchWrap.append('input')
36080 .attr('class', 'preset-search-input')
36081 .attr('placeholder', t('inspector.search'))
36082 .attr('type', 'search')
36083 .on('keydown', keydown)
36084 .on('keypress', keypress)
36085 .on('input', inputevent);
36088 .call(iD.svg.Icon('#icon-search', 'pre-text'));
36091 search.node().focus();
36094 var listWrap = selection.append('div')
36095 .attr('class', 'inspector-body');
36097 var list = listWrap.append('div')
36098 .attr('class', 'preset-list fillL cf')
36099 .call(drawList, context.presets().defaults(geometry, 36));
36102 function drawList(list, presets) {
36103 var collection = presets.collection.map(function(preset) {
36104 return preset.members ? CategoryItem(preset) : PresetItem(preset);
36107 var items = list.selectAll('.preset-list-item')
36108 .data(collection, function(d) { return d.preset.id; });
36110 items.enter().append('div')
36111 .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
36112 .classed('current', function(item) { return item.preset === currentPreset; })
36113 .each(function(item) {
36114 d3.select(this).call(item);
36116 .style('opacity', 0)
36118 .style('opacity', 1);
36126 function CategoryItem(preset) {
36127 var box, sublist, shown = false;
36129 function item(selection) {
36130 var wrap = selection.append('div')
36131 .attr('class', 'preset-list-button-wrap category col12');
36133 wrap.append('button')
36134 .attr('class', 'preset-list-button')
36135 .classed('expanded', false)
36136 .call(iD.ui.PresetIcon()
36137 .geometry(context.geometry(id))
36139 .on('click', function() {
36140 var isExpanded = d3.select(this).classed('expanded');
36141 var triangle = isExpanded ? '▶ ' : '▼ ';
36142 d3.select(this).classed('expanded', !isExpanded);
36143 d3.select(this).selectAll('.label').text(triangle + preset.name());
36147 .attr('class', 'label')
36149 return '▶ ' + preset.name();
36152 box = selection.append('div')
36153 .attr('class', 'subgrid col12')
36154 .style('max-height', '0px')
36155 .style('opacity', 0);
36158 .attr('class', 'arrow');
36160 sublist = box.append('div')
36161 .attr('class', 'preset-list fillL3 cf fl');
36164 item.choose = function() {
36165 if (!box || !sublist) return;
36171 .style('opacity', '0')
36172 .style('max-height', '0px')
36173 .style('padding-bottom', '0px');
36176 sublist.call(drawList, preset.members);
36179 .style('opacity', '1')
36180 .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
36181 .style('padding-bottom', '20px');
36185 item.preset = preset;
36190 function PresetItem(preset) {
36191 function item(selection) {
36192 var wrap = selection.append('div')
36193 .attr('class', 'preset-list-button-wrap col12');
36195 wrap.append('button')
36196 .attr('class', 'preset-list-button')
36197 .call(iD.ui.PresetIcon()
36198 .geometry(context.geometry(id))
36200 .on('click', item.choose)
36202 .attr('class', 'label')
36203 .text(preset.name());
36205 wrap.call(item.reference.button);
36206 selection.call(item.reference.body);
36209 item.choose = function() {
36210 context.presets().choose(preset);
36213 iD.actions.ChangePreset(id, currentPreset, preset),
36214 t('operations.change_tags.annotation'));
36216 event.choose(preset);
36219 item.help = function() {
36220 d3.event.stopPropagation();
36221 item.reference.toggle();
36224 item.preset = preset;
36225 item.reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context);
36230 presetList.autofocus = function(_) {
36231 if (!arguments.length) return autofocus;
36236 presetList.entityID = function(_) {
36237 if (!arguments.length) return id;
36239 presetList.preset(context.presets().match(context.entity(id), context.graph()));
36243 presetList.preset = function(_) {
36244 if (!arguments.length) return currentPreset;
36249 return d3.rebind(presetList, event, 'on');
36251 iD.ui.RadialMenu = function(context, operations) {
36256 var radialMenu = function(selection) {
36257 if (!operations.length)
36260 selection.node().parentNode.focus();
36262 function click(operation) {
36263 d3.event.stopPropagation();
36264 if (operation.disabled())
36267 radialMenu.close();
36270 menu = selection.append('g')
36271 .attr('class', 'radial-menu')
36272 .attr('transform', 'translate(' + center + ')')
36273 .attr('opacity', 0);
36276 .attr('opacity', 1);
36281 a1 = a0 + (operations.length - 1) * a;
36283 menu.append('path')
36284 .attr('class', 'radial-menu-background')
36285 .attr('d', 'M' + r * Math.sin(a0) + ',' +
36287 ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
36288 (r * Math.sin(a1) + 1e-3) + ',' +
36289 (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
36290 .attr('stroke-width', 50)
36291 .attr('stroke-linecap', 'round');
36293 var button = menu.selectAll()
36297 .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
36298 .classed('disabled', function(d) { return d.disabled(); })
36299 .attr('transform', function(d, i) {
36300 return 'translate(' + iD.geo.roundCoords([
36301 r * Math.sin(a0 + i * a),
36302 r * Math.cos(a0 + i * a)]).join(',') + ')';
36305 button.append('circle')
36307 .on('click', click)
36308 .on('mousedown', mousedown)
36309 .on('mouseover', mouseover)
36310 .on('mouseout', mouseout);
36312 button.append('use')
36313 .attr('transform', 'translate(-10,-10)')
36314 .attr('width', '20')
36315 .attr('height', '20')
36316 .attr('xlink:href', function(d) { return '#operation-' + d.id; });
36318 tooltip = d3.select(document.body)
36320 .attr('class', 'tooltip-inner radial-menu-tooltip');
36322 function mousedown() {
36323 d3.event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
36326 function mouseover(d, i) {
36327 var rect = context.surfaceRect(),
36328 angle = a0 + i * a,
36329 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
36330 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
36331 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
36332 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
36335 .style('top', null)
36336 .style('left', null)
36337 .style('bottom', null)
36338 .style('right', null)
36339 .style('display', 'block')
36340 .html(iD.ui.tooltipHtml(d.tooltip(), d.keys[0]));
36344 .style('right', right)
36345 .style('top', top);
36346 } else if (i >= 4) {
36348 .style('left', left)
36349 .style('bottom', bottom);
36352 .style('left', left)
36353 .style('top', top);
36357 function mouseout() {
36358 tooltip.style('display', 'none');
36362 radialMenu.close = function() {
36365 .style('pointer-events', 'none')
36367 .attr('opacity', 0)
36376 radialMenu.center = function(_) {
36377 if (!arguments.length) return center;
36384 iD.ui.RawMemberEditor = function(context) {
36387 function selectMember(d) {
36388 d3.event.preventDefault();
36389 context.enter(iD.modes.Select(context, [d.id]));
36392 function changeRole(d) {
36393 var role = d3.select(this).property('value');
36395 iD.actions.ChangeMember(d.relation.id, _.extend({}, d.id, {role: role}), d.index),
36396 t('operations.change_role.annotation'));
36399 function deleteMember(d) {
36401 iD.actions.DeleteMember(d.relation.id, d.index),
36402 t('operations.delete_member.annotation'));
36404 if (!context.hasEntity(d.relation.id)) {
36405 context.enter(iD.modes.Browse(context));
36409 function rawMemberEditor(selection) {
36410 var entity = context.entity(id),
36413 entity.members.forEach(function(member, index) {
36419 member: context.hasEntity(member.id)
36423 selection.call(iD.ui.Disclosure()
36424 .title(t('inspector.all_members') + ' (' + memberships.length + ')')
36426 .on('toggled', toggled)
36427 .content(content));
36429 function toggled(expanded) {
36431 selection.node().parentNode.scrollTop += 200;
36435 function content($wrap) {
36436 var $list = $wrap.selectAll('.member-list')
36439 $list.enter().append('ul')
36440 .attr('class', 'member-list');
36442 var $items = $list.selectAll('li')
36443 .data(memberships, function(d) {
36444 return iD.Entity.key(d.relation) + ',' + d.index + ',' +
36445 (d.member ? iD.Entity.key(d.member) : 'incomplete');
36448 var $enter = $items.enter().append('li')
36449 .attr('class', 'member-row form-field')
36450 .classed('member-incomplete', function(d) { return !d.member; });
36452 $enter.each(function(d) {
36454 var $label = d3.select(this).append('label')
36455 .attr('class', 'form-label')
36458 .on('click', selectMember);
36460 $label.append('span')
36461 .attr('class', 'member-entity-type')
36462 .text(function(d) { return context.presets().match(d.member, context.graph()).name(); });
36464 $label.append('span')
36465 .attr('class', 'member-entity-name')
36466 .text(function(d) { return iD.util.displayName(d.member); });
36469 d3.select(this).append('label')
36470 .attr('class', 'form-label')
36471 .text(t('inspector.incomplete'));
36475 $enter.append('input')
36476 .attr('class', 'member-role')
36477 .property('type', 'text')
36478 .attr('maxlength', 255)
36479 .attr('placeholder', t('inspector.role'))
36480 .property('value', function(d) { return d.role; })
36481 .on('change', changeRole);
36483 $enter.append('button')
36484 .attr('tabindex', -1)
36485 .attr('class', 'remove button-input-action member-delete minor')
36486 .on('click', deleteMember)
36487 .call(iD.svg.Icon('#operation-delete'));
36494 rawMemberEditor.entityID = function(_) {
36495 if (!arguments.length) return id;
36497 return rawMemberEditor;
36500 return rawMemberEditor;
36502 iD.ui.RawMembershipEditor = function(context) {
36505 function selectRelation(d) {
36506 d3.event.preventDefault();
36507 context.enter(iD.modes.Select(context, [d.relation.id]));
36510 function changeRole(d) {
36511 var role = d3.select(this).property('value');
36513 iD.actions.ChangeMember(d.relation.id, _.extend({}, d.member, {role: role}), d.index),
36514 t('operations.change_role.annotation'));
36517 function addMembership(d, role) {
36522 iD.actions.AddMember(d.relation.id, {id: id, type: context.entity(id).type, role: role}),
36523 t('operations.add_member.annotation'));
36526 var relation = iD.Relation();
36529 iD.actions.AddEntity(relation),
36530 iD.actions.AddMember(relation.id, {id: id, type: context.entity(id).type, role: role}),
36531 t('operations.add.annotation.relation'));
36533 context.enter(iD.modes.Select(context, [relation.id]));
36537 function deleteMembership(d) {
36539 iD.actions.DeleteMember(d.relation.id, d.index),
36540 t('operations.delete_member.annotation'));
36543 function relations(q) {
36544 var newRelation = {
36546 value: t('inspector.new_relation')
36549 graph = context.graph();
36551 context.intersects(context.extent()).forEach(function(entity) {
36552 if (entity.type !== 'relation' || entity.id === id)
36555 var presetName = context.presets().match(entity, graph).name(),
36556 entityName = iD.util.displayName(entity) || '';
36558 var value = presetName + ' ' + entityName;
36559 if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
36568 result.sort(function(a, b) {
36569 return iD.Relation.creationOrder(a.relation, b.relation);
36571 result.unshift(newRelation);
36576 function rawMembershipEditor(selection) {
36577 var entity = context.entity(id),
36580 context.graph().parentRelations(entity).forEach(function(relation) {
36581 relation.members.forEach(function(member, index) {
36582 if (member.id === entity.id) {
36583 memberships.push({relation: relation, member: member, index: index});
36588 selection.call(iD.ui.Disclosure()
36589 .title(t('inspector.all_relations') + ' (' + memberships.length + ')')
36591 .on('toggled', toggled)
36592 .content(content));
36594 function toggled(expanded) {
36596 selection.node().parentNode.scrollTop += 200;
36600 function content($wrap) {
36601 var $list = $wrap.selectAll('.member-list')
36604 $list.enter().append('ul')
36605 .attr('class', 'member-list');
36607 var $items = $list.selectAll('li.member-row-normal')
36608 .data(memberships, function(d) { return iD.Entity.key(d.relation) + ',' + d.index; });
36610 var $enter = $items.enter().append('li')
36611 .attr('class', 'member-row member-row-normal form-field');
36613 var $label = $enter.append('label')
36614 .attr('class', 'form-label')
36617 .on('click', selectRelation);
36619 $label.append('span')
36620 .attr('class', 'member-entity-type')
36621 .text(function(d) { return context.presets().match(d.relation, context.graph()).name(); });
36623 $label.append('span')
36624 .attr('class', 'member-entity-name')
36625 .text(function(d) { return iD.util.displayName(d.relation); });
36627 $enter.append('input')
36628 .attr('class', 'member-role')
36629 .property('type', 'text')
36630 .attr('maxlength', 255)
36631 .attr('placeholder', t('inspector.role'))
36632 .property('value', function(d) { return d.member.role; })
36633 .on('change', changeRole);
36635 $enter.append('button')
36636 .attr('tabindex', -1)
36637 .attr('class', 'remove button-input-action member-delete minor')
36638 .on('click', deleteMembership)
36639 .call(iD.svg.Icon('#operation-delete'));
36645 var $new = $list.selectAll('.member-row-new')
36648 $enter = $new.enter().append('li')
36649 .attr('class', 'member-row member-row-new form-field');
36651 $enter.append('input')
36652 .attr('type', 'text')
36653 .attr('class', 'member-entity-input')
36654 .call(d3.combobox()
36656 .fetcher(function(value, callback) {
36657 callback(relations(value));
36659 .on('accept', function(d) {
36660 addMembership(d, $new.select('.member-role').property('value'));
36663 $enter.append('input')
36664 .attr('class', 'member-role')
36665 .property('type', 'text')
36666 .attr('maxlength', 255)
36667 .attr('placeholder', t('inspector.role'))
36668 .on('change', changeRole);
36670 $enter.append('button')
36671 .attr('tabindex', -1)
36672 .attr('class', 'remove button-input-action member-delete minor')
36673 .on('click', deleteMembership)
36674 .call(iD.svg.Icon('#operation-delete'));
36677 $list.selectAll('.member-row-new')
36681 var $add = $wrap.selectAll('.add-relation')
36686 .attr('class', 'add-relation')
36687 .call(iD.svg.Icon('#icon-plus', 'light'));
36689 $wrap.selectAll('.add-relation')
36690 .on('click', function() {
36693 $list.selectAll('.member-entity-input').node().focus();
36698 rawMembershipEditor.entityID = function(_) {
36699 if (!arguments.length) return id;
36701 return rawMembershipEditor;
36704 return rawMembershipEditor;
36706 iD.ui.RawTagEditor = function(context) {
36707 var event = d3.dispatch('change'),
36714 function rawTagEditor(selection) {
36715 var count = Object.keys(tags).filter(function(d) { return d; }).length;
36717 selection.call(iD.ui.Disclosure()
36718 .title(t('inspector.all_tags') + ' (' + count + ')')
36719 .expanded(context.storage('raw_tag_editor.expanded') === 'true' || preset.isFallback())
36720 .on('toggled', toggled)
36721 .content(content));
36723 function toggled(expanded) {
36724 context.storage('raw_tag_editor.expanded', expanded);
36726 selection.node().parentNode.scrollTop += 200;
36731 function content($wrap) {
36732 var entries = d3.entries(tags);
36734 if (!entries.length || showBlank) {
36736 entries.push({key: '', value: ''});
36739 var $list = $wrap.selectAll('.tag-list')
36742 $list.enter().append('ul')
36743 .attr('class', 'tag-list');
36745 var $newTag = $wrap.selectAll('.add-tag')
36750 .attr('class', 'add-tag')
36751 .call(iD.svg.Icon('#icon-plus', 'light'));
36753 $newTag.on('click', addTag);
36755 var $items = $list.selectAll('li')
36756 .data(entries, function(d) { return d.key; });
36760 var $enter = $items.enter().append('li')
36761 .attr('class', 'tag-row cf');
36763 $enter.append('div')
36764 .attr('class', 'key-wrap')
36766 .property('type', 'text')
36767 .attr('class', 'key')
36768 .attr('maxlength', 255);
36770 $enter.append('div')
36771 .attr('class', 'input-wrap-position')
36773 .property('type', 'text')
36774 .attr('class', 'value')
36775 .attr('maxlength', 255);
36777 $enter.append('button')
36778 .attr('tabindex', -1)
36779 .attr('class', 'remove minor')
36780 .call(iD.svg.Icon('#operation-delete'));
36782 if (context.taginfo()) {
36783 $enter.each(bindTypeahead);
36790 $items.each(function(tag) {
36791 var isRelation = (context.entity(id).type === 'relation'),
36793 if (isRelation && tag.key === 'type')
36794 reference = iD.ui.TagReference({rtype: tag.value}, context);
36796 reference = iD.ui.TagReference({key: tag.key, value: tag.value}, context);
36798 if (state === 'hover') {
36799 reference.showing(false);
36803 .call(reference.button)
36804 .call(reference.body);
36807 $items.select('input.key')
36808 .value(function(d) { return d.key; })
36809 .on('blur', keyChange)
36810 .on('change', keyChange);
36812 $items.select('input.value')
36813 .value(function(d) { return d.value; })
36814 .on('blur', valueChange)
36815 .on('change', valueChange)
36816 .on('keydown.push-more', pushMore);
36818 $items.select('button.remove')
36819 .on('click', removeTag);
36825 function pushMore() {
36826 if (d3.event.keyCode === 9 && !d3.event.shiftKey &&
36827 $list.selectAll('li:last-child input.value').node() === this) {
36832 function bindTypeahead() {
36833 var row = d3.select(this),
36834 key = row.selectAll('input.key'),
36835 value = row.selectAll('input.value');
36837 function sort(value, data) {
36838 var sameletter = [],
36840 for (var i = 0; i < data.length; i++) {
36841 if (data[i].value.substring(0, value.length) === value) {
36842 sameletter.push(data[i]);
36844 other.push(data[i]);
36847 return sameletter.concat(other);
36850 key.call(d3.combobox()
36851 .fetcher(function(value, callback) {
36852 context.taginfo().keys({
36854 geometry: context.geometry(id),
36856 }, function(err, data) {
36857 if (!err) callback(sort(value, data));
36861 value.call(d3.combobox()
36862 .fetcher(function(value, callback) {
36863 context.taginfo().values({
36866 geometry: context.geometry(id),
36868 }, function(err, data) {
36869 if (!err) callback(sort(value, data));
36874 function unbind() {
36875 var row = d3.select(this);
36877 row.selectAll('input.key')
36878 .call(d3.combobox.off);
36880 row.selectAll('input.value')
36881 .call(d3.combobox.off);
36884 function keyChange(d) {
36886 kNew = this.value.trim(),
36889 if (kNew && kNew !== kOld) {
36890 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
36892 suffix = +(match[2] || 1);
36893 while (tags[kNew]) { // rename key if already in use
36894 kNew = base + '_' + suffix++;
36897 tag[kOld] = undefined;
36898 tag[kNew] = d.value;
36899 d.key = kNew; // Maintain DOM identity through the subsequent update.
36904 function valueChange(d) {
36906 tag[d.key] = this.value;
36910 function removeTag(d) {
36912 tag[d.key] = undefined;
36914 d3.select(this.parentNode).remove();
36917 function addTag() {
36918 // Wrapped in a setTimeout in case it's being called from a blur
36919 // handler. Without the setTimeout, the call to `content` would
36920 // wipe out the pending value change.
36921 setTimeout(function() {
36924 $list.selectAll('li:last-child input.key').node().focus();
36929 rawTagEditor.state = function(_) {
36930 if (!arguments.length) return state;
36932 return rawTagEditor;
36935 rawTagEditor.preset = function(_) {
36936 if (!arguments.length) return preset;
36938 return rawTagEditor;
36941 rawTagEditor.tags = function(_) {
36942 if (!arguments.length) return tags;
36944 return rawTagEditor;
36947 rawTagEditor.entityID = function(_) {
36948 if (!arguments.length) return id;
36950 return rawTagEditor;
36953 return d3.rebind(rawTagEditor, event, 'on');
36955 iD.ui.Restore = function(context) {
36956 return function(selection) {
36957 if (!context.history().lock() || !context.history().restorableChanges())
36960 var modal = iD.ui.modal(selection);
36962 modal.select('.modal')
36963 .attr('class', 'modal fillL col6');
36965 var introModal = modal.select('.content');
36967 introModal.attr('class','cf');
36969 introModal.append('div')
36970 .attr('class', 'modal-section')
36972 .text(t('restore.heading'));
36974 introModal.append('div')
36975 .attr('class','modal-section')
36977 .text(t('restore.description'));
36979 var buttonWrap = introModal.append('div')
36980 .attr('class', 'modal-actions cf');
36982 var restore = buttonWrap.append('button')
36983 .attr('class', 'restore col6')
36984 .text(t('restore.restore'))
36985 .on('click', function() {
36986 context.history().restore();
36990 buttonWrap.append('button')
36991 .attr('class', 'reset col6')
36992 .text(t('restore.reset'))
36993 .on('click', function() {
36994 context.history().clearSaved();
36998 restore.node().focus();
37001 iD.ui.Save = function(context) {
37002 var history = context.history(),
37003 key = iD.ui.cmd('⌘S');
37005 function saving() {
37006 return context.mode().id === 'save';
37010 d3.event.preventDefault();
37011 if (!context.inIntro() && !saving() && history.hasChanges()) {
37012 context.enter(iD.modes.Save(context));
37016 return function(selection) {
37017 var tooltip = bootstrap.tooltip()
37018 .placement('bottom')
37020 .title(iD.ui.tooltipHtml(t('save.no_changes'), key));
37022 var button = selection.append('button')
37023 .attr('class', 'save col12 disabled')
37024 .attr('tabindex', -1)
37028 button.append('span')
37029 .attr('class', 'label')
37030 .text(t('save.title'));
37032 button.append('span')
37033 .attr('class', 'count')
37036 var keybinding = d3.keybinding('undo-redo')
37037 .on(key, save, true);
37039 d3.select(document)
37042 var numChanges = 0;
37044 context.history().on('change.save', function() {
37045 var _ = history.difference().summary().length;
37046 if (_ === numChanges)
37050 tooltip.title(iD.ui.tooltipHtml(t(numChanges > 0 ?
37051 'save.help' : 'save.no_changes'), key));
37054 .classed('disabled', numChanges === 0)
37055 .classed('has-count', numChanges > 0);
37057 button.select('span.count')
37061 context.on('enter.save', function() {
37062 button.property('disabled', saving());
37063 if (saving()) button.call(tooltip.hide);
37067 iD.ui.Scale = function(context) {
37068 var projection = context.projection,
37072 function scaleDefs(loc1, loc2) {
37073 var lat = (loc2[1] + loc1[1]) / 2,
37074 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
37075 conversion = (imperial ? 3.28084 : 1),
37076 dist = iD.geo.lonToMeters(loc2[0] - loc1[0], lat) * conversion,
37077 scale = { dist: 0, px: 0, text: '' },
37078 buckets, i, val, dLon;
37081 buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
37083 buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
37086 // determine a user-friendly endpoint for the scale
37087 for (i = 0; i < buckets.length; i++) {
37090 scale.dist = Math.floor(dist / val) * val;
37095 dLon = iD.geo.metersToLon(scale.dist / conversion, lat);
37096 scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
37099 if (scale.dist >= 5280) {
37100 scale.dist /= 5280;
37101 scale.text = String(scale.dist) + ' mi';
37103 scale.text = String(scale.dist) + ' ft';
37106 if (scale.dist >= 1000) {
37107 scale.dist /= 1000;
37108 scale.text = String(scale.dist) + ' km';
37110 scale.text = String(scale.dist) + ' m';
37117 function update(selection) {
37118 // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
37119 var dims = context.map().dimensions(),
37120 loc1 = projection.invert([0, dims[1]]),
37121 loc2 = projection.invert([maxLength, dims[1]]),
37122 scale = scaleDefs(loc1, loc2);
37124 selection.select('#scalepath')
37125 .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
37127 selection.select('#scaletext')
37128 .attr('x', scale.px + 8)
37129 .attr('y', tickHeight)
37133 return function(selection) {
37134 var g = selection.append('svg')
37135 .attr('id', 'scale')
37137 .attr('transform', 'translate(10,11)');
37139 g.append('path').attr('id', 'scalepath');
37140 g.append('text').attr('id', 'scaletext');
37144 context.map().on('move.scale', function() {
37149 iD.ui.SelectionList = function(context, selectedIDs) {
37151 function selectEntity(entity) {
37152 context.enter(iD.modes.Select(context, [entity.id]).suppressMenu(true));
37156 function selectionList(selection) {
37157 selection.classed('selection-list-pane', true);
37159 var header = selection.append('div')
37160 .attr('class', 'header fillL cf');
37162 header.append('h3')
37163 .text(t('inspector.multiselect'));
37165 var listWrap = selection.append('div')
37166 .attr('class', 'inspector-body');
37168 var list = listWrap.append('div')
37169 .attr('class', 'feature-list cf');
37171 context.history().on('change.selection-list', drawList);
37174 function drawList() {
37175 var entities = selectedIDs
37176 .map(function(id) { return context.hasEntity(id); })
37177 .filter(function(entity) { return entity; });
37179 var items = list.selectAll('.feature-list-item')
37180 .data(entities, iD.Entity.key);
37182 var enter = items.enter().append('button')
37183 .attr('class', 'feature-list-item')
37184 .on('click', selectEntity);
37187 var label = enter.append('div')
37188 .attr('class', 'label')
37189 .call(iD.svg.Icon('', 'pre-text'));
37191 label.append('span')
37192 .attr('class', 'entity-type');
37194 label.append('span')
37195 .attr('class', 'entity-name');
37198 items.selectAll('use')
37199 .attr('href', function() {
37200 var entity = this.parentNode.parentNode.__data__;
37201 return '#icon-' + context.geometry(entity.id);
37204 items.selectAll('.entity-type')
37205 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
37207 items.selectAll('.entity-name')
37208 .text(function(entity) { return iD.util.displayName(entity); });
37216 return selectionList;
37219 iD.ui.Sidebar = function(context) {
37220 var inspector = iD.ui.Inspector(context),
37223 function sidebar(selection) {
37224 var featureListWrap = selection.append('div')
37225 .attr('class', 'feature-list-pane')
37226 .call(iD.ui.FeatureList(context));
37228 selection.call(iD.ui.Notice(context));
37230 var inspectorWrap = selection.append('div')
37231 .attr('class', 'inspector-hidden inspector-wrap fr');
37233 function hover(id) {
37234 if (!current && context.hasEntity(id)) {
37235 featureListWrap.classed('inspector-hidden', true);
37236 inspectorWrap.classed('inspector-hidden', false)
37237 .classed('inspector-hover', true);
37239 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
37244 inspectorWrap.call(inspector);
37246 } else if (!current) {
37247 featureListWrap.classed('inspector-hidden', false);
37248 inspectorWrap.classed('inspector-hidden', true);
37249 inspector.state('hide');
37253 sidebar.hover = _.throttle(hover, 200);
37255 sidebar.select = function(id, newFeature) {
37256 if (!current && id) {
37257 featureListWrap.classed('inspector-hidden', true);
37258 inspectorWrap.classed('inspector-hidden', false)
37259 .classed('inspector-hover', false);
37261 if (inspector.entityID() !== id || inspector.state() !== 'select') {
37265 .newFeature(newFeature);
37267 inspectorWrap.call(inspector);
37269 } else if (!current) {
37270 featureListWrap.classed('inspector-hidden', false);
37271 inspectorWrap.classed('inspector-hidden', true);
37272 inspector.state('hide');
37276 sidebar.show = function(component) {
37277 featureListWrap.classed('inspector-hidden', true);
37278 inspectorWrap.classed('inspector-hidden', true);
37279 if (current) current.remove();
37280 current = selection.append('div')
37281 .attr('class', 'sidebar-component')
37285 sidebar.hide = function() {
37286 featureListWrap.classed('inspector-hidden', false);
37287 inspectorWrap.classed('inspector-hidden', true);
37288 if (current) current.remove();
37293 sidebar.hover = function() {};
37294 sidebar.hover.cancel = function() {};
37295 sidebar.select = function() {};
37296 sidebar.show = function() {};
37297 sidebar.hide = function() {};
37301 iD.ui.SourceSwitch = function(context) {
37305 d3.event.preventDefault();
37307 if (context.history().hasChanges() &&
37308 !window.confirm(t('source_switch.lose_changes'))) return;
37310 var live = d3.select(this)
37313 context.connection()
37314 .switch(live ? keys[1] : keys[0]);
37316 context.enter(iD.modes.Browse(context));
37320 .text(live ? t('source_switch.dev') : t('source_switch.live'))
37321 .classed('live', !live);
37324 var sourceSwitch = function(selection) {
37325 selection.append('a')
37327 .text(t('source_switch.live'))
37328 .classed('live', true)
37329 .attr('tabindex', -1)
37330 .on('click', click);
37333 sourceSwitch.keys = function(_) {
37334 if (!arguments.length) return keys;
37336 return sourceSwitch;
37339 return sourceSwitch;
37341 iD.ui.Spinner = function(context) {
37342 var connection = context.connection();
37344 return function(selection) {
37345 var img = selection.append('img')
37346 .attr('src', context.imagePath('loader-black.gif'))
37347 .style('opacity', 0);
37349 connection.on('loading.spinner', function() {
37351 .style('opacity', 1);
37354 connection.on('loaded.spinner', function() {
37356 .style('opacity', 0);
37360 iD.ui.Splash = function(context) {
37361 return function(selection) {
37362 if (context.storage('sawSplash'))
37365 context.storage('sawSplash', true);
37367 var modal = iD.ui.modal(selection);
37369 modal.select('.modal')
37370 .attr('class', 'modal-splash modal col6');
37372 var introModal = modal.select('.content')
37374 .attr('class', 'fillL');
37376 introModal.append('div')
37377 .attr('class','modal-section cf')
37378 .append('h3').text(t('splash.welcome'));
37380 introModal.append('div')
37381 .attr('class','modal-section')
37383 .html(t('splash.text', {
37384 version: iD.version,
37385 website: '<a href="http://ideditor.com/">ideditor.com</a>',
37386 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
37389 var buttons = introModal.append('div').attr('class', 'modal-actions cf');
37391 buttons.append('button')
37392 .attr('class', 'col6 walkthrough')
37393 .text(t('splash.walkthrough'))
37394 .on('click', function() {
37395 d3.select(document.body).call(iD.ui.intro(context));
37399 buttons.append('button')
37400 .attr('class', 'col6 start')
37401 .text(t('splash.start'))
37402 .on('click', modal.close);
37404 modal.select('button.close').attr('class','hide');
37408 iD.ui.Status = function(context) {
37409 var connection = context.connection(),
37412 return function(selection) {
37414 function update() {
37416 connection.status(function(err, apiStatus) {
37418 selection.html('');
37420 if (err && errCount++ < 2) return;
37423 selection.text(t('status.error'));
37425 } else if (apiStatus === 'readonly') {
37426 selection.text(t('status.readonly'));
37428 } else if (apiStatus === 'offline') {
37429 selection.text(t('status.offline'));
37432 selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
37433 if (!err) errCount = 0;
37438 connection.on('auth', function() { update(selection); });
37439 window.setInterval(update, 90000);
37443 iD.ui.Success = function(context) {
37444 var dispatch = d3.dispatch('cancel'),
37447 function success(selection) {
37448 var message = (changeset.comment || t('success.edited_osm')).substring(0, 130) +
37449 ' ' + context.connection().changesetURL(changeset.id);
37451 var header = selection.append('div')
37452 .attr('class', 'header fillL');
37454 header.append('button')
37455 .attr('class', 'fr')
37456 .on('click', function() { dispatch.cancel(); })
37457 .call(iD.svg.Icon('#icon-close'));
37459 header.append('h3')
37460 .text(t('success.just_edited'));
37462 var body = selection.append('div')
37463 .attr('class', 'body save-success fillL');
37466 .html(t('success.help_html'));
37469 .attr('class', 'details')
37470 .attr('target', '_blank')
37471 .attr('tabindex', -1)
37472 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37473 .attr('href', t('success.help_link_url'))
37475 .text(t('success.help_link_text'));
37477 var changesetURL = context.connection().changesetURL(changeset.id);
37480 .attr('class', 'button col12 osm')
37481 .attr('target', '_blank')
37482 .attr('href', changesetURL)
37483 .text(t('success.view_on_osm'));
37486 facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
37487 twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
37488 google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
37491 body.selectAll('.button.social')
37492 .data(d3.entries(sharing))
37495 .attr('class', 'button social col4')
37496 .attr('target', '_blank')
37497 .attr('href', function(d) { return d.value; })
37498 .call(bootstrap.tooltip()
37499 .title(function(d) { return t('success.' + d.key); })
37500 .placement('bottom'))
37501 .each(function(d) { d3.select(this).call(iD.svg.Icon('#logo-' + d.key, 'social')); });
37504 success.changeset = function(_) {
37505 if (!arguments.length) return changeset;
37510 return d3.rebind(success, dispatch, 'on');
37512 iD.ui.TagReference = function(tag, context) {
37513 var tagReference = {},
37519 function findLocal(data) {
37520 var locale = iD.detect().locale.toLowerCase(),
37523 localized = _.find(data, function(d) {
37524 return d.lang.toLowerCase() === locale;
37526 if (localized) return localized;
37528 // try the non-regional version of a language, like
37529 // 'en' if the language is 'en-US'
37530 if (locale.indexOf('-') !== -1) {
37531 var first = locale.split('-')[0];
37532 localized = _.find(data, function(d) {
37533 return d.lang.toLowerCase() === first;
37535 if (localized) return localized;
37538 // finally fall back to english
37539 return _.find(data, function(d) {
37540 return d.lang.toLowerCase() === 'en';
37544 function load(param) {
37545 button.classed('tag-reference-loading', true);
37547 context.taginfo().docs(param, function show(err, data) {
37549 if (!err && data) {
37550 docs = findLocal(data);
37555 if (!docs || !docs.description) {
37556 if (param.hasOwnProperty('value')) {
37557 load(_.omit(param, 'value')); // retry with key only
37559 body.append('p').text(t('inspector.no_documentation_key'));
37565 if (docs.image && docs.image.thumb_url_prefix) {
37568 .attr('class', 'wiki-image')
37569 .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
37570 .on('load', function() { done(); })
37571 .on('error', function() { d3.select(this).remove(); done(); });
37578 .text(docs.description);
37582 .attr('target', '_blank')
37583 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
37584 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37586 .text(t('inspector.reference'));
37593 button.classed('tag-reference-loading', false);
37597 .style('max-height', '200px')
37598 .style('opacity', '1');
37603 function hide(selection) {
37604 selection = selection || body.transition().duration(200);
37607 .style('max-height', '0px')
37608 .style('opacity', '0');
37613 tagReference.button = function(selection) {
37614 button = selection.selectAll('.tag-reference-button')
37619 .attr('class', 'tag-reference-button')
37620 .attr('tabindex', -1)
37621 .call(iD.svg.Icon('#icon-inspect'));
37623 button.on('click', function () {
37624 d3.event.stopPropagation();
37625 d3.event.preventDefault();
37628 } else if (loaded) {
37631 if (context.taginfo()) {
37638 tagReference.body = function(selection) {
37639 body = selection.selectAll('.tag-reference-body')
37642 body.enter().append('div')
37643 .attr('class', 'tag-reference-body cf')
37644 .style('max-height', '0')
37645 .style('opacity', '0');
37647 if (showing === false) {
37652 tagReference.showing = function(_) {
37653 if (!arguments.length) return showing;
37655 return tagReference;
37658 return tagReference;
37660 // toggles the visibility of ui elements, using a combination of the
37661 // hide class, which sets display=none, and a d3 transition for opacity.
37662 // this will cause blinking when called repeatedly, so check that the
37663 // value actually changes between calls.
37664 iD.ui.Toggle = function(show, callback) {
37665 return function(selection) {
37667 .style('opacity', show ? 0 : 1)
37668 .classed('hide', false)
37670 .style('opacity', show ? 1 : 0)
37671 .each('end', function() {
37673 .classed('hide', !show)
37674 .style('opacity', null);
37675 if (callback) callback.apply(this);
37679 iD.ui.UndoRedo = function(context) {
37682 cmd: iD.ui.cmd('⌘Z'),
37683 action: function() { if (!(context.inIntro() || saving())) context.undo(); },
37684 annotation: function() { return context.history().undoAnnotation(); }
37687 cmd: iD.ui.cmd('⌘⇧Z'),
37688 action: function() {if (!(context.inIntro() || saving())) context.redo(); },
37689 annotation: function() { return context.history().redoAnnotation(); }
37692 function saving() {
37693 return context.mode().id === 'save';
37696 return function(selection) {
37697 var tooltip = bootstrap.tooltip()
37698 .placement('bottom')
37700 .title(function (d) {
37701 return iD.ui.tooltipHtml(d.annotation() ?
37702 t(d.id + '.tooltip', {action: d.annotation()}) :
37703 t(d.id + '.nothing'), d.cmd);
37706 var buttons = selection.selectAll('button')
37708 .enter().append('button')
37709 .attr('class', 'col6 disabled')
37710 .on('click', function(d) { return d.action(); })
37713 buttons.each(function(d) {
37715 .call(iD.svg.Icon('#icon-' + d.id));
37718 var keybinding = d3.keybinding('undo')
37719 .on(commands[0].cmd, function() { d3.event.preventDefault(); commands[0].action(); })
37720 .on(commands[1].cmd, function() { d3.event.preventDefault(); commands[1].action(); });
37722 d3.select(document)
37726 .on('change.undo_redo', update);
37729 .on('enter.undo_redo', update);
37731 function update() {
37733 .property('disabled', saving())
37734 .classed('disabled', function(d) { return !d.annotation(); })
37736 var selection = d3.select(this);
37737 if (selection.property('tooltipVisible')) {
37738 selection.call(tooltip.show);
37744 iD.ui.ViewOnOSM = function(context) {
37747 function viewOnOSM(selection) {
37748 var entity = context.entity(id);
37750 selection.style('display', entity.isNew() ? 'none' : null);
37752 var $link = selection.selectAll('.view-on-osm')
37757 .attr('class', 'view-on-osm')
37758 .attr('target', '_blank')
37759 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37761 .text(t('inspector.view_on_osm'));
37764 .attr('href', context.connection().entityURL(entity));
37767 viewOnOSM.entityID = function(_) {
37768 if (!arguments.length) return id;
37775 iD.ui.Zoom = function(context) {
37779 title: t('zoom.in'),
37780 action: context.zoomIn,
37785 title: t('zoom.out'),
37786 action: context.zoomOut,
37790 function zoomIn() {
37791 d3.event.preventDefault();
37792 if (!context.inIntro()) context.zoomIn();
37795 function zoomOut() {
37796 d3.event.preventDefault();
37797 if (!context.inIntro()) context.zoomOut();
37800 function zoomInFurther() {
37801 d3.event.preventDefault();
37802 if (!context.inIntro()) context.zoomInFurther();
37805 function zoomOutFurther() {
37806 d3.event.preventDefault();
37807 if (!context.inIntro()) context.zoomOutFurther();
37811 return function(selection) {
37812 var button = selection.selectAll('button')
37814 .enter().append('button')
37815 .attr('tabindex', -1)
37816 .attr('class', function(d) { return d.id; })
37817 .on('click.editor', function(d) { d.action(); })
37818 .call(bootstrap.tooltip()
37821 .title(function(d) {
37822 return iD.ui.tooltipHtml(d.title, d.key);
37825 button.each(function(d) {
37827 .call(iD.svg.Icon('#icon-' + d.icon, 'light'));
37830 var keybinding = d3.keybinding('zoom');
37832 _.each(['=','ffequals','plus','ffplus'], function(key) {
37833 keybinding.on(key, zoomIn);
37834 keybinding.on('⇧' + key, zoomIn);
37835 keybinding.on(iD.ui.cmd('⌘' + key), zoomInFurther);
37836 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomInFurther);
37838 _.each(['-','ffminus','_','dash'], function(key) {
37839 keybinding.on(key, zoomOut);
37840 keybinding.on('⇧' + key, zoomOut);
37841 keybinding.on(iD.ui.cmd('⌘' + key), zoomOutFurther);
37842 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomOutFurther);
37845 d3.select(document)
37849 iD.ui.preset.access = function(field) {
37850 var dispatch = d3.dispatch('change'),
37853 function access(selection) {
37854 var wrap = selection.selectAll('.preset-input-wrap')
37857 wrap.enter().append('div')
37858 .attr('class', 'cf preset-input-wrap')
37861 items = wrap.select('ul').selectAll('li')
37866 var enter = items.enter().append('li')
37867 .attr('class', function(d) { return 'cf preset-access-' + d; });
37869 enter.append('span')
37870 .attr('class', 'col6 label preset-label-access')
37871 .attr('for', function(d) { return 'preset-input-access-' + d; })
37872 .text(function(d) { return field.t('types.' + d); });
37874 enter.append('div')
37875 .attr('class', 'col6 preset-input-access-wrap')
37877 .attr('type', 'text')
37878 .attr('class', 'preset-input-access')
37879 .attr('id', function(d) { return 'preset-input-access-' + d; })
37880 .each(function(d) {
37882 .call(d3.combobox()
37883 .data(access.options(d)));
37888 wrap.selectAll('.preset-input-access')
37889 .on('change', change)
37890 .on('blur', change);
37893 function change(d) {
37895 tag[d] = d3.select(this).value() || undefined;
37896 dispatch.change(tag);
37899 access.options = function(type) {
37900 var options = ['no', 'permissive', 'private', 'destination'];
37902 if (type !== 'access') {
37903 options.unshift('yes');
37904 options.push('designated');
37906 if (type === 'bicycle') {
37907 options.push('dismount');
37911 return options.map(function(option) {
37913 title: field.t('options.' + option + '.description'),
37919 var placeholders = {
37921 foot: 'designated',
37922 motor_vehicle: 'no'
37926 motor_vehicle: 'no',
37932 motor_vehicle: 'no'
37935 motor_vehicle: 'no',
37936 bicycle: 'designated'
37939 motor_vehicle: 'no',
37940 horse: 'designated'
37944 motor_vehicle: 'no',
37950 motor_vehicle: 'yes',
37955 motor_vehicle: 'yes'
37959 motor_vehicle: 'yes',
37965 motor_vehicle: 'yes',
37971 motor_vehicle: 'yes',
37977 motor_vehicle: 'yes',
37983 motor_vehicle: 'yes',
37989 motor_vehicle: 'yes',
37995 motor_vehicle: 'yes',
38000 motor_vehicle: 'yes'
38004 motor_vehicle: 'yes',
38010 motor_vehicle: 'yes',
38016 motor_vehicle: 'yes',
38022 access.tags = function(tags) {
38023 items.selectAll('.preset-input-access')
38024 .value(function(d) { return tags[d] || ''; })
38025 .attr('placeholder', function() {
38026 return tags.access ? tags.access : field.placeholder();
38029 // items.selectAll('#preset-input-access-access')
38030 // .attr('placeholder', 'yes');
38032 _.forEach(placeholders[tags.highway], function(v, k) {
38033 items.selectAll('#preset-input-access-' + k)
38034 .attr('placeholder', function() { return (tags.access || v); });
38038 access.focus = function() {
38039 items.selectAll('.preset-input-access')
38043 return d3.rebind(access, dispatch, 'on');
38045 iD.ui.preset.address = function(field, context) {
38046 var dispatch = d3.dispatch('init', 'change'),
38059 function getStreets() {
38060 var extent = entity.extent(context.graph()),
38061 l = extent.center(),
38062 box = iD.geo.Extent(l).padByMeters(200);
38064 return context.intersects(box)
38065 .filter(isAddressable)
38067 var loc = context.projection([
38068 (extent[0][0] + extent[1][0]) / 2,
38069 (extent[0][1] + extent[1][1]) / 2]),
38070 choice = iD.geo.chooseEdge(context.childNodes(d), loc, context.projection);
38072 title: d.tags.name,
38073 value: d.tags.name,
38074 dist: choice.distance
38076 }).sort(function(a, b) {
38077 return a.dist - b.dist;
38080 function isAddressable(d) {
38081 return d.tags.highway && d.tags.name && d.type === 'way';
38085 function getCities() {
38086 var extent = entity.extent(context.graph()),
38087 l = extent.center(),
38088 box = iD.geo.Extent(l).padByMeters(200);
38090 return context.intersects(box)
38091 .filter(isAddressable)
38094 title: d.tags['addr:city'] || d.tags.name,
38095 value: d.tags['addr:city'] || d.tags.name,
38096 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
38098 }).sort(function(a, b) {
38099 return a.dist - b.dist;
38102 function isAddressable(d) {
38104 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
38107 if (d.tags.place && d.tags.name && (
38108 d.tags.place === 'city' ||
38109 d.tags.place === 'town' ||
38110 d.tags.place === 'village'))
38113 if (d.tags['addr:city']) return true;
38119 function getPostCodes() {
38120 var extent = entity.extent(context.graph()),
38121 l = extent.center(),
38122 box = iD.geo.Extent(l).padByMeters(200);
38124 return context.intersects(box)
38125 .filter(isAddressable)
38128 title: d.tags['addr:postcode'],
38129 value: d.tags['addr:postcode'],
38130 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
38132 }).sort(function(a, b) {
38133 return a.dist - b.dist;
38136 function isAddressable(d) {
38137 return d.tags['addr:postcode'];
38141 function address(selection) {
38142 isInitialized = false;
38144 wrap = selection.selectAll('.preset-input-wrap')
38151 .attr('class', 'preset-input-wrap');
38153 var center = entity.extent(context.graph()).center(),
38156 iD.services.nominatim().countryCode(center, function (err, countryCode) {
38157 addressFormat = _.find(iD.data.addressFormats, function (a) {
38158 return a && a.countryCodes && _.contains(a.countryCodes, countryCode);
38159 }) || _.first(iD.data.addressFormats);
38162 // Normalize widths.
38163 var total = _.reduce(r, function(sum, field) {
38164 return sum + (widths[field] || 0.5);
38167 return r.map(function (field) {
38170 width: (widths[field] || 0.5) / total
38175 wrap.selectAll('div')
38176 .data(addressFormat.format)
38179 .attr('class', 'addr-row')
38180 .selectAll('input')
38184 .property('type', 'text')
38185 .attr('placeholder', function (d) { return field.t('placeholders.' + d.id); })
38186 .attr('class', function (d) { return 'addr-' + d.id; })
38187 .style('width', function (d) { return d.width * 100 + '%'; });
38191 wrap.selectAll('.addr-street')
38192 .call(d3.combobox()
38193 .fetcher(function(value, callback) {
38194 callback(getStreets());
38197 wrap.selectAll('.addr-city')
38198 .call(d3.combobox()
38199 .fetcher(function(value, callback) {
38200 callback(getCities());
38203 wrap.selectAll('.addr-postcode')
38204 .call(d3.combobox()
38205 .fetcher(function(value, callback) {
38206 callback(getPostCodes());
38209 wrap.selectAll('input')
38210 .on('blur', change())
38211 .on('change', change());
38213 wrap.selectAll('input:not(.combobox-input)')
38214 .on('input', change(true));
38217 isInitialized = true;
38221 function change(onInput) {
38222 return function() {
38225 wrap.selectAll('input')
38226 .each(function (field) {
38227 tags['addr:' + field.id] = this.value || undefined;
38230 dispatch.change(tags, onInput);
38234 function updateTags(tags) {
38235 wrap.selectAll('input')
38236 .value(function (field) {
38237 return tags['addr:' + field.id] || '';
38241 address.entity = function(_) {
38242 if (!arguments.length) return entity;
38247 address.tags = function(tags) {
38248 if (isInitialized) {
38251 dispatch.on('init', function () {
38257 address.focus = function() {
38258 var node = wrap.selectAll('input').node();
38259 if (node) node.focus();
38262 return d3.rebind(address, dispatch, 'on');
38264 iD.ui.preset.check =
38265 iD.ui.preset.defaultcheck = function(field) {
38266 var dispatch = d3.dispatch('change'),
38267 options = field.strings && field.strings.options,
38270 entity, value, box, text, label;
38273 for (var k in options) {
38274 values.push(k === 'undefined' ? undefined : k);
38275 texts.push(field.t('options.' + k, { 'default': options[k] }));
38278 values = [undefined, 'yes'];
38279 texts = [t('inspector.unknown'), t('inspector.check.yes')];
38280 if (field.type === 'check') {
38282 texts.push(t('inspector.check.no'));
38286 var check = function(selection) {
38287 // hack: pretend oneway field is a oneway_yes field
38288 // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
38289 if (field.id === 'oneway') {
38290 for (var key in entity.tags) {
38291 if (key in iD.oneWayTags && (entity.tags[key] in iD.oneWayTags[key])) {
38292 texts[0] = t('presets.fields.oneway_yes.options.undefined');
38298 selection.classed('checkselect', 'true');
38300 label = selection.selectAll('.preset-input-wrap')
38303 var enter = label.enter().append('label')
38304 .attr('class', 'preset-input-wrap');
38306 enter.append('input')
38307 .property('indeterminate', field.type === 'check')
38308 .attr('type', 'checkbox')
38309 .attr('id', 'preset-input-' + field.id);
38311 enter.append('span')
38313 .attr('class', 'value');
38315 box = label.select('input')
38316 .on('click', function() {
38318 t[field.key] = values[(values.indexOf(value) + 1) % values.length];
38319 dispatch.change(t);
38320 d3.event.stopPropagation();
38323 text = label.select('span.value');
38326 check.entity = function(_) {
38327 if (!arguments.length) return entity;
38332 check.tags = function(tags) {
38333 value = tags[field.key];
38334 box.property('indeterminate', field.type === 'check' && !value);
38335 box.property('checked', value === 'yes');
38336 text.text(texts[values.indexOf(value)]);
38337 label.classed('set', !!value);
38340 check.focus = function() {
38341 box.node().focus();
38344 return d3.rebind(check, dispatch, 'on');
38346 iD.ui.preset.combo =
38347 iD.ui.preset.typeCombo = function(field, context) {
38348 var dispatch = d3.dispatch('change'),
38349 optstrings = field.strings && field.strings.options,
38350 optarray = field.options,
38351 snake_case = (field.snake_case || (field.snake_case === undefined)),
38355 function snake(s) {
38356 return s.replace(/\s+/g, '_');
38359 function unsnake(s) {
38360 return s.replace(/_+/g, ' ');
38363 function clean(s) {
38364 return s.split(';')
38365 .map(function(s) { return s.trim(); })
38369 function optString() {
38370 return _.find(_.keys(strings), function(k) {
38371 return strings[k] === input.value();
38375 function combo(selection) {
38376 var combobox = d3.combobox();
38378 input = selection.selectAll('input')
38381 var enter = input.enter()
38383 .attr('type', 'text')
38384 .attr('id', 'preset-input-' + field.id);
38386 if (optstrings) { enter.attr('readonly', 'readonly'); }
38390 .on('change', change)
38391 .on('blur', change)
38394 _.each(optstrings, function(v, k) {
38395 strings[k] = field.t('options.' + k, { 'default': v });
38398 } else if (optarray) {
38399 _.each(optarray, function(k) {
38400 strings[k] = (snake_case ? unsnake(k) : k);
38403 } else if (context.taginfo()) {
38404 context.taginfo().values({key: field.key}, function(err, data) {
38406 _.each(_.pluck(data, 'value'), function(k) {
38407 strings[k] = (snake_case ? unsnake(k) : k);
38415 function stringsLoaded() {
38416 var keys = _.keys(strings),
38420 combobox.data(keys.map(function(k) {
38421 var s = strings[k],
38423 o.title = o.value = s;
38424 if (s.length < 20) { strs.push(s); }
38428 placeholders = strs.length > 1 ? strs : keys;
38429 input.attr('placeholder', field.placeholder() ||
38430 (placeholders.slice(0, 3).join(', ') + '...'));
38434 function change() {
38435 var value = optString() || clean(input.value());
38438 value = snake(value);
38440 if (field.type === 'typeCombo' && !value) {
38445 t[field.key] = value || undefined;
38446 dispatch.change(t);
38449 combo.tags = function(tags) {
38450 var key = tags[field.key],
38451 optstring = optString(),
38452 value = strings[key] || key || '';
38454 if (field.type === 'typeCombo' && value.toLowerCase() === 'yes') {
38457 if (!optstring && snake_case) {
38458 value = unsnake(value);
38460 input.value(value);
38463 combo.focus = function() {
38464 input.node().focus();
38467 return d3.rebind(combo, dispatch, 'on');
38469 iD.ui.preset.cycleway = function(field) {
38470 var dispatch = d3.dispatch('change'),
38473 function cycleway(selection) {
38474 var wrap = selection.selectAll('.preset-input-wrap')
38477 wrap.enter().append('div')
38478 .attr('class', 'cf preset-input-wrap')
38481 items = wrap.select('ul').selectAll('li')
38486 var enter = items.enter().append('li')
38487 .attr('class', function(d) { return 'cf preset-cycleway-' + d; });
38489 enter.append('span')
38490 .attr('class', 'col6 label preset-label-cycleway')
38491 .attr('for', function(d) { return 'preset-input-cycleway-' + d; })
38492 .text(function(d) { return field.t('types.' + d); });
38494 enter.append('div')
38495 .attr('class', 'col6 preset-input-cycleway-wrap')
38497 .attr('type', 'text')
38498 .attr('class', 'preset-input-cycleway')
38499 .attr('id', function(d) { return 'preset-input-cycleway-' + d; })
38500 .each(function(d) {
38502 .call(d3.combobox()
38503 .data(cycleway.options(d)));
38508 wrap.selectAll('.preset-input-cycleway')
38509 .on('change', change)
38510 .on('blur', change);
38513 function change() {
38514 var inputs = d3.selectAll('.preset-input-cycleway')[0],
38515 left = d3.select(inputs[0]).value(),
38516 right = d3.select(inputs[1]).value(),
38518 if (left === 'none' || left === '') { left = undefined; }
38519 if (right === 'none' || right === '') { right = undefined; }
38521 // Always set both left and right as changing one can affect the other
38523 cycleway: undefined,
38524 'cycleway:left': left,
38525 'cycleway:right': right
38528 // If the left and right tags match, use the cycleway tag to tag both
38529 // sides the same way
38530 if (left === right) {
38533 'cycleway:left': undefined,
38534 'cycleway:right': undefined
38538 dispatch.change(tag);
38541 cycleway.options = function() {
38542 return d3.keys(field.strings.options).map(function(option) {
38544 title: field.t('options.' + option + '.description'),
38550 cycleway.tags = function(tags) {
38551 items.selectAll('.preset-input-cycleway')
38552 .value(function(d) {
38553 // If cycleway is set, always return that
38554 if (tags.cycleway) {
38555 return tags.cycleway;
38557 return tags[d] || '';
38559 .attr('placeholder', field.placeholder());
38562 cycleway.focus = function() {
38563 items.selectAll('.preset-input-cycleway')
38567 return d3.rebind(cycleway, dispatch, 'on');
38569 iD.ui.preset.text =
38570 iD.ui.preset.number =
38572 iD.ui.preset.email =
38573 iD.ui.preset.url = function(field) {
38575 var dispatch = d3.dispatch('change'),
38578 function i(selection) {
38579 input = selection.selectAll('input')
38582 input.enter().append('input')
38583 .attr('type', field.type)
38584 .attr('id', 'preset-input-' + field.id)
38585 .attr('placeholder', field.placeholder() || t('inspector.unknown'));
38588 .on('input', change(true))
38589 .on('blur', change())
38590 .on('change', change());
38592 if (field.type === 'number') {
38593 input.attr('type', 'text');
38595 var spinControl = selection.selectAll('.spin-control')
38598 var enter = spinControl.enter().append('div')
38599 .attr('class', 'spin-control');
38601 enter.append('button')
38603 .attr('class', 'increment');
38605 enter.append('button')
38607 .attr('class', 'decrement');
38609 spinControl.selectAll('button')
38610 .on('click', function(d) {
38611 d3.event.preventDefault();
38612 var num = parseInt(input.node().value || 0, 10);
38613 if (!isNaN(num)) input.node().value = num + d;
38619 function change(onInput) {
38620 return function() {
38622 t[field.key] = input.value() || undefined;
38623 dispatch.change(t, onInput);
38627 i.tags = function(tags) {
38628 input.value(tags[field.key] || '');
38631 i.focus = function() {
38632 input.node().focus();
38635 return d3.rebind(i, dispatch, 'on');
38637 iD.ui.preset.localized = function(field, context) {
38638 var dispatch = d3.dispatch('change', 'input'),
38639 wikipedia = iD.services.wikipedia(),
38640 input, localizedInputs, wikiTitles,
38643 function i(selection) {
38644 input = selection.selectAll('.localized-main')
38647 input.enter().append('input')
38648 .attr('type', 'text')
38649 .attr('id', 'preset-input-' + field.id)
38650 .attr('class', 'localized-main')
38651 .attr('placeholder', field.placeholder());
38653 if (field.id === 'name') {
38654 var preset = context.presets().match(entity, context.graph());
38655 input.call(d3.combobox().fetcher(
38656 iD.util.SuggestNames(preset, iD.data.suggestions)
38661 .on('input', change(true))
38662 .on('blur', change())
38663 .on('change', change());
38665 var translateButton = selection.selectAll('.localized-add')
38668 translateButton.enter()
38670 .attr('class', 'button-input-action localized-add minor')
38671 .call(iD.svg.Icon('#icon-plus'))
38672 .call(bootstrap.tooltip()
38673 .title(t('translate.translate'))
38674 .placement('left'));
38677 .on('click', addNew);
38679 localizedInputs = selection.selectAll('.localized-wrap')
38682 localizedInputs.enter().append('div')
38683 .attr('class', 'localized-wrap');
38686 function addNew() {
38687 d3.event.preventDefault();
38688 var data = localizedInputs.selectAll('div.entry').data();
38689 var defaultLang = iD.detect().locale.toLowerCase().split('-')[0];
38690 var langExists = _.find(data, function(datum) { return datum.lang === defaultLang;});
38691 var isLangEn = defaultLang.indexOf('en') > -1;
38692 if (isLangEn || langExists) {
38695 data.push({ lang: defaultLang, value: '' });
38696 localizedInputs.call(render, data);
38699 function change(onInput) {
38700 return function() {
38702 t[field.key] = d3.select(this).value() || undefined;
38703 dispatch.change(t, onInput);
38707 function key(lang) { return field.key + ':' + lang; }
38709 function changeLang(d) {
38710 var lang = d3.select(this).value(),
38712 language = _.find(iD.data.wikipedia, function(d) {
38713 return d[0].toLowerCase() === lang.toLowerCase() ||
38714 d[1].toLowerCase() === lang.toLowerCase();
38717 if (language) lang = language[2];
38719 if (d.lang && d.lang !== lang) {
38720 t[key(d.lang)] = undefined;
38723 var value = d3.select(this.parentNode)
38724 .selectAll('.localized-value')
38727 if (lang && value) {
38728 t[key(lang)] = value;
38729 } else if (lang && wikiTitles && wikiTitles[d.lang]) {
38730 t[key(lang)] = wikiTitles[d.lang];
38734 dispatch.change(t);
38737 function changeValue(d) {
38738 if (!d.lang) return;
38740 t[key(d.lang)] = d3.select(this).value() || undefined;
38741 dispatch.change(t);
38744 function fetcher(value, cb) {
38745 var v = value.toLowerCase();
38747 cb(iD.data.wikipedia.filter(function(d) {
38748 return d[0].toLowerCase().indexOf(v) >= 0 ||
38749 d[1].toLowerCase().indexOf(v) >= 0 ||
38750 d[2].toLowerCase().indexOf(v) >= 0;
38751 }).map(function(d) {
38752 return { value: d[1] };
38756 function render(selection, data) {
38757 var wraps = selection.selectAll('div.entry').
38758 data(data, function(d) { return d.lang; });
38760 var innerWrap = wraps.enter()
38761 .insert('div', ':first-child');
38763 innerWrap.attr('class', 'entry')
38765 var wrap = d3.select(this);
38766 var langcombo = d3.combobox().fetcher(fetcher);
38768 var label = wrap.append('label')
38769 .attr('class','form-label')
38770 .text(t('translate.localized_translation_label'))
38771 .attr('for','localized-lang');
38773 label.append('button')
38774 .attr('class', 'minor remove')
38775 .on('click', function(d){
38776 d3.event.preventDefault();
38778 t[key(d.lang)] = undefined;
38779 dispatch.change(t);
38780 d3.select(this.parentNode.parentNode)
38782 .style('max-height','240px')
38784 .style('opacity', '0')
38785 .style('max-height','0px')
38788 .call(iD.svg.Icon('#operation-delete'));
38790 wrap.append('input')
38791 .attr('class', 'localized-lang')
38792 .attr('type', 'text')
38793 .attr('placeholder',t('translate.localized_translation_language'))
38794 .on('blur', changeLang)
38795 .on('change', changeLang)
38798 wrap.append('input')
38799 .on('blur', changeValue)
38800 .on('change', changeValue)
38801 .attr('type', 'text')
38802 .attr('placeholder', t('translate.localized_translation_name'))
38803 .attr('class', 'localized-value');
38807 .style('margin-top', '0px')
38808 .style('max-height', '0px')
38809 .style('opacity', '0')
38812 .style('margin-top', '10px')
38813 .style('max-height', '240px')
38814 .style('opacity', '1')
38815 .each('end', function() {
38817 .style('max-height', '')
38818 .style('overflow', 'visible');
38824 .style('max-height','0px')
38825 .style('opacity', '0')
38826 .style('top','-10px')
38829 var entry = selection.selectAll('.entry');
38831 entry.select('.localized-lang')
38832 .value(function(d) {
38833 var lang = _.find(iD.data.wikipedia, function(lang) { return lang[2] === d.lang; });
38834 return lang ? lang[1] : d.lang;
38837 entry.select('.localized-value')
38838 .value(function(d) { return d.value; });
38841 i.tags = function(tags) {
38842 // Fetch translations from wikipedia
38843 if (tags.wikipedia && !wikiTitles) {
38845 var wm = tags.wikipedia.match(/([^:]+):(.+)/);
38846 if (wm && wm[0] && wm[1]) {
38847 wikipedia.translations(wm[1], wm[2], function(d) {
38853 input.value(tags[field.key] || '');
38855 var postfixed = [], k, m;
38857 m = k.match(/^(.*):([a-zA-Z_-]+)$/);
38858 if (m && m[1] === field.key && m[2]) {
38859 postfixed.push({ lang: m[2], value: tags[k] });
38863 localizedInputs.call(render, postfixed.reverse());
38866 i.focus = function() {
38867 input.node().focus();
38870 i.entity = function(_) {
38874 return d3.rebind(i, dispatch, 'on');
38876 iD.ui.preset.maxspeed = function(field, context) {
38877 var dispatch = d3.dispatch('change'),
38884 var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
38885 imperialValues = [20, 25, 30, 35, 40, 45, 50, 55, 65, 70];
38887 function maxspeed(selection) {
38888 combobox = d3.combobox();
38889 var unitCombobox = d3.combobox().data(['km/h', 'mph'].map(comboValues));
38891 input = selection.selectAll('#preset-input-' + field.id)
38894 input.enter().append('input')
38895 .attr('type', 'text')
38896 .attr('id', 'preset-input-' + field.id)
38897 .attr('placeholder', field.placeholder());
38901 .on('change', change)
38902 .on('blur', change);
38904 var childNodes = context.graph().childNodes(context.entity(entity.id)),
38905 loc = childNodes[~~(childNodes.length/2)].loc;
38907 imperial = _.any(iD.data.imperial.features, function(f) {
38908 return _.any(f.geometry.coordinates, function(d) {
38909 return iD.geo.pointInPolygon(loc, d[0]);
38913 unitInput = selection.selectAll('input.maxspeed-unit')
38916 unitInput.enter().append('input')
38917 .attr('type', 'text')
38918 .attr('class', 'maxspeed-unit');
38921 .on('blur', changeUnits)
38922 .on('change', changeUnits)
38923 .call(unitCombobox);
38925 function changeUnits() {
38926 imperial = unitInput.value() === 'mph';
38927 unitInput.value(imperial ? 'mph' : 'km/h');
38934 function setSuggestions() {
38935 combobox.data((imperial ? imperialValues : metricValues).map(comboValues));
38936 unitInput.value(imperial ? 'mph' : 'km/h');
38939 function comboValues(d) {
38941 value: d.toString(),
38942 title: d.toString()
38946 function change() {
38948 value = input.value();
38951 tag[field.key] = undefined;
38952 } else if (isNaN(value) || !imperial) {
38953 tag[field.key] = value;
38955 tag[field.key] = value + ' mph';
38958 dispatch.change(tag);
38961 maxspeed.tags = function(tags) {
38962 var value = tags[field.key];
38964 if (value && value.indexOf('mph') >= 0) {
38965 value = parseInt(value, 10);
38967 } else if (value) {
38973 input.value(value || '');
38976 maxspeed.focus = function() {
38977 input.node().focus();
38980 maxspeed.entity = function(_) {
38984 return d3.rebind(maxspeed, dispatch, 'on');
38986 iD.ui.preset.radio = function(field) {
38987 var dispatch = d3.dispatch('change'),
38988 labels, radios, placeholder;
38990 function radio(selection) {
38991 selection.classed('preset-radio', true);
38993 var wrap = selection.selectAll('.preset-input-wrap')
38996 var buttonWrap = wrap.enter().append('div')
38997 .attr('class', 'preset-input-wrap toggle-list');
38999 buttonWrap.append('span')
39000 .attr('class', 'placeholder');
39002 placeholder = selection.selectAll('.placeholder');
39004 labels = wrap.selectAll('label')
39005 .data(field.options || field.keys);
39007 var enter = labels.enter().append('label');
39009 enter.append('input')
39010 .attr('type', 'radio')
39011 .attr('name', field.id)
39012 .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
39013 .attr('checked', false);
39015 enter.append('span')
39016 .text(function(d) { return field.t('options.' + d, { 'default': d }); });
39018 radios = labels.selectAll('input')
39019 .on('change', change);
39022 function change() {
39024 if (field.key) t[field.key] = undefined;
39025 radios.each(function(d) {
39026 var active = d3.select(this).property('checked');
39028 if (active) t[field.key] = d;
39030 t[d] = active ? 'yes' : undefined;
39033 dispatch.change(t);
39036 radio.tags = function(tags) {
39037 function checked(d) {
39039 return tags[field.key] === d;
39041 return !!(tags[d] && tags[d] !== 'no');
39045 labels.classed('active', checked);
39046 radios.property('checked', checked);
39047 var selection = radios.filter(function() { return this.checked; });
39048 if (selection.empty()) {
39049 placeholder.text(t('inspector.none'));
39051 placeholder.text(selection.attr('value'));
39055 radio.focus = function() {
39056 radios.node().focus();
39059 return d3.rebind(radio, dispatch, 'on');
39061 iD.ui.preset.restrictions = function(field, context) {
39062 var dispatch = d3.dispatch('change'),
39063 hover = iD.behavior.Hover(context),
39068 function restrictions(selection) {
39069 // if form field is hidden or has detached from dom, clean up.
39070 if (!d3.select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
39071 selection.call(restrictions.off);
39075 var wrap = selection.selectAll('.preset-input-wrap')
39078 var enter = wrap.enter()
39080 .attr('class', 'preset-input-wrap');
39084 .attr('class', 'restriction-help');
39087 var intersection = iD.geo.Intersection(context.graph(), vertexID),
39088 graph = intersection.graph,
39089 vertex = graph.entity(vertexID),
39090 filter = d3.functor(true),
39091 extent = iD.geo.Extent(),
39092 projection = iD.geo.RawMercator();
39094 var d = wrap.dimensions(),
39095 c = [d[0] / 2, d[1] / 2],
39099 .scale(256 * Math.pow(2, z) / (2 * Math.PI));
39101 var s = projection(vertex.loc);
39104 .translate([c[0] - s[0], c[1] - s[1]])
39105 .clipExtent([[0, 0], d]);
39107 var drawLayers = iD.svg.Layers(projection, context).only('osm').dimensions(d),
39108 drawVertices = iD.svg.Vertices(projection, context),
39109 drawLines = iD.svg.Lines(projection, context),
39110 drawTurns = iD.svg.Turns(projection, context);
39114 .selectAll('.surface')
39118 var surface = wrap.selectAll('.surface');
39122 .call(drawVertices, graph, [vertex], filter, extent, z)
39123 .call(drawLines, graph, intersection.ways, filter)
39124 .call(drawTurns, graph, intersection.turns(fromNodeID));
39127 .on('click.restrictions', click)
39128 .on('mouseover.restrictions', mouseover)
39129 .on('mouseout.restrictions', mouseout);
39132 .selectAll('.selected')
39133 .classed('selected', false);
39137 .selectAll('.' + intersection.highways[fromNodeID].id)
39138 .classed('selected', true);
39144 .on('change.restrictions', render);
39147 .on('resize.restrictions', function() {
39148 wrap.dimensions(null);
39153 var datum = d3.event.target.__data__;
39154 if (datum instanceof iD.Entity) {
39155 fromNodeID = intersection.adjacentNodeId(datum.id);
39157 } else if (datum instanceof iD.geo.Turn) {
39158 if (datum.restriction) {
39160 iD.actions.UnrestrictTurn(datum, projection),
39161 t('operations.restriction.annotation.delete'));
39164 iD.actions.RestrictTurn(datum, projection),
39165 t('operations.restriction.annotation.create'));
39170 function mouseover() {
39171 var datum = d3.event.target.__data__;
39172 if (datum instanceof iD.geo.Turn) {
39173 var graph = context.graph(),
39174 presets = context.presets(),
39177 if (datum.restriction) {
39178 preset = presets.match(graph.entity(datum.restriction), graph);
39180 preset = presets.item('type/restriction/' +
39181 iD.geo.inferRestriction(
39189 wrap.selectAll('.restriction-help')
39190 .text(t('operations.restriction.help.' +
39191 (datum.restriction ? 'toggle_off' : 'toggle_on'),
39192 {restriction: preset.name()}));
39196 function mouseout() {
39197 wrap.selectAll('.restriction-help')
39198 .text(t('operations.restriction.help.' +
39199 (fromNodeID ? 'toggle' : 'select')));
39202 function render() {
39203 if (context.hasEntity(vertexID)) {
39204 restrictions(selection);
39209 restrictions.entity = function(_) {
39210 if (!vertexID || vertexID !== _.id) {
39216 restrictions.tags = function() {};
39217 restrictions.focus = function() {};
39219 restrictions.off = function(selection) {
39220 selection.selectAll('.surface')
39222 .on('click.restrictions', null)
39223 .on('mouseover.restrictions', null)
39224 .on('mouseout.restrictions', null);
39227 .on('change.restrictions', null);
39230 .on('resize.restrictions', null);
39233 return d3.rebind(restrictions, dispatch, 'on');
39235 iD.ui.preset.textarea = function(field) {
39236 var dispatch = d3.dispatch('change'),
39239 function i(selection) {
39240 input = selection.selectAll('textarea')
39243 input.enter().append('textarea')
39244 .attr('id', 'preset-input-' + field.id)
39245 .attr('placeholder', field.placeholder() || t('inspector.unknown'))
39246 .attr('maxlength', 255);
39249 .on('input', change(true))
39250 .on('blur', change())
39251 .on('change', change());
39254 function change(onInput) {
39255 return function() {
39257 t[field.key] = input.value() || undefined;
39258 dispatch.change(t, onInput);
39262 i.tags = function(tags) {
39263 input.value(tags[field.key] || '');
39266 i.focus = function() {
39267 input.node().focus();
39270 return d3.rebind(i, dispatch, 'on');
39272 iD.ui.preset.wikipedia = function(field, context) {
39273 var dispatch = d3.dispatch('change'),
39274 wikipedia = iD.services.wikipedia(),
39275 link, entity, lang, title;
39277 function i(selection) {
39278 var langcombo = d3.combobox()
39279 .fetcher(function(value, cb) {
39280 var v = value.toLowerCase();
39282 cb(iD.data.wikipedia.filter(function(d) {
39283 return d[0].toLowerCase().indexOf(v) >= 0 ||
39284 d[1].toLowerCase().indexOf(v) >= 0 ||
39285 d[2].toLowerCase().indexOf(v) >= 0;
39286 }).map(function(d) {
39287 return { value: d[1] };
39291 var titlecombo = d3.combobox()
39292 .fetcher(function(value, cb) {
39294 if (!value) value = context.entity(entity.id).tags.name || '';
39295 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
39297 searchfn(language()[2], value, function(query, data) {
39298 cb(data.map(function(d) {
39299 return { value: d };
39304 lang = selection.selectAll('input.wiki-lang')
39307 lang.enter().append('input')
39308 .attr('type', 'text')
39309 .attr('class', 'wiki-lang')
39314 .on('blur', changeLang)
39315 .on('change', changeLang);
39317 title = selection.selectAll('input.wiki-title')
39320 title.enter().append('input')
39321 .attr('type', 'text')
39322 .attr('class', 'wiki-title')
39323 .attr('id', 'preset-input-' + field.id);
39327 .on('blur', change)
39328 .on('change', change);
39330 link = selection.selectAll('a.wiki-link')
39333 link.enter().append('a')
39334 .attr('class', 'wiki-link button-input-action minor')
39335 .attr('target', '_blank')
39336 .call(iD.svg.Icon('#icon-out-link', 'inline'));
39339 function language() {
39340 var value = lang.value().toLowerCase();
39341 var locale = iD.detect().locale.toLowerCase();
39342 var localeLanguage;
39343 return _.find(iD.data.wikipedia, function(d) {
39344 if (d[2] === locale) localeLanguage = d;
39345 return d[0].toLowerCase() === value ||
39346 d[1].toLowerCase() === value ||
39348 }) || localeLanguage || ['English', 'English', 'en'];
39351 function changeLang() {
39352 lang.value(language()[1]);
39356 function change() {
39357 var value = title.value(),
39358 m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
39359 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
39363 // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
39364 value = decodeURIComponent(m[2]).replace(/_/g, ' ');
39367 // Best-effort `anchordecode:` implementation
39368 anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
39370 anchor = decodeURIComponent(m[3]);
39372 value += '#' + anchor.replace(/_/g, ' ');
39374 value = value.slice(0, 1).toUpperCase() + value.slice(1);
39376 title.value(value);
39380 t[field.key] = value ? language()[2] + ':' + value : undefined;
39381 dispatch.change(t);
39384 i.tags = function(tags) {
39385 var value = tags[field.key] || '',
39386 m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
39387 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
39388 anchor = m && m[3];
39390 // value in correct format
39393 title.value(m[2] + (anchor ? ('#' + anchor) : ''));
39396 // Best-effort `anchorencode:` implementation
39397 anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
39399 anchor = anchor.replace(/ /g, '_');
39402 link.attr('href', 'https://' + m[1] + '.wikipedia.org/wiki/' +
39403 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : ''));
39405 // unrecognized value format
39407 title.value(value);
39408 link.attr('href', 'https://en.wikipedia.org/wiki/Special:Search?search=' + value);
39412 i.entity = function(_) {
39416 i.focus = function() {
39417 title.node().focus();
39420 return d3.rebind(i, dispatch, 'on');
39422 iD.ui.intro.area = function(context, reveal) {
39423 var event = d3.dispatch('done'),
39427 title: 'intro.areas.title'
39430 step.enter = function() {
39431 var playground = [-85.63552, 41.94159],
39432 corner = [-85.63565411045074, 41.9417715536927];
39433 context.map().centerZoom(playground, 19);
39434 reveal('button.add-area',
39435 t('intro.areas.add', { button: iD.ui.intro.icon('#icon-area', 'pre-text') }),
39436 { tooltipClass: 'intro-areas-add' });
39438 context.on('enter.intro', addArea);
39440 function addArea(mode) {
39441 if (mode.id !== 'add-area') return;
39442 context.on('enter.intro', drawArea);
39444 var padding = 120 * Math.pow(2, context.map().zoom() - 19);
39445 var pointBox = iD.ui.intro.pad(corner, padding, context);
39446 reveal(pointBox, t('intro.areas.corner'));
39448 context.map().on('move.intro', function() {
39449 padding = 120 * Math.pow(2, context.map().zoom() - 19);
39450 pointBox = iD.ui.intro.pad(corner, padding, context);
39451 reveal(pointBox, t('intro.areas.corner'), {duration: 0});
39455 function drawArea(mode) {
39456 if (mode.id !== 'draw-area') return;
39457 context.on('enter.intro', enterSelect);
39459 var padding = 150 * Math.pow(2, context.map().zoom() - 19);
39460 var pointBox = iD.ui.intro.pad(playground, padding, context);
39461 reveal(pointBox, t('intro.areas.place'));
39463 context.map().on('move.intro', function() {
39464 padding = 150 * Math.pow(2, context.map().zoom() - 19);
39465 pointBox = iD.ui.intro.pad(playground, padding, context);
39466 reveal(pointBox, t('intro.areas.place'), {duration: 0});
39470 function enterSelect(mode) {
39471 if (mode.id !== 'select') return;
39472 context.map().on('move.intro', null);
39473 context.on('enter.intro', null);
39475 timeout = setTimeout(function() {
39476 reveal('.preset-search-input',
39477 t('intro.areas.search',
39478 { name: context.presets().item('leisure/playground').name() }));
39479 d3.select('.preset-search-input').on('keyup.intro', keySearch);
39483 function keySearch() {
39484 var first = d3.select('.preset-list-item:first-child');
39485 if (first.classed('preset-leisure-playground')) {
39486 reveal(first.select('.preset-list-button').node(), t('intro.areas.choose'));
39487 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
39488 d3.select('.preset-search-input').on('keyup.intro', null);
39492 function selectedPreset() {
39494 t('intro.areas.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39495 context.on('exit.intro', event.done);
39499 step.exit = function() {
39500 window.clearTimeout(timeout);
39501 context.on('enter.intro', null);
39502 context.on('exit.intro', null);
39503 context.history().on('change.intro', null);
39504 context.map().on('move.intro', null);
39505 d3.select('.preset-search-input').on('keyup.intro', null);
39508 return d3.rebind(step, event, 'on');
39510 iD.ui.intro.line = function(context, reveal) {
39511 var event = d3.dispatch('done'),
39515 title: 'intro.lines.title'
39518 function timeout(f, t) {
39519 timeouts.push(window.setTimeout(f, t));
39522 function eventCancel() {
39523 d3.event.stopPropagation();
39524 d3.event.preventDefault();
39527 step.enter = function() {
39528 var centroid = [-85.62830, 41.95699];
39529 var midpoint = [-85.62975395449628, 41.95787501510204];
39530 var start = [-85.6297754121684, 41.95805253325314];
39531 var intersection = [-85.62974496187628, 41.95742515554585];
39533 context.map().centerZoom(start, 18);
39534 reveal('button.add-line',
39535 t('intro.lines.add', { button: iD.ui.intro.icon('#icon-line', 'pre-text') }),
39536 { tooltipClass: 'intro-lines-add' });
39538 context.on('enter.intro', addLine);
39540 function addLine(mode) {
39541 if (mode.id !== 'add-line') return;
39542 context.on('enter.intro', drawLine);
39544 var padding = 150 * Math.pow(2, context.map().zoom() - 18);
39545 var pointBox = iD.ui.intro.pad(start, padding, context);
39546 reveal(pointBox, t('intro.lines.start'));
39548 context.map().on('move.intro', function() {
39549 padding = 150 * Math.pow(2, context.map().zoom() - 18);
39550 pointBox = iD.ui.intro.pad(start, padding, context);
39551 reveal(pointBox, t('intro.lines.start'), {duration: 0});
39555 function drawLine(mode) {
39556 if (mode.id !== 'draw-line') return;
39557 context.history().on('change.intro', addIntersection);
39558 context.on('enter.intro', retry);
39560 var padding = 300 * Math.pow(2, context.map().zoom() - 19);
39561 var pointBox = iD.ui.intro.pad(midpoint, padding, context);
39562 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}));
39564 context.map().on('move.intro', function() {
39565 padding = 300 * Math.pow(2, context.map().zoom() - 19);
39566 pointBox = iD.ui.intro.pad(midpoint, padding, context);
39567 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}), {duration: 0});
39571 // ended line before creating intersection
39572 function retry(mode) {
39573 if (mode.id !== 'select') return;
39574 var pointBox = iD.ui.intro.pad(intersection, 30, context),
39575 ids = mode.selectedIDs();
39576 reveal(pointBox, t('intro.lines.restart', {name: t('intro.graph.flower_st')}));
39577 d3.select(window).on('mousedown.intro', eventCancel, true);
39579 timeout(function() {
39580 context.replace(iD.actions.DeleteMultiple(ids));
39586 function addIntersection(changes) {
39587 if ( _.any(changes.created(), function(d) {
39588 return d.type === 'node' && context.graph().parentWays(d).length > 1;
39590 context.history().on('change.intro', null);
39591 context.on('enter.intro', enterSelect);
39593 var padding = 900 * Math.pow(2, context.map().zoom() - 19);
39594 var pointBox = iD.ui.intro.pad(centroid, padding, context);
39595 reveal(pointBox, t('intro.lines.finish'));
39597 context.map().on('move.intro', function() {
39598 padding = 900 * Math.pow(2, context.map().zoom() - 19);
39599 pointBox = iD.ui.intro.pad(centroid, padding, context);
39600 reveal(pointBox, t('intro.lines.finish'), {duration: 0});
39605 function enterSelect(mode) {
39606 if (mode.id !== 'select') return;
39607 context.map().on('move.intro', null);
39608 context.on('enter.intro', null);
39609 d3.select('#curtain').style('pointer-events', 'all');
39614 function presetCategory() {
39615 timeout(function() {
39616 d3.select('#curtain').style('pointer-events', 'none');
39617 var road = d3.select('.preset-category-road .preset-list-button');
39618 reveal(road.node(), t('intro.lines.road'));
39619 road.one('click.intro', roadCategory);
39623 function roadCategory() {
39624 timeout(function() {
39625 var grid = d3.select('.subgrid');
39626 reveal(grid.node(), t('intro.lines.residential'));
39627 grid.selectAll(':not(.preset-highway-residential) .preset-list-button')
39628 .one('click.intro', retryPreset);
39629 grid.selectAll('.preset-highway-residential .preset-list-button')
39630 .one('click.intro', roadDetails);
39634 // selected wrong road type
39635 function retryPreset() {
39636 timeout(function() {
39637 var preset = d3.select('.entity-editor-pane .preset-list-button');
39638 reveal(preset.node(), t('intro.lines.wrong_preset'));
39639 preset.one('click.intro', presetCategory);
39643 function roadDetails() {
39645 t('intro.lines.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39646 context.on('exit.intro', event.done);
39651 step.exit = function() {
39652 d3.select(window).on('mousedown.intro', null, true);
39653 d3.select('#curtain').style('pointer-events', 'none');
39654 timeouts.forEach(window.clearTimeout);
39655 context.on('enter.intro', null);
39656 context.on('exit.intro', null);
39657 context.map().on('move.intro', null);
39658 context.history().on('change.intro', null);
39661 return d3.rebind(step, event, 'on');
39663 iD.ui.intro.navigation = function(context, reveal) {
39664 var event = d3.dispatch('done'),
39668 title: 'intro.navigation.title'
39671 function set(f, t) {
39672 timeouts.push(window.setTimeout(f, t));
39675 function eventCancel() {
39676 d3.event.stopPropagation();
39677 d3.event.preventDefault();
39680 step.enter = function() {
39681 var rect = context.surfaceRect(),
39683 left: rect.left + 10,
39684 top: rect.top + 70,
39685 width: rect.width - 70,
39686 height: rect.height - 170
39689 context.map().centerZoom([-85.63591, 41.94285], 19);
39691 reveal(map, t('intro.navigation.drag'));
39693 context.map().on('move.intro', _.debounce(function() {
39694 context.map().on('move.intro', null);
39696 context.on('enter.intro', inspectTownHall);
39699 function townhall() {
39700 var hall = [-85.63645945147184, 41.942986488012565];
39702 var point = context.projection(hall);
39703 if (point[0] < 0 || point[0] > rect.width ||
39704 point[1] < 0 || point[1] > rect.height) {
39705 context.map().center(hall);
39708 var box = iD.ui.intro.pointBox(hall, context);
39709 reveal(box, t('intro.navigation.select'));
39711 context.map().on('move.intro', function() {
39712 var box = iD.ui.intro.pointBox(hall, context);
39713 reveal(box, t('intro.navigation.select'), {duration: 0});
39717 function inspectTownHall(mode) {
39718 if (mode.id !== 'select') return;
39719 context.on('enter.intro', null);
39720 context.map().on('move.intro', null);
39722 reveal('.entity-editor-pane',
39723 t('intro.navigation.pane', { button: iD.ui.intro.icon('#icon-close', 'pre-text') }));
39724 context.on('exit.intro', streetSearch);
39728 function streetSearch() {
39729 context.on('exit.intro', null);
39730 reveal('.search-header input',
39731 t('intro.navigation.search', { name: t('intro.graph.spring_st') }));
39732 d3.select('.search-header input').on('keyup.intro', searchResult);
39735 function searchResult() {
39736 var first = d3.select('.feature-list-item:nth-child(0n+2)'), // skip No Results item
39737 firstName = first.select('.entity-name'),
39738 name = t('intro.graph.spring_st');
39740 if (!firstName.empty() && firstName.text() === name) {
39741 reveal(first.node(), t('intro.navigation.choose', { name: name }));
39742 context.on('exit.intro', selectedStreet);
39743 d3.select('.search-header input')
39744 .on('keydown.intro', eventCancel, true)
39745 .on('keyup.intro', null);
39749 function selectedStreet() {
39750 var springSt = [-85.63585099140167, 41.942506848938926];
39751 context.map().center(springSt);
39752 context.on('exit.intro', event.done);
39754 reveal('.entity-editor-pane',
39755 t('intro.navigation.chosen', {
39756 name: t('intro.graph.spring_st'),
39757 button: iD.ui.intro.icon('#icon-close', 'pre-text')
39763 step.exit = function() {
39764 timeouts.forEach(window.clearTimeout);
39765 context.map().on('move.intro', null);
39766 context.on('enter.intro', null);
39767 context.on('exit.intro', null);
39768 d3.select('.search-header input')
39769 .on('keydown.intro', null)
39770 .on('keyup.intro', null);
39773 return d3.rebind(step, event, 'on');
39775 iD.ui.intro.point = function(context, reveal) {
39776 var event = d3.dispatch('done'),
39780 title: 'intro.points.title'
39783 function setTimeout(f, t) {
39784 timeouts.push(window.setTimeout(f, t));
39787 function eventCancel() {
39788 d3.event.stopPropagation();
39789 d3.event.preventDefault();
39792 step.enter = function() {
39793 context.map().centerZoom([-85.63279, 41.94394], 19);
39794 reveal('button.add-point',
39795 t('intro.points.add', { button: iD.ui.intro.icon('#icon-point', 'pre-text') }),
39796 { tooltipClass: 'intro-points-add' });
39798 var corner = [-85.632481,41.944094];
39800 context.on('enter.intro', addPoint);
39802 function addPoint(mode) {
39803 if (mode.id !== 'add-point') return;
39804 context.on('enter.intro', enterSelect);
39806 var pointBox = iD.ui.intro.pad(corner, 150, context);
39807 reveal(pointBox, t('intro.points.place'));
39809 context.map().on('move.intro', function() {
39810 pointBox = iD.ui.intro.pad(corner, 150, context);
39811 reveal(pointBox, t('intro.points.place'), {duration: 0});
39815 function enterSelect(mode) {
39816 if (mode.id !== 'select') return;
39817 context.map().on('move.intro', null);
39818 context.on('enter.intro', null);
39820 setTimeout(function() {
39821 reveal('.preset-search-input',
39822 t('intro.points.search', {name: context.presets().item('amenity/cafe').name()}));
39823 d3.select('.preset-search-input').on('keyup.intro', keySearch);
39827 function keySearch() {
39828 var first = d3.select('.preset-list-item:first-child');
39829 if (first.classed('preset-amenity-cafe')) {
39830 reveal(first.select('.preset-list-button').node(), t('intro.points.choose'));
39831 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
39832 d3.select('.preset-search-input')
39833 .on('keydown.intro', eventCancel, true)
39834 .on('keyup.intro', null);
39838 function selectedPreset() {
39839 setTimeout(function() {
39840 reveal('.entity-editor-pane', t('intro.points.describe'), {tooltipClass: 'intro-points-describe'});
39841 context.history().on('change.intro', closeEditor);
39842 context.on('exit.intro', selectPoint);
39846 function closeEditor() {
39847 d3.select('.preset-search-input').on('keydown.intro', null);
39848 context.history().on('change.intro', null);
39849 reveal('.entity-editor-pane',
39850 t('intro.points.close', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39853 function selectPoint() {
39854 context.on('exit.intro', null);
39855 context.history().on('change.intro', null);
39856 context.on('enter.intro', enterReselect);
39858 var pointBox = iD.ui.intro.pad(corner, 150, context);
39859 reveal(pointBox, t('intro.points.reselect'));
39861 context.map().on('move.intro', function() {
39862 pointBox = iD.ui.intro.pad(corner, 150, context);
39863 reveal(pointBox, t('intro.points.reselect'), {duration: 0});
39867 function enterReselect(mode) {
39868 if (mode.id !== 'select') return;
39869 context.map().on('move.intro', null);
39870 context.on('enter.intro', null);
39872 setTimeout(function() {
39873 reveal('.entity-editor-pane',
39874 t('intro.points.fixname', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39875 context.on('exit.intro', deletePoint);
39879 function deletePoint() {
39880 context.on('exit.intro', null);
39881 context.on('enter.intro', enterDelete);
39883 var pointBox = iD.ui.intro.pad(corner, 150, context);
39884 reveal(pointBox, t('intro.points.reselect_delete'));
39886 context.map().on('move.intro', function() {
39887 pointBox = iD.ui.intro.pad(corner, 150, context);
39888 reveal(pointBox, t('intro.points.reselect_delete'), {duration: 0});
39892 function enterDelete(mode) {
39893 if (mode.id !== 'select') return;
39894 context.map().on('move.intro', null);
39895 context.on('enter.intro', null);
39896 context.on('exit.intro', deletePoint);
39897 context.map().on('move.intro', deletePoint);
39898 context.history().on('change.intro', deleted);
39900 setTimeout(function() {
39901 var node = d3.select('.radial-menu-item-delete').node();
39902 var pointBox = iD.ui.intro.pad(node.getBoundingClientRect(), 50, context);
39904 t('intro.points.delete', { button: iD.ui.intro.icon('#operation-delete', 'pre-text') }));
39908 function deleted(changed) {
39909 if (changed.deleted().length) event.done();
39914 step.exit = function() {
39915 timeouts.forEach(window.clearTimeout);
39916 context.on('exit.intro', null);
39917 context.on('enter.intro', null);
39918 context.map().on('move.intro', null);
39919 context.history().on('change.intro', null);
39920 d3.select('.preset-search-input')
39921 .on('keyup.intro', null)
39922 .on('keydown.intro', null);
39925 return d3.rebind(step, event, 'on');
39927 iD.ui.intro.startEditing = function(context, reveal) {
39928 var event = d3.dispatch('done', 'startEditing'),
39933 title: 'intro.startediting.title'
39936 function timeout(f, t) {
39937 timeouts.push(window.setTimeout(f, t));
39940 step.enter = function() {
39941 reveal('.map-control.help-control',
39942 t('intro.startediting.help', { button: iD.ui.intro.icon('#icon-help', 'pre-text') }));
39944 timeout(function() {
39945 reveal('#bar button.save', t('intro.startediting.save'));
39948 timeout(function() {
39949 reveal('#surface');
39952 timeout(function() {
39953 modal = iD.ui.modal(context.container());
39955 modal.select('.modal')
39956 .attr('class', 'modal-splash modal col6');
39958 modal.selectAll('.close').remove();
39960 var startbutton = modal.select('.content')
39961 .attr('class', 'fillL')
39963 .attr('class', 'modal-section huge-modal-button')
39964 .on('click', function() {
39968 startbutton.append('div')
39969 .attr('class','illustration');
39970 startbutton.append('h2')
39971 .text(t('intro.startediting.start'));
39973 event.startEditing();
39977 step.exit = function() {
39978 if (modal) modal.remove();
39979 timeouts.forEach(window.clearTimeout);
39982 return d3.rebind(step, event, 'on');
39984 iD.presets = function() {
39986 // an iD.presets.Collection with methods for
39987 // loading new data and returning defaults
39989 var all = iD.presets.Collection([]),
39990 defaults = { area: all, line: all, point: all, vertex: all, relation: all },
39993 recent = iD.presets.Collection([]);
39995 // Index of presets by (geometry, tag key).
40004 all.match = function(entity, resolver) {
40005 var geometry = entity.geometry(resolver),
40006 geometryMatches = index[geometry],
40010 for (var k in entity.tags) {
40011 var keyMatches = geometryMatches[k];
40012 if (!keyMatches) continue;
40014 for (var i = 0; i < keyMatches.length; i++) {
40015 var score = keyMatches[i].matchScore(entity);
40016 if (score > best) {
40018 match = keyMatches[i];
40023 return match || all.item(geometry);
40026 // Because of the open nature of tagging, iD will never have a complete
40027 // list of tags used in OSM, so we want it to have logic like "assume
40028 // that a closed way with an amenity tag is an area, unless the amenity
40029 // is one of these specific types". This function computes a structure
40030 // that allows testing of such conditions, based on the presets designated
40031 // as as supporting (or not supporting) the area geometry.
40033 // The returned object L is a whitelist/blacklist of tags. A closed way
40034 // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
40035 // (see `iD.Way#isArea()`). In other words, the keys of L form the whitelist,
40036 // and the subkeys form the blacklist.
40037 all.areaKeys = function() {
40039 ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],
40040 presets = _.reject(all.collection, 'suggestion');
40043 presets.forEach(function(d) {
40044 for (var key in d.tags) break;
40046 if (ignore.indexOf(key) !== -1) return;
40048 if (d.geometry.indexOf('area') !== -1) {
40049 areaKeys[key] = areaKeys[key] || {};
40054 presets.forEach(function(d) {
40055 for (var key in d.tags) break;
40057 if (ignore.indexOf(key) !== -1) return;
40059 var value = d.tags[key];
40060 if (d.geometry.indexOf('area') === -1 &&
40061 d.geometry.indexOf('line') !== -1 &&
40062 key in areaKeys && value !== '*') {
40063 areaKeys[key][value] = true;
40070 all.load = function(d) {
40073 _.forEach(d.fields, function(d, id) {
40074 fields[id] = iD.presets.Field(id, d);
40075 if (d.universal) universal.push(fields[id]);
40080 _.forEach(d.presets, function(d, id) {
40081 all.collection.push(iD.presets.Preset(id, d, fields));
40085 if (d.categories) {
40086 _.forEach(d.categories, function(d, id) {
40087 all.collection.push(iD.presets.Category(id, d, all));
40092 var getItem = _.bind(all.item, all);
40094 area: iD.presets.Collection(d.defaults.area.map(getItem)),
40095 line: iD.presets.Collection(d.defaults.line.map(getItem)),
40096 point: iD.presets.Collection(d.defaults.point.map(getItem)),
40097 vertex: iD.presets.Collection(d.defaults.vertex.map(getItem)),
40098 relation: iD.presets.Collection(d.defaults.relation.map(getItem))
40102 for (var i = 0; i < all.collection.length; i++) {
40103 var preset = all.collection[i],
40104 geometry = preset.geometry;
40106 for (var j = 0; j < geometry.length; j++) {
40107 var g = index[geometry[j]];
40108 for (var k in preset.tags) {
40109 (g[k] = g[k] || []).push(preset);
40117 all.field = function(id) {
40121 all.universal = function() {
40125 all.defaults = function(geometry, n) {
40126 var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
40127 def = _.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
40128 return iD.presets.Collection(_.unique(rec.concat(def).concat(all.item(geometry))));
40131 all.choose = function(preset) {
40132 if (!preset.isFallback()) {
40133 recent = iD.presets.Collection(_.unique([preset].concat(recent.collection)));
40140 iD.presets.Category = function(id, category, all) {
40141 category = _.clone(category);
40145 category.members = iD.presets.Collection(category.members.map(function(id) {
40146 return all.item(id);
40149 category.matchGeometry = function(geometry) {
40150 return category.geometry.indexOf(geometry) >= 0;
40153 category.matchScore = function() { return -1; };
40155 category.name = function() {
40156 return t('presets.categories.' + id + '.name', {'default': id});
40159 category.terms = function() {
40165 iD.presets.Collection = function(collection) {
40167 var maxSearchResults = 50,
40168 maxSuggestionResults = 10;
40172 collection: collection,
40174 item: function(id) {
40175 return _.find(collection, function(d) {
40176 return d.id === id;
40180 matchGeometry: function(geometry) {
40181 return iD.presets.Collection(collection.filter(function(d) {
40182 return d.matchGeometry(geometry);
40186 search: function(value, geometry) {
40187 if (!value) return this;
40189 value = value.toLowerCase();
40191 var searchable = _.filter(collection, function(a) {
40192 return a.searchable !== false && a.suggestion !== true;
40194 suggestions = _.filter(collection, function(a) {
40195 return a.suggestion === true;
40198 function leading(a) {
40199 var index = a.indexOf(value);
40200 return index === 0 || a[index - 1] === ' ';
40203 // matches value to preset.name
40204 var leading_name = _.filter(searchable, function(a) {
40205 return leading(a.name().toLowerCase());
40206 }).sort(function(a, b) {
40207 var i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
40208 if (i === 0) return a.name().length - b.name().length;
40212 // matches value to preset.terms values
40213 var leading_terms = _.filter(searchable, function(a) {
40214 return _.any(a.terms() || [], leading);
40217 // matches value to preset.tags values
40218 var leading_tag_values = _.filter(searchable, function(a) {
40219 return _.any(_.without(_.values(a.tags || {}), '*'), leading);
40223 // finds close matches to value in preset.name
40224 var levenstein_name = searchable.map(function(a) {
40227 dist: iD.util.editDistance(value, a.name().toLowerCase())
40229 }).filter(function(a) {
40230 return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
40231 }).sort(function(a, b) {
40232 return a.dist - b.dist;
40233 }).map(function(a) {
40237 // finds close matches to value in preset.terms
40238 var leventstein_terms = _.filter(searchable, function(a) {
40239 return _.any(a.terms() || [], function(b) {
40240 return iD.util.editDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
40244 function suggestionName(name) {
40245 var nameArray = name.split(' - ');
40246 if (nameArray.length > 1) {
40247 name = nameArray.slice(0, nameArray.length-1).join(' - ');
40249 return name.toLowerCase();
40252 var leading_suggestions = _.filter(suggestions, function(a) {
40253 return leading(suggestionName(a.name()));
40254 }).sort(function(a, b) {
40255 a = suggestionName(a.name());
40256 b = suggestionName(b.name());
40257 var i = a.indexOf(value) - b.indexOf(value);
40258 if (i === 0) return a.length - b.length;
40262 var leven_suggestions = suggestions.map(function(a) {
40265 dist: iD.util.editDistance(value, suggestionName(a.name()))
40267 }).filter(function(a) {
40268 return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
40269 }).sort(function(a, b) {
40270 return a.dist - b.dist;
40271 }).map(function(a) {
40275 var other = presets.item(geometry);
40277 var results = leading_name.concat(
40279 leading_tag_values,
40280 leading_suggestions.slice(0, maxSuggestionResults+5),
40283 leven_suggestions.slice(0, maxSuggestionResults)
40284 ).slice(0, maxSearchResults-1);
40286 return iD.presets.Collection(_.unique(
40287 results.concat(other)
40294 iD.presets.Field = function(id, field) {
40295 field = _.clone(field);
40299 field.matchGeometry = function(geometry) {
40300 return !field.geometry || field.geometry === geometry;
40303 field.t = function(scope, options) {
40304 return t('presets.fields.' + id + '.' + scope, options);
40307 field.label = function() {
40308 return field.t('label', {'default': id});
40311 var placeholder = field.placeholder;
40312 field.placeholder = function() {
40313 return field.t('placeholder', {'default': placeholder});
40318 iD.presets.Preset = function(id, preset, fields) {
40319 preset = _.clone(preset);
40322 preset.fields = (preset.fields || []).map(getFields);
40323 preset.geometry = (preset.geometry || []);
40325 function getFields(f) {
40329 preset.matchGeometry = function(geometry) {
40330 return preset.geometry.indexOf(geometry) >= 0;
40333 var matchScore = preset.matchScore || 1;
40334 preset.matchScore = function(entity) {
40335 var tags = preset.tags,
40338 for (var t in tags) {
40339 if (entity.tags[t] === tags[t]) {
40340 score += matchScore;
40341 } else if (tags[t] === '*' && t in entity.tags) {
40342 score += matchScore / 2;
40351 preset.t = function(scope, options) {
40352 return t('presets.presets.' + id + '.' + scope, options);
40355 var name = preset.name;
40356 preset.name = function() {
40357 if (preset.suggestion) {
40358 id = id.split('/');
40359 id = id[0] + '/' + id[1];
40360 return name + ' - ' + t('presets.presets.' + id + '.name');
40362 return preset.t('name', {'default': name});
40365 preset.terms = function() {
40366 return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
40369 preset.isFallback = function() {
40370 var tagCount = Object.keys(preset.tags).length;
40371 return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
40374 preset.reference = function(geometry) {
40375 var key = Object.keys(preset.tags)[0],
40376 value = preset.tags[key];
40378 if (geometry === 'relation' && key === 'type') {
40379 return { rtype: value };
40380 } else if (value === '*') {
40381 return { key: key };
40383 return { key: key, value: value };
40387 var removeTags = preset.removeTags || preset.tags;
40388 preset.removeTags = function(tags, geometry) {
40389 tags = _.omit(tags, _.keys(removeTags));
40391 for (var f in preset.fields) {
40392 var field = preset.fields[f];
40393 if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
40394 delete tags[field.key];
40402 var applyTags = preset.addTags || preset.tags;
40403 preset.applyTags = function(tags, geometry) {
40406 tags = _.clone(tags);
40408 for (k in applyTags) {
40409 if (applyTags[k] === '*') {
40412 tags[k] = applyTags[k];
40416 // Add area=yes if necessary.
40417 // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
40418 // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
40419 // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
40420 if (geometry === 'area') {
40421 var needsAreaTag = true;
40422 if (preset.geometry.indexOf('line') === -1) {
40423 for (k in applyTags) {
40424 if (k in iD.areaKeys) {
40425 needsAreaTag = false;
40430 if (needsAreaTag) {
40435 for (var f in preset.fields) {
40436 var field = preset.fields[f];
40437 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
40438 tags[field.key] = field.default;
40447 iD.validations = {};
40448 iD.validations.DeprecatedTag = function() {
40450 var validation = function(changes) {
40452 for (var i = 0; i < changes.created.length; i++) {
40453 var change = changes.created[i],
40454 deprecatedTags = change.deprecatedTags();
40456 if (!_.isEmpty(deprecatedTags)) {
40457 var tags = iD.util.tagText({ tags: deprecatedTags });
40459 id: 'deprecated_tags',
40460 message: t('validations.deprecated_tags', { tags: tags }),
40470 iD.validations.ManyDeletions = function() {
40471 var threshold = 100;
40473 var validation = function(changes) {
40475 if (changes.deleted.length > threshold) {
40477 id: 'many_deletions',
40478 message: t('validations.many_deletions', { n: changes.deleted.length })
40486 iD.validations.MissingTag = function() {
40488 var validation = function(changes, graph) {
40490 for (var i = 0; i < changes.created.length; i++) {
40491 var change = changes.created[i],
40492 geometry = change.geometry(graph);
40494 if ((geometry === 'point' || geometry === 'line' || geometry === 'area') && !change.isUsed(graph)) {
40497 message: t('validations.untagged_' + geometry),
40498 tooltip: t('validations.untagged_' + geometry + '_tooltip'),
40508 iD.validations.TagSuggestsArea = function() {
40510 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
40511 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
40512 function tagSuggestsArea(tags) {
40513 if (_.isEmpty(tags)) return false;
40515 var presence = ['landuse', 'amenities', 'tourism', 'shop'];
40516 for (var i = 0; i < presence.length; i++) {
40517 if (tags[presence[i]] !== undefined) {
40518 return presence[i] + '=' + tags[presence[i]];
40522 if (tags.building && tags.building === 'yes') return 'building=yes';
40525 var validation = function(changes, graph) {
40527 for (var i = 0; i < changes.created.length; i++) {
40528 var change = changes.created[i],
40529 geometry = change.geometry(graph),
40530 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
40534 id: 'tag_suggests_area',
40535 message: t('validations.tag_suggests_area', { tag: suggestion }),
40546 window.locale = { _current: 'en' };
40548 locale.current = function(_) {
40549 if (!arguments.length) return locale._current;
40550 if (locale[_] !== undefined) locale._current = _;
40551 else if (locale[_.split('-')[0]]) locale._current = _.split('-')[0];
40555 function t(s, o, loc) {
40556 loc = loc || locale._current;
40558 var path = s.split(".").reverse(),
40561 while (rep !== undefined && path.length) rep = rep[path.pop()];
40563 if (rep !== undefined) {
40564 if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
40568 if (loc !== 'en') {
40569 return t(s, o, 'en');
40572 if (o && 'default' in o) {
40573 return o['default'];
40576 var missing = 'Missing ' + loc + ' translation: ' + s;
40577 if (typeof console !== "undefined") console.error(missing);
40581 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","locating":"Locating, please wait..."},"inspector":{"no_documentation_combination":"There is no documentation available for this tag combination","no_documentation_key":"There is no documentation available for this key","show_more":"Show More","view_on_osm":"View on openstreetmap.org","all_fields":"All fields","all_tags":"All tags","all_members":"All members","all_relations":"All relations","new_relation":"New relation...","role":"Role","choose":"Select feature type","results":"{n} results for {search}","reference":"View on OpenStreetMap Wiki","back_tooltip":"Change feature","remove":"Remove","search":"Search","multiselect":"Selected items","unknown":"Unknown","incomplete":"<not downloaded>","feature_list":"Search features","edit":"Edit feature","check":{"yes":"Yes","no":"No"},"none":"None","node":"Node","way":"Way","relation":"Relation","location":"Location","add_fields":"Add field:"},"background":{"title":"Background","description":"Background settings","percent_brightness":"{opacity}% brightness","none":"None","best_imagery":"Best known imagery source for this location","custom":"Custom","custom_button":"Edit custom background","custom_prompt":"Enter a tile URL template. Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.","fix_misalignment":"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"},"traffic_roads":{"description":"Traffic Roads","tooltip":"Highways, Streets, etc."},"service_roads":{"description":"Service Roads","tooltip":"Service Roads, Parking Aisles, Tracks, etc."},"paths":{"description":"Paths","tooltip":"Sidewalks, Foot Paths, Cycle Paths, etc."},"buildings":{"description":"Buildings","tooltip":"Buildings, Shelters, Garages, etc."},"landuse":{"description":"Landuse Features","tooltip":"Forests, Farmland, Parks, Residential, Commercial, etc."},"boundaries":{"description":"Boundaries","tooltip":"Administrative Boundaries"},"water":{"description":"Water Features","tooltip":"Rivers, Lakes, Ponds, Basins, etc."},"rail":{"description":"Rail Features","tooltip":"Railways"},"power":{"description":"Power Features","tooltip":"Power Lines, Power Plants, Substations, etc."},"past_future":{"description":"Past/Future","tooltip":"Proposed, Construction, Abandoned, Demolished, etc."},"others":{"description":"Others","tooltip":"Everything Else"}},"area_fill":{"wireframe":{"description":"No Fill (Wireframe)","tooltip":"Enabling wireframe mode makes it easy to see the background imagery."},"partial":{"description":"Partial Fill","tooltip":"Areas are drawn with fill only around their inner edges. (Recommended for beginner mappers)"},"full":{"description":"Full Fill","tooltip":"Areas are drawn fully filled."}},"restore":{"heading":"You have unsaved changes","description":"Do you wish to restore unsaved changes from a previous editing session?","restore":"Restore","reset":"Reset"},"save":{"title":"Save","help":"Save changes to OpenStreetMap, making them visible to other users.","no_changes":"No changes to save.","error":"Errors occurred while trying to save","status_code":"Server returned status code {code}","unknown_error_details":"Please ensure you are connected to the internet.","uploading":"Uploading changes to OpenStreetMap.","unsaved_changes":"You have unsaved changes","conflict":{"header":"Resolve conflicting edits","count":"Conflict {num} of {total}","previous":"< Previous","next":"Next >","keep_local":"Keep mine","keep_remote":"Use theirs","restore":"Restore","delete":"Leave Deleted","download_changes":"Or download your changes.","done":"All conflicts resolved!","help":"Another user changed some of the same map features you changed.\nClick on each item below for more details about the conflict, and choose whether to keep\nyour changes or the other user's changes.\n"}},"merge_remote_changes":{"conflict":{"deleted":"This object has been deleted by {user}.","location":"This object was moved by both you and {user}.","nodelist":"Nodes were changed by both you and {user}.","memberlist":"Relation members were changed by both you and {user}.","tags":"You changed the <b>{tag}</b> tag to \"{local}\" and {user} changed it to \"{remote}\"."}},"success":{"edited_osm":"Edited OSM!","just_edited":"You just edited OpenStreetMap!","view_on_osm":"View on OSM","facebook":"Share on Facebook","twitter":"Share on Twitter","google":"Share on Google+","help_html":"Your changes should appear in the \"Standard\" layer in a few minutes. Other layers, and certain features, may take longer.","help_link_text":"Details","help_link_url":"https://wiki.openstreetmap.org/wiki/FAQ#I_have_just_made_some_changes_to_the_map._How_do_I_get_to_see_my_changes.3F"},"confirm":{"okay":"Okay","cancel":"Cancel"},"splash":{"welcome":"Welcome to the iD OpenStreetMap editor","text":"iD is a friendly but powerful tool for contributing to the world's best free world map. This is version {version}. For more information see {website} and report bugs at {github}.","walkthrough":"Start the Walkthrough","start":"Edit Now"},"source_switch":{"live":"live","lose_changes":"You have unsaved changes. Switching the map server will discard them. Are you sure you want to switch servers?","dev":"dev"},"tag_reference":{"description":"Description","on_wiki":"{tag} on wiki.osm.org","used_with":"used with {type}"},"validations":{"untagged_point":"Untagged point","untagged_line":"Untagged line","untagged_area":"Untagged area","many_deletions":"You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.","tag_suggests_area":"The tag {tag} suggests line should be area, but it is not an area","untagged_point_tooltip":"Select a feature type that describes what this point is.","untagged_line_tooltip":"Select a feature type that describes what this line is.","untagged_area_tooltip":"Select a feature type that describes what this area is.","deprecated_tags":"Deprecated tags: {tags}"},"zoom":{"in":"Zoom In","out":"Zoom Out"},"cannot_zoom":"Cannot zoom out further in current mode.","full_screen":"Toggle Full Screen","gpx":{"local_layer":"Local GPX file","drag_drop":"Drag and drop a .gpx file on the page, or click the button to the right to browse","zoom":"Zoom to GPX track","browse":"Browse for a .gpx file"},"mapillary_images":{"tooltip":"Street-level photos from Mapillary","title":"Photo Overlay (Mapillary)"},"mapillary_signs":{"tooltip":"Traffic signs from Mapillary","title":"Traffic Sign Overlay (Mapillary)"},"mapillary":{"view_on_mapillary":"View this image on Mapillary"},"help":{"title":"Help","help":"# Help\n\nThis is an editor for [OpenStreetMap](http://www.openstreetmap.org/), the\nfree and editable map of the world. You can use it to add and update\ndata in your area, making an open-source and open-data map of the world\nbetter for everyone.\n\nEdits that you make on this map will be visible to everyone who uses\nOpenStreetMap. In order to make an edit, you'll need to\n[log in](https://www.openstreetmap.org/login).\n\nThe [iD editor](http://ideditor.com/) is a collaborative project with [source\ncode available on GitHub](https://github.com/openstreetmap/iD).\n","editing_saving":"# Editing & Saving\n\nThis editor is designed to work primarily online, and you're accessing\nit through a website right now.\n\n### Selecting Features\n\nTo select a map feature, like a road or point of interest, click\non it on the map. This will highlight the selected feature, open a panel with\ndetails about it, and show a menu of things you can do with the feature.\n\nTo select multiple features, hold down the 'Shift' key. Then either click\non the features you want to select, or drag on the map to draw a rectangle.\nThis will draw a box and select all the points within it.\n\n### Saving Edits\n\nWhen you make changes like editing roads, buildings, and places, these are\nstored locally until you save them to the server. Don't worry if you make\na mistake - you can undo changes by clicking the undo button, and redo\nchanges by clicking the redo button.\n\nClick 'Save' to finish a group of edits - for instance, if you've completed\nan area of town and would like to start on a new area. You'll have a chance\nto review what you've done, and the editor supplies helpful suggestions\nand warnings if something doesn't seem right about the changes.\n\nIf everything looks good, you can enter a short comment explaining the change\nyou made, and click 'Save' again to post the changes\nto [OpenStreetMap.org](http://www.openstreetmap.org/), where they are visible\nto all other users and available for others to build and improve upon.\n\nIf you can't finish your edits in one sitting, you can leave the editor\nwindow and come back (on the same browser and computer), and the\neditor application will offer to restore your work.\n\n### Using the editor\n\nA list of available keyboard shortcuts can be found [here](http://wiki.openstreetmap.org/wiki/ID/Shortcuts).\n","roads":"# Roads\n\nYou can create, fix, and delete roads with this editor. Roads can be all\nkinds: paths, highways, trails, cycleways, and more - any often-crossed\nsegment should be mappable.\n\n### Selecting\n\nClick on a road to select it. An outline should become visible, along\nwith a small tools menu on the map and a sidebar showing more information\nabout the road.\n\n### Modifying\n\nOften you'll see roads that aren't aligned to the imagery behind them\nor to a GPS track. You can adjust these roads so they are in the correct\nplace.\n\nFirst click on the road you want to change. This will highlight it and show\ncontrol points along it that you can drag to better locations. If\nyou want to add new control points for more detail, double-click a part\nof the road without a node, and one will be added.\n\nIf the road connects to another road, but doesn't properly connect on\nthe map, you can drag one of its control points onto the other road in\norder to join them. Having roads connect is important for the map\nand essential for providing driving directions.\n\nYou can also click the 'Move' tool or press the `M` shortcut key to move the entire road at\none time, and then click again to save that movement.\n\n### Deleting\n\nIf a road is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the road could simply be newly built.\n\nYou can delete a road by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n\n### Creating\n\nFound somewhere there should be a road but there isn't? Click the 'Line'\nicon in the top-left of the editor or press the shortcut key `2` to start drawing\na line.\n\nClick on the start of the road on the map to start drawing. If the road\nbranches off from an existing road, start by clicking on the place where they connect.\n\nThen click on points along the road so that it follows the right path, according\nto satellite imagery or GPS. If the road you are drawing crosses another road, connect\nit by clicking on the intersection point. When you're done drawing, double-click\nor press 'Return' or 'Enter' on your keyboard.\n","gps":"# GPS\n\nCollected GPS traces are one valuable source of data for OpenStreetMap. This editor\nsupports local traces - `.gpx` files on your local computer. You can collect\nthis kind of GPS trace with a number of smartphone applications as well as\npersonal GPS hardware.\n\nFor information on how to perform a GPS survey, read\n[Mapping with a smartphone, GPS, or paper](http://learnosm.org/en/mobile-mapping/).\n\nTo use a GPX track for mapping, drag and drop the GPX file onto the map\neditor. If it's recognized, it will be added to the map as a bright purple\nline. Click on the 'Map Data' menu on the right side to enable,\ndisable, or zoom to this new GPX-powered layer.\n\nThe GPX track isn't directly uploaded to OpenStreetMap - the best way to\nuse it is to draw on the map, using it as a guide for the new features that\nyou add, and also to [upload it to OpenStreetMap](http://www.openstreetmap.org/trace/create)\nfor other users to use.\n","imagery":"# Imagery\n\nAerial imagery is an important resource for mapping. A combination of\nairplane flyovers, satellite views, and freely-compiled sources are available\nin the editor under the 'Background Settings' menu on the right.\n\nBy default a [Bing Maps](http://www.bing.com/maps/) satellite layer is\npresented in the editor, but as you pan and zoom the map to new geographical\nareas, new sources will become available. Some countries, like the United\nStates, France, and Denmark have very high-quality imagery available for some areas.\n\nImagery is sometimes offset from the map data because of a mistake on the\nimagery provider's side. If you see a lot of roads shifted from the background,\ndon't immediately move them all to match the background. Instead you can adjust\nthe imagery so that it matches the existing data by clicking 'Fix alignment' at\nthe bottom of the Background Settings UI.\n","addresses":"# Addresses\n\nAddresses are some of the most useful information for the map.\n\nAlthough addresses are often represented as parts of streets, in OpenStreetMap\nthey're recorded as attributes of buildings and places along streets.\n\nYou can add address information to places mapped as building outlines\nas well as those mapped as single points. The optimal source of address\ndata is from an on-the-ground survey or personal knowledge - as with any\nother feature, copying from commercial sources like Google Maps is strictly\nforbidden.\n","inspector":"# Using the Inspector\n\nThe inspector is the section on the left side of the page that allows you to\nedit the details of the selected feature.\n\n### Selecting a Feature Type\n\nAfter you add a point, line, or area, you can choose what type of feature it\nis, like whether it's a highway or residential road, supermarket or cafe.\nThe inspector will display buttons for common feature types, and you can\nfind others by typing what you're looking for in the search box.\n\nClick the 'i' in the bottom-right-hand corner of a feature type button to\nlearn more about it. Click a button to choose that type.\n\n### Using Forms and Editing Tags\n\nAfter you choose a feature type, or when you select a feature that already\nhas a type assigned, the inspector will display fields with details about\nthe feature like its name and address.\n\nBelow the fields you see, you can click the 'Add field' dropdown to add\nother details, like a Wikipedia link, wheelchair access, and more.\n\nAt the bottom of the inspector, click 'Additional tags' to add arbitrary\nother tags to the element. [Taginfo](http://taginfo.openstreetmap.org/) is a\ngreat resource for learn more about popular tag combinations.\n\nChanges you make in the inspector are automatically applied to the map.\nYou can undo them at any time by clicking the 'Undo' button.\n","buildings":"# Buildings\n\nOpenStreetMap is the world's largest database of buildings. You can create\nand improve this database.\n\n### Selecting\n\nYou can select a building by clicking on its border. This will highlight the\nbuilding and open a small tools menu and a sidebar showing more information\nabout the building.\n\n### Modifying\n\nSometimes buildings are incorrectly placed or have incorrect tags.\n\nTo move an entire building, select it, then click the 'Move' tool. Move your\nmouse to shift the building, and click when it's correctly placed.\n\nTo fix the specific shape of a building, click and drag the nodes that form\nits border into better places.\n\n### Creating\n\nOne of the main questions around adding buildings to the map is that\nOpenStreetMap records buildings both as shapes and points. The rule of thumb\nis to _map a building as a shape whenever possible_, and map companies, homes,\namenities, and other things that operate out of buildings as points placed\nwithin the building shape.\n\nStart drawing a building as a shape by clicking the 'Area' button in the top\nleft of the interface, and end it either by pressing 'Return' on your keyboard\nor clicking on the first node drawn to close the shape.\n\n### Deleting\n\nIf a building is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the building could simply be newly built.\n\nYou can delete a building by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n","relations":"# Relations\n\nA relation is a special type of feature in OpenStreetMap that groups together\nother features. For example, two common types of relations are *route relations*,\nwhich group together sections of road that belong to a specific freeway or\nhighway, and *multipolygons*, which group together several lines that define\na complex area (one with several pieces or holes in it like a donut).\n\nThe group of features in a relation are called *members*. In the sidebar, you can\nsee which relations a feature is a member of, and click on a relation there\nto select the it. When the relation is selected, you can see all of its\nmembers listed in the sidebar and highlighted on the map.\n\nFor the most part, iD will take care of maintaining relations automatically\nwhile you edit. The main thing you should be aware of is that if you delete a\nsection of road to redraw it more accurately, you should make sure that the\nnew section is a member of the same relations as the original.\n\n## Editing Relations\n\nIf you want to edit relations, here are the basics.\n\nTo add a feature to a relation, select the feature, click the \"+\" button in the\n\"All relations\" section of the sidebar, and select or type the name of the relation.\n\nTo create a new relation, select the first feature that should be a member,\nclick the \"+\" button in the \"All relations\" section, and select \"New relation...\".\n\nTo remove a feature from a relation, select the feature and click the trash\nbutton next to the relation you want to remove it from.\n\nYou can create multipolygons with holes using the \"Merge\" tool. Draw two areas (inner\nand outer), hold the Shift key and click on each of them to select them both, and then\nclick the \"Merge\" (+) button.\n"},"intro":{"graph":{"city_hall":"Three Rivers City Hall","fire_department":"Three Rivers Fire Department","memory_isle_park":"Memory Isle Park","riverwalk_trail":"Riverwalk Trail","w_michigan_ave":"West Michigan Avenue","e_michigan_ave":"East Michigan Avenue","spring_st":"Spring Street","scidmore_park":"Scidmore Park","petting_zoo":"Scidmore Park Petting Zoo","n_andrews_st":"North Andrews Street","s_andrews_st":"South Andrews Street","n_constantine_st":"North Constantine Street","s_constantine_st":"South Constantine Street","rocky_river":"Rocky River","railroad_dr":"Railroad Drive","conrail_rr":"Conrail Railroad","st_joseph_river":"Saint Joseph River","n_main_st":"North Main Street","s_main_st":"South Main Street","water_st":"Water Street","foster_st":"Foster Street","portage_river":"Portage River","flower_st":"Flower Street","elm_st":"Elm Street","walnut_st":"Walnut Street","morris_ave":"Morris Avenue","east_st":"East Street","portage_ave":"Portage Avenue"},"navigation":{"title":"Navigation","drag":"The main map area shows OpenStreetMap data on top of a background. You can navigate by dragging and scrolling, just like any web map. **Drag the map!**","select":"Map features are represented three ways: using points, lines or areas. All features can be selected by clicking on them. **Click on the point to select it.**","pane":"When a feature is selected, the feature editor is displayed. The header shows us the feature type and the main pane shows the feature's attributes, such as its name and address. **Close the feature editor by pressing the {button} button in the top right.**","search":"You can also search for features in the current view, or worldwide. **Search for '{name}'**","choose":"**Choose {name} from the list to select it.**","chosen":"Great! {name} is now selected. **Close the feature editor by pressing the {button} button.**"},"points":{"title":"Points","add":"Points can be used to represent features such as shops, restaurants, and monuments. They mark a specific location, and describe what's there. **Click the {button} Point button to add a new point.**","place":"The point can be placed by clicking on the map. **Click the map to place the new point on top of the building.**","search":"There are many different features that can be represented by points. The point you just added is a Cafe. **Search for '{name}'**","choose":"**Choose Cafe from the list.**","describe":"The point is now marked as a cafe. Using the feature editor, we can add more information about the feature. **Add a name**","close":"The feature editor will remember all of your changes automatically. When you change a feature, the close button will change to a checkmark. **Click the {button} button to close the feature editor**","reselect":"Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Click to select the point you just created.**","fixname":"**Change the name, then click the {button} button to close the feature editor.**","reselect_delete":"All features on the map can be deleted. **Click to select the point you created.**","delete":"The menu around the point contains operations that can be performed on it, including delete. **Click on the {button} button to delete the point.**"},"areas":{"title":"Areas","add":"Areas are used to show the boundaries of features like lakes, buildings, and residential areas. They can be also be used for more detailed mapping of many features you might normally map as points. **Click the {button} Area button to add a new area.**","corner":"Areas are drawn by placing nodes that mark the boundary of the area. **Click to place a starting node on one of the corners of the playground.**","place":"Draw the area by placing more nodes. Finish the area by clicking on the starting node. **Draw an area for the playground.**","search":"**Search for '{name}'.**","choose":"**Choose Playground from the list.**","describe":"**Add a name, then click the {button} button to close the feature editor**"},"lines":{"title":"Lines","add":"Lines are used to represent features such as roads, railroads, and rivers. **Click the {button} Line button to add a new line.**","start":"**Start the line by clicking on the end of the road.**","intersect":"Click to add more nodes to the line. You can drag the map while drawing if necessary. Roads, and many other types of lines, are part of a larger network. It is important for these lines to be connected properly in order for routing applications to work. **Click on {name} to create an intersection connecting the two lines.**","finish":"Lines can be finished by clicking on the last node again. **Finish drawing the road.**","road":"**Select Road from the list**","residential":"There are different types of roads, the most common of which is Residential. **Choose the Residential road type**","describe":"**Name the road, then click the {button} button to close the feature editor.**","restart":"The road needs to intersect {name}.","wrong_preset":"You didn't select the Residential road type. **Click here to choose again**"},"startediting":{"title":"Start Editing","help":"You can replay this walkthrough or view more documentation by clicking the {button} Help button.","save":"Don't forget to regularly save your changes!","start":"Start mapping!"}},"presets":{"categories":{"category-building":{"name":"Building Features"},"category-golf":{"name":"Golf Features"},"category-landuse":{"name":"Land Use Features"},"category-path":{"name":"Path Features"},"category-rail":{"name":"Rail Features"},"category-restriction":{"name":"Restriction Features"},"category-road":{"name":"Road Features"},"category-route":{"name":"Route Features"},"category-water-area":{"name":"Water Features"},"category-water-line":{"name":"Water Features"}},"fields":{"access":{"label":"Allowed Access","placeholder":"Not Specified","types":{"access":"All","foot":"Foot","motor_vehicle":"Motor Vehicles","bicycle":"Bicycles","horse":"Horses"},"options":{"yes":{"title":"Allowed","description":"Access permitted by law; a right of way"},"no":{"title":"Prohibited","description":"Access not permitted to the general public"},"permissive":{"title":"Permissive","description":"Access permitted until such time as the owner revokes the permission"},"private":{"title":"Private","description":"Access permitted only with permission of the owner on an individual basis"},"designated":{"title":"Designated","description":"Access permitted according to signs or specific local laws"},"destination":{"title":"Destination","description":"Access permitted only to reach a destination"},"dismount":{"title":"Dismount","description":"Access permitted but rider must dismount"}}},"access_simple":{"label":"Allowed Access","placeholder":"yes"},"access_toilets":{"label":"Access"},"address":{"label":"Address","placeholders":{"housename":"Housename","housenumber":"123","conscriptionnumber":"123","street":"Street","city":"City","postcode":"Postcode","place":"Place","hamlet":"Hamlet","suburb":"Suburb","subdistrict":"Subdistrict","district":"District","province":"Province","state":"State","country":"Country"}},"admin_level":{"label":"Admin Level"},"aerialway":{"label":"Type"},"aerialway/access":{"label":"Access","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aerialway/bubble":{"label":"Bubble"},"aerialway/capacity":{"label":"Capacity (per hour)","placeholder":"500, 2500, 5000..."},"aerialway/duration":{"label":"Duration (minutes)","placeholder":"1, 2, 3..."},"aerialway/heating":{"label":"Heated"},"aerialway/occupancy":{"label":"Occupancy","placeholder":"2, 4, 8..."},"aerialway/summer/access":{"label":"Access (summer)","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aeroway":{"label":"Type"},"amenity":{"label":"Type"},"area/highway":{"label":"Type"},"artist":{"label":"Artist"},"artwork_type":{"label":"Type"},"atm":{"label":"ATM"},"backrest":{"label":"Backrest"},"barrier":{"label":"Type"},"bench":{"label":"Bench"},"bicycle_parking":{"label":"Type"},"boundary":{"label":"Type"},"brand":{"label":"Brand"},"building":{"label":"Building"},"building_area":{"label":"Building"},"capacity":{"label":"Capacity","placeholder":"50, 100, 200..."},"cardinal_direction":{"label":"Direction","options":{"N":"North","E":"East","S":"South","W":"West","NE":"Northeast","SE":"Southeast","SW":"Southwest","NW":"Northwest","NNE":"North-northeast","ENE":"East-northeast","ESE":"East-southeast","SSE":"South-southeast","SSW":"South-southwest","WSW":"West-southwest","WNW":"West-northwest","NNW":"North-northwest"}},"clock_direction":{"label":"Direction","options":{"clockwise":"Clockwise","anticlockwise":"Counterclockwise"}},"collection_times":{"label":"Collection Times"},"construction":{"label":"Type"},"content":{"label":"Contents"},"country":{"label":"Country"},"covered":{"label":"Covered"},"craft":{"label":"Type"},"crop":{"label":"Crop"},"crossing":{"label":"Type"},"cuisine":{"label":"Cuisine"},"cycleway":{"label":"Bike Lanes","placeholder":"none","types":{"cycleway:left":"Left side","cycleway:right":"Right side"},"options":{"none":{"title":"None","description":"No bike lane"},"lane":{"title":"Standard bike lane","description":"A bike lane separated from auto traffic by a painted line"},"shared_lane":{"title":"Shared bike lane","description":"A bike lane with no separation from auto traffic"},"track":{"title":"Bike track","description":"A bike lane separated from traffic by a physical barrier"},"share_busway":{"title":"Bike lane shared with bus","description":"A bike lane shared with a bus lane"},"opposite_lane":{"title":"Opposite bike lane","description":"A bike lane that travels in the opposite direction of traffic"},"opposite":{"title":"Contraflow bike lane","description":"A bike lane that travels in both directions on a one-way street"}}},"delivery":{"label":"Delivery"},"denomination":{"label":"Denomination"},"denotation":{"label":"Denotation"},"description":{"label":"Description"},"diaper":{"label":"Diaper Changing Available"},"dock":{"label":"Type"},"drive_through":{"label":"Drive-Through"},"electrified":{"label":"Electrification","placeholder":"Contact Line, Electrified Rail...","options":{"contact_line":"Contact Line","rail":"Electrified Rail","yes":"Yes (unspecified)","no":"No"}},"elevation":{"label":"Elevation"},"emergency":{"label":"Emergency"},"entrance":{"label":"Type"},"except":{"label":"Exceptions"},"fax":{"label":"Fax","placeholder":"+31 42 123 4567"},"fee":{"label":"Fee"},"fire_hydrant/type":{"label":"Type","options":{"pillar":"Pillar/Aboveground","underground":"Underground","wall":"Wall","pond":"Pond"}},"fixme":{"label":"Fix Me"},"fuel":{"label":"Fuel"},"fuel/biodiesel":{"label":"Sells Biodiesel"},"fuel/diesel":{"label":"Sells Diesel"},"fuel/e10":{"label":"Sells E10"},"fuel/e85":{"label":"Sells E85"},"fuel/lpg":{"label":"Sells Propane"},"fuel/octane_100":{"label":"Sells Racing Gasoline"},"fuel/octane_91":{"label":"Sells Regular Gasoline"},"fuel/octane_95":{"label":"Sells Midgrade Gasoline"},"fuel/octane_98":{"label":"Sells Premium Gasoline"},"gauge":{"label":"Gauge"},"gender":{"label":"Gender","placeholder":"Unknown","options":{"male":"Male","female":"Female","unisex":"Unisex"}},"generator/method":{"label":"Method"},"generator/source":{"label":"Source"},"generator/type":{"label":"Type"},"golf_hole":{"label":"Reference","placeholder":"Hole number (1-18)"},"handicap":{"label":"Handicap","placeholder":"1-18"},"handrail":{"label":"Handrail"},"highway":{"label":"Type"},"historic":{"label":"Type"},"hoops":{"label":"Hoops","placeholder":"1, 2, 4..."},"iata":{"label":"IATA"},"icao":{"label":"ICAO"},"incline":{"label":"Incline"},"incline_steps":{"label":"Incline","options":{"up":"Up","down":"Down"}},"information":{"label":"Type"},"internet_access":{"label":"Internet Access","options":{"yes":"Yes","no":"No","wlan":"Wifi","wired":"Wired","terminal":"Terminal"}},"lamp_type":{"label":"Type"},"landuse":{"label":"Type"},"lanes":{"label":"Lanes","placeholder":"1, 2, 3..."},"layer":{"label":"Layer"},"leaf_cycle":{"label":"Leaf Cycle","options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous","mixed":"Mixed"}},"leaf_cycle_singular":{"label":"Leaf Cycle","options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous"}},"leaf_type":{"label":"Leaf Type","options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","mixed":"Mixed","leafless":"Leafless"}},"leaf_type_singular":{"label":"Leaf Type","options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","leafless":"Leafless"}},"leisure":{"label":"Type"},"length":{"label":"Length (Meters)"},"level":{"label":"Level"},"levels":{"label":"Levels","placeholder":"2, 4, 6..."},"lit":{"label":"Lit"},"location":{"label":"Location"},"man_made":{"label":"Type"},"maxspeed":{"label":"Speed Limit","placeholder":"40, 50, 60..."},"maxstay":{"label":"Max Stay"},"mtb/scale":{"label":"Mountain Biking Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Solid gravel/packed earth, no obstacles, wide curves","1":"1: Some loose surface, small obstacles, wide curves","2":"2: Much loose surface, large obstacles, easy hairpins","3":"3: Slippery surface, large obstacles, tight hairpins","4":"4: Loose surface or boulders, dangerous hairpins","5":"5: Maximum difficulty, boulder fields, landslides","6":"6: Not rideable except by the very best mountain bikers"}},"mtb/scale/imba":{"label":"IMBA Trail Difficulty","placeholder":"Easy, Medium, Difficult...","options":{"0":"Easiest (white circle)","1":"Easy (green circle)","2":"Medium (blue square)","3":"Difficult (black diamond)","4":"Extremely Difficult (double black diamond)"}},"mtb/scale/uphill":{"label":"Mountain Biking Uphill Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Avg. incline <10%, gravel/packed earth, no obstacles","1":"1: Avg. incline <15%, gravel/packed earth, few small objects","2":"2: Avg. incline <20%, stable surface, fistsize rocks/roots","3":"3: Avg. incline <25%, variable surface, fistsize rocks/branches","4":"4: Avg. incline <30%, poor condition, big rocks/branches","5":"5: Very steep, bike generally needs to be pushed or carried"}},"name":{"label":"Name","placeholder":"Common name (if any)"},"natural":{"label":"Natural"},"network":{"label":"Network"},"note":{"label":"Note"},"office":{"label":"Type"},"oneway":{"label":"One Way","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"oneway_yes":{"label":"One Way","options":{"undefined":"Assumed to be Yes","yes":"Yes","no":"No"}},"opening_hours":{"label":"Hours"},"operator":{"label":"Operator"},"par":{"label":"Par","placeholder":"3, 4, 5..."},"park_ride":{"label":"Park and Ride"},"parking":{"label":"Type","options":{"surface":"Surface","multi-storey":"Multilevel","underground":"Underground","sheds":"Sheds","carports":"Carports","garage_boxes":"Garage Boxes","lane":"Roadside Lane"}},"phone":{"label":"Phone","placeholder":"+31 42 123 4567"},"piste/difficulty":{"label":"Difficulty","placeholder":"Easy, Intermediate, Advanced...","options":{"novice":"Novice (instructional)","easy":"Easy (green circle)","intermediate":"Intermediate (blue square)","advanced":"Advanced (black diamond)","expert":"Expert (double black diamond)","freeride":"Freeride (off-piste)","extreme":"Extreme (climbing equipment required)"}},"piste/grooming":{"label":"Grooming","options":{"classic":"Classic","mogul":"Mogul","backcountry":"Backcountry","classic+skating":"Classic and Skating","scooter":"Scooter/Snowmobile","skating":"Skating"}},"piste/type":{"label":"Type","options":{"downhill":"Downhill","nordic":"Nordic","skitour":"Skitour","sled":"Sled","hike":"Hike","sleigh":"Sleigh","ice_skate":"Ice Skate","snow_park":"Snow Park","playground":"Playground"}},"place":{"label":"Type"},"population":{"label":"Population"},"power":{"label":"Type"},"power_supply":{"label":"Power Supply"},"railway":{"label":"Type"},"recycling/cans":{"label":"Accepts Cans"},"recycling/clothes":{"label":"Accepts Clothes"},"recycling/glass":{"label":"Accepts Glass"},"recycling/glass_bottles":{"label":"Accepts Glass Bottles"},"recycling/paper":{"label":"Accepts Paper"},"recycling/plastic":{"label":"Accepts Plastic"},"recycling/type":{"label":"Recycling Type","options":{"container":"Container","centre":"Recycling Center"}},"ref":{"label":"Reference"},"relation":{"label":"Type"},"religion":{"label":"Religion"},"restriction":{"label":"Type"},"restrictions":{"label":"Turn Restrictions"},"route":{"label":"Type"},"route_master":{"label":"Type"},"sac_scale":{"label":"Hiking Difficulty","placeholder":"Mountain Hiking, Alpine Hiking...","options":{"hiking":"T1: Hiking","mountain_hiking":"T2: Mountain Hiking","demanding_mountain_hiking":"T3: Demanding Mountain Hiking","alpine_hiking":"T4: Alpine Hiking","demanding_alpine_hiking":"T5: Demanding Alpine Hiking","difficult_alpine_hiking":"T6: Difficult Alpine Hiking"}},"sanitary_dump_station":{"label":"Toilet Disposal"},"seasonal":{"label":"Seasonal"},"service":{"label":"Type"},"service/bicycle/chain_tool":{"label":"Chain Tool","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"service/bicycle/pump":{"label":"Air Pump","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"service_rail":{"label":"Service Type","options":{"spur":"Spur","yard":"Yard","siding":"Siding","crossover":"Crossover"}},"shelter":{"label":"Shelter"},"shelter_type":{"label":"Type"},"shop":{"label":"Type"},"site":{"label":"Type"},"sloped_curb":{"label":"Sloped Curb"},"smoking":{"label":"Smoking","placeholder":"No, Separated, Yes...","options":{"no":"No smoking anywhere","separated":"In smoking areas, not physically isolated","isolated":"In smoking areas, physically isolated","outside":"Allowed outside","yes":"Allowed everywhere","dedicated":"Dedicated to smokers (e.g. smokers' club)"}},"smoothness":{"label":"Smoothness","placeholder":"Thin Rollers, Wheels, Off-Road...","options":{"excellent":"Thin Rollers: rollerblade, skateboard","good":"Thin Wheels: racing bike","intermediate":"Wheels: city bike, wheelchair, scooter","bad":"Robust Wheels: trekking bike, car, rickshaw","very_bad":"High Clearance: light duty off-road vehicle","horrible":"Off-Road: heavy duty off-road vehicle","very_horrible":"Specialized off-road: tractor, ATV","impassable":"Impassable / No wheeled vehicle"}},"social_facility_for":{"label":"People served","placeholder":"Homeless, Disabled, Child, etc"},"source":{"label":"Source"},"sport":{"label":"Sport"},"sport_ice":{"label":"Sport"},"sport_racing":{"label":"Sport"},"structure":{"label":"Structure","placeholder":"Unknown","options":{"bridge":"Bridge","tunnel":"Tunnel","embankment":"Embankment","cutting":"Cutting","ford":"Ford"}},"studio_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/Unclassified Road","terms":""},"historic":{"name":"Historic Site","terms":""},"historic/archaeological_site":{"name":"Archaeological Site","terms":""},"historic/boundary_stone":{"name":"Boundary Stone","terms":""},"historic/castle":{"name":"Castle","terms":""},"historic/memorial":{"name":"Memorial","terms":""},"historic/monument":{"name":"Monument","terms":""},"historic/ruins":{"name":"Ruins","terms":""},"historic/wayside_cross":{"name":"Wayside Cross","terms":""},"historic/wayside_shrine":{"name":"Wayside Shrine","terms":""},"junction":{"name":"Junction","terms":""},"landuse":{"name":"Land Use","terms":""},"landuse/allotments":{"name":"Community Garden","terms":"allotment,garden"},"landuse/basin":{"name":"Basin","terms":""},"landuse/cemetery":{"name":"Cemetery","terms":""},"landuse/churchyard":{"name":"Churchyard","terms":""},"landuse/commercial":{"name":"Commercial Area","terms":""},"landuse/construction":{"name":"Construction","terms":""},"landuse/farm":{"name":"Farmland","terms":""},"landuse/farmland":{"name":"Farmland","terms":""},"landuse/farmyard":{"name":"Farmyard","terms":""},"landuse/forest":{"name":"Forest","terms":"tree"},"landuse/garages":{"name":"Garages","terms":""},"landuse/grass":{"name":"Grass","terms":""},"landuse/industrial":{"name":"Industrial Area","terms":""},"landuse/landfill":{"name":"Landfill","terms":"dump"},"landuse/meadow":{"name":"Meadow","terms":""},"landuse/military":{"name":"Military Area","terms":""},"landuse/orchard":{"name":"Orchard","terms":""},"landuse/plant_nursery":{"name":"Plant Nursery","terms":"vivero"},"landuse/quarry":{"name":"Quarry","terms":""},"landuse/residential":{"name":"Residential Area","terms":""},"landuse/retail":{"name":"Retail Area","terms":""},"landuse/vineyard":{"name":"Vineyard","terms":""},"leisure":{"name":"Leisure","terms":""},"leisure/adult_gaming_centre":{"name":"Adult Gaming Center","terms":"gambling,slot machine"},"leisure/bird_hide":{"name":"Bird Hide","terms":"machan,ornithology"},"leisure/bowling_alley":{"name":"Bowling Alley","terms":""},"leisure/common":{"name":"Common","terms":"open space"},"leisure/dog_park":{"name":"Dog Park","terms":""},"leisure/firepit":{"name":"Firepit","terms":"fireplace,campfire"},"leisure/garden":{"name":"Garden","terms":""},"leisure/golf_course":{"name":"Golf Course","terms":"links"},"leisure/ice_rink":{"name":"Ice Rink","terms":"hockey,skating,curling"},"leisure/marina":{"name":"Marina","terms":"boat"},"leisure/nature_reserve":{"name":"Nature Reserve","terms":"protected,wildlife"},"leisure/park":{"name":"Park","terms":"esplanade,estate,forest,garden,grass,green,grounds,lawn,lot,meadow,parkland,place,playground,plaza,pleasure garden,recreation area,square,tract,village green,woodland"},"leisure/picnic_table":{"name":"Picnic Table","terms":"bench"},"leisure/pitch":{"name":"Sport Pitch","terms":"field"},"leisure/pitch/american_football":{"name":"American Football Field","terms":""},"leisure/pitch/baseball":{"name":"Baseball Diamond","terms":""},"leisure/pitch/basketball":{"name":"Basketball Court","terms":""},"leisure/pitch/rugby_league":{"name":"Rugby League Field","terms":""},"leisure/pitch/rugby_union":{"name":"Rugby Union Field","terms":""},"leisure/pitch/skateboard":{"name":"Skate Park","terms":""},"leisure/pitch/soccer":{"name":"Soccer Field","terms":""},"leisure/pitch/tennis":{"name":"Tennis Court","terms":""},"leisure/pitch/volleyball":{"name":"Volleyball Court","terms":""},"leisure/playground":{"name":"Playground","terms":"jungle gym,play area"},"leisure/running_track":{"name":"Running Track","terms":""},"leisure/slipway":{"name":"Slipway","terms":"boat launch,boat ramp"},"leisure/sports_centre":{"name":"Sports Center / Gym","terms":"gym"},"leisure/sports_centre/swimming":{"name":"Swimming Pool Facility","terms":"dive,water"},"leisure/stadium":{"name":"Stadium","terms":""},"leisure/swimming_pool":{"name":"Swimming Pool","terms":"dive,water"},"leisure/track":{"name":"Racetrack (non-Motorsport)","terms":""},"leisure/water_park":{"name":"Water Park","terms":"swim,pool,dive"},"line":{"name":"Line","terms":""},"man_made":{"name":"Man Made","terms":""},"man_made/adit":{"name":"Adit","terms":"entrance,underground,mine,cave"},"man_made/breakwater":{"name":"Breakwater","terms":""},"man_made/chimney":{"name":"Chimney","terms":""},"man_made/cutline":{"name":"Cut line","terms":""},"man_made/embankment":{"name":"Embankment","terms":""},"man_made/flagpole":{"name":"Flagpole","terms":""},"man_made/gasometer":{"name":"Gasometer","terms":"gas holder"},"man_made/groyne":{"name":"Groyne","terms":""},"man_made/lighthouse":{"name":"Lighthouse","terms":""},"man_made/mast":{"name":"Radio Mast","terms":"broadcast tower,cell phone tower,cell tower,guyed tower,mobile phone tower,radio tower,television tower,transmission mast,transmission tower,tv tower"},"man_made/observation":{"name":"Observation Tower","terms":"lookout tower,fire tower"},"man_made/petroleum_well":{"name":"Oil Well","terms":"drilling rig,oil derrick,oil drill,oil horse,oil rig,oil pump,petroleum well,pumpjack"},"man_made/pier":{"name":"Pier","terms":"dock"},"man_made/pipeline":{"name":"Pipeline","terms":""},"man_made/silo":{"name":"Silo","terms":"grain,corn,wheat"},"man_made/storage_tank":{"name":"Storage Tank","terms":"water,oil,gas,petrol"},"man_made/surveillance":{"name":"Surveillance","terms":""},"man_made/survey_point":{"name":"Survey Point","terms":""},"man_made/tower":{"name":"Tower","terms":""},"man_made/wastewater_plant":{"name":"Wastewater Plant","terms":"sewage*,water treatment plant,reclamation plant"},"man_made/water_tower":{"name":"Water Tower","terms":""},"man_made/water_well":{"name":"Water Well","terms":""},"man_made/water_works":{"name":"Water Works","terms":""},"man_made/works":{"name":"Works","terms":"car assembly plant,aluminium processing plant,brewery,furniture manufacture factory,oil refinery,plastic recycling"},"military/airfield":{"name":"Airfield","terms":""},"military/barracks":{"name":"Barracks","terms":""},"military/bunker":{"name":"Bunker","terms":""},"military/checkpoint":{"name":"Checkpoint","terms":""},"military/danger_area":{"name":"Danger Area","terms":""},"military/naval_base":{"name":"Naval Base","terms":""},"military/obstacle_course":{"name":"Obstacle Course","terms":""},"military/range":{"name":"Military Range","terms":""},"military/training_area":{"name":"Training area","terms":""},"natural":{"name":"Natural","terms":""},"natural/bay":{"name":"Bay","terms":""},"natural/beach":{"name":"Beach","terms":""},"natural/cave_entrance":{"name":"Cave Entrance","terms":"cavern,hollow,grotto,shelter,cavity"},"natural/cliff":{"name":"Cliff","terms":""},"natural/coastline":{"name":"Coastline","terms":"shore"},"natural/fell":{"name":"Fell","terms":""},"natural/glacier":{"name":"Glacier","terms":""},"natural/grassland":{"name":"Grassland","terms":""},"natural/heath":{"name":"Heath","terms":""},"natural/peak":{"name":"Peak","terms":"acme,aiguille,alp,climax,crest,crown,hill,mount,mountain,pinnacle,summit,tip,top"},"natural/saddle":{"name":"Saddle","terms":"pass,mountain pass,top"},"natural/scree":{"name":"Scree","terms":"loose rocks"},"natural/scrub":{"name":"Scrub","terms":"bush,shrubs"},"natural/spring":{"name":"Spring","terms":""},"natural/tree":{"name":"Tree","terms":""},"natural/tree_row":{"name":"Tree row","terms":""},"natural/volcano":{"name":"Volcano","terms":"mountain,crater"},"natural/water":{"name":"Water","terms":""},"natural/water/lake":{"name":"Lake","terms":"lakelet,loch,mere"},"natural/water/pond":{"name":"Pond","terms":"lakelet,millpond,tarn,pool,mere"},"natural/water/reservoir":{"name":"Reservoir","terms":""},"natural/wetland":{"name":"Wetland","terms":""},"natural/wood":{"name":"Wood","terms":"tree"},"office":{"name":"Office","terms":""},"office/accountant":{"name":"Accountant","terms":""},"office/administrative":{"name":"Administrative Office","terms":""},"office/architect":{"name":"Architect","terms":""},"office/company":{"name":"Company Office","terms":""},"office/educational_institution":{"name":"Educational Institution","terms":""},"office/employment_agency":{"name":"Employment Agency","terms":"job"},"office/estate_agent":{"name":"Real Estate Office","terms":""},"office/financial":{"name":"Financial Office","terms":""},"office/government":{"name":"Government Office","terms":""},"office/insurance":{"name":"Insurance Office","terms":""},"office/it":{"name":"IT Office","terms":""},"office/lawyer":{"name":"Law Office","terms":""},"office/newspaper":{"name":"Newspaper","terms":""},"office/ngo":{"name":"NGO Office","terms":""},"office/physician":{"name":"Physician","terms":""},"office/political_party":{"name":"Political Party","terms":""},"office/research":{"name":"Research Office","terms":""},"office/telecommunication":{"name":"Telecom Office","terms":""},"office/therapist":{"name":"Therapist","terms":""},"office/travel_agent":{"name":"Travel Agency","terms":""},"piste":{"name":"Piste/Ski Trail","terms":"ski,sled,sleigh,snowboard,nordic,downhill,snowmobile"},"place":{"name":"Place","terms":""},"place/city":{"name":"City","terms":""},"place/farm":{"name":"Farm","terms":""},"place/hamlet":{"name":"Hamlet","terms":""},"place/island":{"name":"Island","terms":"archipelago,atoll,bar,cay,isle,islet,key,reef"},"place/isolated_dwelling":{"name":"Isolated Dwelling","terms":""},"place/locality":{"name":"Locality","terms":""},"place/neighbourhood":{"name":"Neighborhood","terms":"neighbourhood"},"place/suburb":{"name":"Borough","terms":"Boro,Quarter"},"place/town":{"name":"Town","terms":""},"place/village":{"name":"Village","terms":""},"point":{"name":"Point","terms":""},"power":{"name":"Power","terms":""},"power/generator":{"name":"Power Generator","terms":""},"power/line":{"name":"Power Line","terms":""},"power/minor_line":{"name":"Minor Power Line","terms":""},"power/pole":{"name":"Power Pole","terms":""},"power/sub_station":{"name":"Substation","terms":""},"power/substation":{"name":"Substation","terms":""},"power/tower":{"name":"High-Voltage Tower","terms":""},"power/transformer":{"name":"Transformer","terms":""},"public_transport/platform":{"name":"Platform","terms":""},"public_transport/stop_position":{"name":"Stop Position","terms":""},"railway":{"name":"Railway","terms":""},"railway/abandoned":{"name":"Abandoned Railway","terms":""},"railway/disused":{"name":"Disused Railway","terms":""},"railway/funicular":{"name":"Funicular","terms":"venicular,cliff railway,cable car,cable railway,funicular railway"},"railway/halt":{"name":"Railway Halt","terms":"break,interrupt,rest,wait,interruption"},"railway/level_crossing":{"name":"Railway Crossing","terms":"crossing,railroad crossing,level crossing,grade crossing,road through railroad,train crossing"},"railway/monorail":{"name":"Monorail","terms":""},"railway/narrow_gauge":{"name":"Narrow Gauge Rail","terms":"narrow gauge railway,narrow gauge railroad"},"railway/platform":{"name":"Railway Platform","terms":""},"railway/rail":{"name":"Rail","terms":""},"railway/station":{"name":"Railway Station","terms":"train station,station"},"railway/subway":{"name":"Subway","terms":""},"railway/subway_entrance":{"name":"Subway Entrance","terms":""},"railway/tram":{"name":"Tram","terms":"streetcar"},"relation":{"name":"Relation","terms":""},"roundabout":{"name":"Roundabout","terms":""},"route/ferry":{"name":"Ferry Route","terms":""},"shop":{"name":"Shop","terms":""},"shop/alcohol":{"name":"Liquor Store","terms":"alcohol,beer,booze,wine"},"shop/anime":{"name":"Anime Shop","terms":""},"shop/antiques":{"name":"Antiques Shop","terms":""},"shop/art":{"name":"Art Store","terms":"art*,exhibit*,gallery"},"shop/baby_goods":{"name":"Baby Goods Store","terms":""},"shop/bag":{"name":"Bag/Luggage Store","terms":"handbag,purse"},"shop/bakery":{"name":"Bakery","terms":""},"shop/bathroom_furnishing":{"name":"Bathroom Furnishing Store","terms":""},"shop/beauty":{"name":"Beauty Shop","terms":"nail spa,spa,salon,tanning"},"shop/bed":{"name":"Bedding/Mattress Store","terms":""},"shop/beverages":{"name":"Beverage Store","terms":""},"shop/bicycle":{"name":"Bicycle Shop","terms":"bike,repair"},"shop/bookmaker":{"name":"Bookmaker","terms":""},"shop/books":{"name":"Book Store","terms":""},"shop/boutique":{"name":"Boutique","terms":""},"shop/butcher":{"name":"Butcher","terms":"meat"},"shop/candles":{"name":"Candle Shop","terms":""},"shop/car":{"name":"Car Dealership","terms":"auto"},"shop/car_parts":{"name":"Car Parts Store","terms":"auto"},"shop/car_repair":{"name":"Car Repair Shop","terms":"auto"},"shop/carpet":{"name":"Carpet Store","terms":"rug"},"shop/cheese":{"name":"Cheese Store","terms":""},"shop/chemist":{"name":"Chemist","terms":""},"shop/chocolate":{"name":"Chocolate Store","terms":""},"shop/clothes":{"name":"Clothing Store","terms":""},"shop/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":"Wet Dock / Dry Dock","terms":"boat,ship,vessel,marine"},"waterway/drain":{"name":"Drain","terms":""},"waterway/fuel":{"name":"Marine Fuel Station","terms":"petrol,gas,diesel,boat"},"waterway/river":{"name":"River","terms":"beck,branch,brook,course,creek,estuary,rill,rivulet,run,runnel,stream,tributary,watercourse"},"waterway/riverbank":{"name":"Riverbank","terms":""},"waterway/sanitary_dump_station":{"name":"Marine Toilet Disposal","terms":"Boat,Watercraft,Sanitary,Dump Station,Pumpout,Pump out,Elsan,CDP,CTDP,Chemical Toilet"},"waterway/stream":{"name":"Stream","terms":"beck,branch,brook,burn,course,creek,current,drift,flood,flow,freshet,race,rill,rindle,rivulet,run,runnel,rush,spate,spritz,surge,tide,torrent,tributary,watercourse"},"waterway/water_point":{"name":"Marine Drinking Water","terms":""},"waterway/weir":{"name":"Weir","terms":""}}}},"suggestions":{"amenity":{"fuel":{"76":{"count":314},"Neste":{"count":189},"BP":{"count":2511},"Shell":{"count":8380},"Agip":{"count":2651},"Migrol":{"count":65},"Avia":{"count":897},"Texaco":{"count":680},"Total":{"count":2607},"Statoil":{"count":596},"Esso":{"count":3652},"Jet":{"count":441},"Avanti":{"count":90},"Sainsbury's":{"count":58},"OMV":{"count":701},"Aral":{"count":1339},"Tesco":{"count":197},"JET":{"count":180},"Morrisons":{"count":111},"United":{"count":91},"Canadian Tire":{"count":66},"Mobil":{"count":613},"Caltex":{"count":1001},"Sunoco":{"count":355},"Q8":{"count":1161},"ABC":{"count":79},"ARAL":{"count":375},"CEPSA":{"count":1018},"BFT":{"count":89},"Petron":{"count":878},"Intermarché":{"count":434},"Total Access":{"count":51},"Super U":{"count":124},"Auchan":{"count":53},"Elf":{"count":129},"Carrefour":{"count":205},"Station Service E. Leclerc":{"count":530},"Shell Express":{"count":131},"Hess":{"count":127},"Flying V":{"count":129},"bft":{"count":168},"Gulf":{"count":199},"PTT":{"count":191},"St1":{"count":100},"Teboil":{"count":115},"HEM":{"count":212},"GALP":{"count":626},"OK":{"count":163},"ÖMV":{"count":101},"Tinq":{"count":215},"OKQ8":{"count":186},"Repsol":{"count":424},"Westfalen":{"count":96},"Esso Express":{"count":98},"Raiffeisenbank":{"count":117},"Tamoil":{"count":866},"Engen":{"count":241},"Sasol":{"count":59},"Topaz":{"count":78},"LPG":{"count":174},"Coop":{"count":62},"Orlen":{"count":598},"Oilibya":{"count":68},"Tango":{"count":122},"Star":{"count":319},"Петрол":{"count":84},"Cepsa":{"count":96},"OIL!":{"count":63},"Ultramar":{"count":125},"Irving":{"count":87},"Lukoil":{"count":701},"Petro-Canada":{"count":489},"7-Eleven":{"count":488},"Agrola":{"count":69},"Husky":{"count":126},"Slovnaft":{"count":219},"Sheetz":{"count":134},"Mol":{"count":61},"Petronas":{"count":159},"Газпромнефть":{"count":748},"Лукойл":{"count":1477},"Elan":{"count":112},"Роснефть":{"count":638},"Turmöl":{"count":57},"Neste A24":{"count":55},"Marathon":{"count":189},"Valero":{"count":366},"Eni":{"count":236},"Chevron":{"count":954},"ТНК":{"count":520},"REPSOL":{"count":1603},"MOL":{"count":228},"Bliska":{"count":150},"Api":{"count":302},"Arco":{"count":179},"Pemex":{"count":423},"Exxon":{"count":506},"Coles Express":{"count":115},"Petrom":{"count":259},"PETRONOR":{"count":207},"Rompetrol":{"count":174},"Lotos":{"count":178},"ОМВ":{"count":60},"BR":{"count":129},"Copec":{"count":505},"Petrobras":{"count":270},"Liberty":{"count":55},"IP":{"count":871},"Erg":{"count":596},"Eneos":{"count":97},"Citgo":{"count":279},"Metano":{"count":208},"Сургутнефтегаз":{"count":61},"EKO":{"count":59},"Eko":{"count":58},"Indipend.":{"count":172},"IES":{"count":63},"TotalErg":{"count":89},"Cenex":{"count":115},"ПТК":{"count":82},"HP":{"count":79},"Phillips 66":{"count":216},"CARREFOUR":{"count":74},"ERG":{"count":76},"Speedway":{"count":148},"Benzina":{"count":96},"Татнефть":{"count":264},"Terpel":{"count":259},"WOG":{"count":189},"Seaoil":{"count":54},"АЗС":{"count":1077},"Kwik Trip":{"count":108},"Wawa":{"count":89},"Pertamina":{"count":186},"COSMO":{"count":64},"Z":{"count":76},"Indian Oil":{"count":183},"АГЗС":{"count":494},"INA":{"count":121},"JOMO":{"count":62},"Holiday":{"count":97},"YPF":{"count":70},"IDEMITSU":{"count":87},"ENEOS":{"count":736},"Bharat Petroleum":{"count":64},"CAMPSA":{"count":615},"Casey's General Store":{"count":190},"Башнефть":{"count":60},"Kangaroo":{"count":60},"コスモ石油 (COSMO)":{"count":136},"MEROIL":{"count":77},"1-2-3":{"count":71},"出光":{"count":228,"tags":{"name:en":"IDEMITSU"}},"НК Альянс":{"count":88},"Sinclair":{"count":100},"Conoco":{"count":189},"SPBU":{"count":54},"Макпетрол":{"count":109},"Circle K":{"count":166},"Posto Ipiranga":{"count":70},"Posto Shell":{"count":54},"Phoenix":{"count":144},"Ipiranga":{"count":119},"OKKO":{"count":85},"ОККО":{"count":119},"บางจาก":{"count":60},"QuikTrip":{"count":105},"Stewart's":{"count":63},"Posto BR":{"count":68},"ป ต ท":{"count":152},"ปตท":{"count":88},"ANP":{"count":80},"Kum & Go":{"count":80},"Petrolimex":{"count":55},"Sokimex":{"count":66},"Tela":{"count":154},"Posto":{"count":71},"H-E-B":{"count":182},"Укрнафта":{"count":58},"Татнефтепродукт":{"count":54},"Afriquia":{"count":88},"Murphy USA":{"count":67},"昭和シェル (Showa-shell)":{"count":94},"エネオス":{"count":53},"CNG":{"count":94}},"pub":{"Kings Arms":{"count":67},"The Ship":{"count":89},"The White Horse":{"count":204},"The White Hart":{"count":226},"Royal Oak":{"count":150},"The Red Lion":{"count":233},"The Kings Arms":{"count":58},"The Star":{"count":73},"The Anchor":{"count":64},"The Cross Keys":{"count":55},"The Wheatsheaf":{"count":117},"The Crown Inn":{"count":67},"The Kings Head":{"count":53},"The Castle":{"count":62},"The Railway":{"count":102},"The White Lion":{"count":118},"The Bell":{"count":121},"The Bull":{"count":68},"The Plough":{"count":179},"The George":{"count":110},"The Royal Oak":{"count":209},"The Fox":{"count":74},"Prince of Wales":{"count":77},"The Rising Sun":{"count":71},"The Prince of Wales":{"count":51},"The Crown":{"count":244},"The Chequers":{"count":66},"The Swan":{"count":152},"Rose and Crown":{"count":79},"The Victoria":{"count":67},"New Inn":{"count":90},"Royal Hotel":{"count":57},"Red Lion":{"count":207},"Cross Keys":{"count":61},"The Greyhound":{"count":96},"The Black Horse":{"count":94},"The New Inn":{"count":105},"Kings Head":{"count":59},"The Albion":{"count":51},"The Angel":{"count":52},"The Queens Head":{"count":52},"The Ship Inn":{"count":83},"Rose & Crown":{"count":51},"Queens Head":{"count":52},"Irish Pub":{"count":76}},"fast_food":{"Quick":{"count":484},"McDonald's":{"count":12376,"tags":{"cuisine":"burger"}},"Subway":{"count":5576,"tags":{"cuisine":"sandwich"}},"Burger King":{"count":3734,"tags":{"cuisine":"burger"}},"Ali Baba":{"count":61},"Hungry Jacks":{"count":173,"tags":{"cuisine":"burger"}},"Red Rooster":{"count":148},"KFC":{"count":3198,"tags":{"cuisine":"chicken"}},"Domino's Pizza":{"count":985,"tags":{"cuisine":"pizza"}},"Chowking":{"count":142},"Jollibee":{"count":396},"Hesburger":{"count":102},"肯德基":{"count":86},"Wendy's":{"count":1621,"tags":{"cuisine":"burger"}},"Tim Hortons":{"count":323},"Steers":{"count":151},"Hardee's":{"count":268,"tags":{"cuisine":"burger"}},"Arby's":{"count":782},"A&W":{"count":283},"Dairy Queen":{"count":791},"Hallo Pizza":{"count":76},"Fish & Chips":{"count":93},"Harvey's":{"count":90},"麥當勞":{"count":65},"Pizza Pizza":{"count":215},"Kotipizza":{"count":74},"Jack in the Box":{"count":546,"tags":{"cuisine":"burger"}},"Istanbul":{"count":56},"Kochlöffel":{"count":68},"Döner":{"count":228},"Telepizza":{"count":201},"Sibylla":{"count":61},"Carl's Jr.":{"count":298,"tags":{"cuisine":"burger"}},"Quiznos":{"count":266,"tags":{"cuisine":"sandwich"}},"Wimpy":{"count":141},"Sonic":{"count":566,"tags":{"cuisine":"burger"}},"Taco Bell":{"count":1423,"tags":{"cuisine":"mexican"}},"Pizza Nova":{"count":63},"Papa John's":{"count":304,"tags":{"cuisine":"pizza"}},"Nordsee":{"count":159},"Mr. Sub":{"count":103},"Макдоналдс":{"count":324,"tags":{"name:en":"McDonald's"}},"Asia Imbiss":{"count":111},"Chipotle":{"count":290,"tags":{"cuisine":"mexican"}},"マクドナルド":{"count":692,"tags":{"name:en":"McDonald's","cuisine":"burger"}},"In-N-Out Burger":{"count":65},"Jimmy John's":{"count":141},"Jamba Juice":{"count":68},"Робин Сдобин":{"count":82},"Baskin Robbins":{"count":74},"ケンタッキーフライドチキン":{"count":164,"tags":{"name:en":"KFC","cuisine":"chicken"}},"吉野家":{"count":191},"Taco Time":{"count":88},"松屋":{"count":281,"tags":{"name:en":"Matsuya"}},"Little Caesars":{"count":81},"El Pollo Loco":{"count":63},"Del Taco":{"count":141},"White Castle":{"count":80},"Boston Market":{"count":66},"Chick-fil-A":{"count":257,"tags":{"cuisine":"chicken"}},"Panda Express":{"count":238,"tags":{"cuisine":"chinese"}},"Whataburger":{"count":364},"Taco John's":{"count":78},"Теремок":{"count":68},"Culver's":{"count":425},"Five Guys":{"count":141},"Church's Chicken":{"count":95},"Popeye's":{"count":167,"tags":{"cuisine":"chicken"}},"Long John Silver's":{"count":93},"Pollo Campero":{"count":62},"Zaxby's":{"count":51},"すき家":{"count":276,"tags":{"name:en":"SUKIYA"}},"モスバーガー":{"count":257,"tags":{"name:en":"MOS BURGER"}},"Русский Аппетит":{"count":69},"なか卯":{"count":63}},"restaurant":{"Pizza Hut":{"count":1180,"tags":{"cuisine":"pizza"}},"Little Chef":{"count":64},"Adler":{"count":158},"Zur Krone":{"count":90},"Deutsches Haus":{"count":90},"Krone":{"count":171},"Akropolis":{"count":152},"Schützenhaus":{"count":124},"Kreuz":{"count":74},"Waldschänke":{"count":55},"La Piazza":{"count":69},"Lamm":{"count":66},"Zur Sonne":{"count":73},"Zur Linde":{"count":204},"Poseidon":{"count":110},"Shanghai":{"count":82},"Red Lobster":{"count":235},"Zum Löwen":{"count":84},"Swiss Chalet":{"count":107},"Olympia":{"count":74},"Wagamama":{"count":64},"Frankie & Benny's":{"count":66},"Hooters":{"count":103},"Sternen":{"count":78},"Hirschen":{"count":79},"Denny's":{"count":450},"Athen":{"count":68},"Sonne":{"count":126},"Hirsch":{"count":79},"Ratskeller":{"count":150},"La Cantina":{"count":56},"Gasthaus Krone":{"count":56},"El Greco":{"count":86},"Gasthof zur Post":{"count":79},"Nando's":{"count":246},"Löwen":{"count":112},"La Pataterie":{"count":51},"Bella Napoli":{"count":53},"Pizza Express":{"count":262},"Mandarin":{"count":65},"Hong Kong":{"count":83},"Zizzi":{"count":68},"Cracker Barrel":{"count":183},"Rhodos":{"count":81},"Lindenhof":{"count":79},"Milano":{"count":54},"Dolce Vita":{"count":77},"Kirchenwirt":{"count":81},"Kantine":{"count":52},"Ochsen":{"count":95},"Spur":{"count":62},"Mykonos":{"count":59},"Lotus":{"count":66},"Applebee's":{"count":531},"Flunch":{"count":72},"Zur Post":{"count":116},"China Town":{"count":76},"La Dolce Vita":{"count":73},"Waffle House":{"count":207},"Delphi":{"count":88},"Linde":{"count":103},"Outback Steakhouse":{"count":218},"Dionysos":{"count":69},"Kelsey's":{"count":57},"Boston Pizza":{"count":165},"Bella Italia":{"count":132},"Sizzler":{"count":53},"Grüner Baum":{"count":116},"Taj Mahal":{"count":104},"Rössli":{"count":68},"Wimpy":{"count":51},"Traube":{"count":65},"Adria":{"count":52},"Red Robin":{"count":185},"Roma":{"count":61},"San Marco":{"count":67},"Hellas":{"count":55},"La Perla":{"count":67},"Vips":{"count":53},"Panera Bread":{"count":218},"Da Vinci":{"count":54},"Hippopotamus":{"count":96},"Prezzo":{"count":75},"Courtepaille":{"count":106},"Hard Rock Cafe":{"count":70},"Panorama":{"count":61},"デニーズ":{"count":82},"Sportheim":{"count":65},"餃子の王将":{"count":57},"Bären":{"count":60},"Alte Post":{"count":60},"Pizzeria Roma":{"count":51},"China Garden":{"count":66},"Vapiano":{"count":82},"Mamma Mia":{"count":64},"Schwarzer Adler":{"count":57},"IHOP":{"count":317},"Chili's":{"count":328},"Asia":{"count":51},"Olive Garden":{"count":279},"TGI Friday's":{"count":159},"Friendly's":{"count":78},"Buffalo Grill":{"count":202},"Texas Roadhouse":{"count":110},"ガスト":{"count":230,"tags":{"name:en":"Gusto"}},"Sakura":{"count":75},"Mensa":{"count":99},"The Keg":{"count":53},"サイゼリヤ":{"count":93},"La Strada":{"count":52},"Village Inn":{"count":92},"Buffalo Wild Wings":{"count":176},"Peking":{"count":59},"Boston Market":{"count":61},"Round Table Pizza":{"count":53},"Jimmy John's":{"count":69},"California Pizza Kitchen":{"count":61},"Якитория":{"count":77},"Golden Corral":{"count":101},"Perkins":{"count":105},"Ruby Tuesday":{"count":162},"Shari's":{"count":65},"Bob Evans":{"count":129},"바다횟집 (Bada Fish Restaurant)":{"count":55},"Mang Inasal":{"count":84},"Евразия":{"count":102},"ジョナサン":{"count":59},"Longhorn Steakhouse":{"count":66}},"bank":{"Chase":{"count":721},"Commonwealth Bank":{"count":232},"Citibank":{"count":277},"HSBC":{"count":1102},"Barclays":{"count":965},"Westpac":{"count":208},"NAB":{"count":131},"ANZ":{"count":218},"Lloyds Bank":{"count":547},"Landbank":{"count":81},"Sparkasse":{"count":4555},"UCPB":{"count":92},"PNB":{"count":244},"Metrobank":{"count":269},"BDO":{"count":290},"Volksbank":{"count":2591},"BPI":{"count":415},"Postbank":{"count":443},"NatWest":{"count":628},"Raiffeisenbank":{"count":2119},"Yorkshire Bank":{"count":63},"ABSA":{"count":95},"Standard Bank":{"count":109},"FNB":{"count":97},"Deutsche Bank":{"count":855},"SEB":{"count":133},"Commerzbank":{"count":806},"Targobank":{"count":166},"ABN AMRO":{"count":130},"Handelsbanken":{"count":184},"Swedbank":{"count":223},"Kreissparkasse":{"count":600},"UniCredit Bank":{"count":408},"Monte dei Paschi di Siena":{"count":132},"Caja Rural":{"count":99},"Dresdner Bank":{"count":66},"Sparda-Bank":{"count":320},"VÚB":{"count":107},"Slovenská sporiteľňa":{"count":134},"Bank of Montreal":{"count":118},"KBC":{"count":203},"Royal Bank of Scotland":{"count":111},"TSB":{"count":80},"US Bank":{"count":256},"HypoVereinsbank":{"count":561},"Bank Austria":{"count":176},"ING":{"count":496},"Erste Bank":{"count":180},"CIBC":{"count":326},"Scotiabank":{"count":413},"Caisse d'Épargne":{"count":882},"Santander":{"count":1323},"Bank of Scotland":{"count":89},"TD Canada Trust":{"count":450},"BMO":{"count":169},"Danske Bank":{"count":131},"OTP":{"count":192},"Crédit Agricole":{"count":1239},"LCL":{"count":553},"VR-Bank":{"count":430},"ČSOB":{"count":160},"Česká spořitelna":{"count":212},"BNP":{"count":112},"Royal Bank":{"count":65},"Nationwide":{"count":209},"Halifax":{"count":225},"BAWAG PSK":{"count":102},"National Bank":{"count":84},"Nedbank":{"count":80},"First National Bank":{"count":85},"Nordea":{"count":319},"Rabobank":{"count":609},"Sparkasse KölnBonn":{"count":69},"Tatra banka":{"count":67},"Berliner Sparkasse":{"count":62},"Berliner Volksbank":{"count":77},"Wells Fargo":{"count":874},"Credit Suisse":{"count":71},"Société Générale":{"count":634},"Osuuspankki":{"count":75},"Sparkasse Aachen":{"count":56},"Hamburger Sparkasse":{"count":156},"Cassa di Risparmio del Veneto":{"count":68},"BNP Paribas":{"count":617},"Banque Populaire":{"count":433},"BNP Paribas Fortis":{"count":209},"Banco Popular":{"count":291},"Bancaja":{"count":55},"Banesto":{"count":208},"La Caixa":{"count":583},"Santander Consumer Bank":{"count":88},"BRD":{"count":191},"BCR":{"count":143},"Banca Transilvania":{"count":141},"BW-Bank":{"count":97},"Komerční banka":{"count":132},"Banco Pastor":{"count":64},"Stadtsparkasse":{"count":86},"Ulster Bank":{"count":86},"Sberbank":{"count":58},"CIC":{"count":427},"Bancpost":{"count":56},"Caja Madrid":{"count":115},"Maybank":{"count":94},"中国银行":{"count":85},"Unicredit Banca":{"count":243},"Crédit Mutuel":{"count":690},"BBVA":{"count":647},"Intesa San Paolo":{"count":69},"TD Bank":{"count":206},"Belfius":{"count":231},"Bank of America":{"count":924},"RBC":{"count":230},"Alpha Bank":{"count":123},"Сбербанк":{"count":4794},"Россельхозбанк":{"count":201},"Crédit du Nord":{"count":96},"BancoEstado":{"count":80},"Millennium Bank":{"count":414},"State Bank of India":{"count":151},"Беларусбанк":{"count":242},"ING Bank Śląski":{"count":67},"Caixa Geral de Depósitos":{"count":129},"Kreissparkasse Köln":{"count":65},"Banco BCI":{"count":51},"Banco de Chile":{"count":98},"ВТБ24":{"count":326},"UBS":{"count":134},"PKO BP":{"count":265},"Chinabank":{"count":55},"PSBank":{"count":59},"Union Bank":{"count":124},"China Bank":{"count":66},"RCBC":{"count":122},"Unicaja":{"count":83},"BBK":{"count":79},"Ibercaja":{"count":69},"RBS":{"count":143},"Commercial Bank of Ceylon PLC":{"count":79},"Bank of Ireland":{"count":109},"BNL":{"count":87},"Banco Santander":{"count":138},"Banco Itaú":{"count":111},"AIB":{"count":72},"BZ WBK":{"count":77},"Banco do Brasil":{"count":557},"Caixa Econômica Federal":{"count":184},"Fifth Third Bank":{"count":84},"Banca Popolare di Vicenza":{"count":81},"Wachovia":{"count":58},"OLB":{"count":53},"みずほ銀行":{"count":78},"BES":{"count":72},"ICICI Bank":{"count":91},"HDFC Bank":{"count":91},"La Banque Postale":{"count":67},"Pekao SA":{"count":56},"Oberbank":{"count":90},"Bradesco":{"count":295},"Oldenburgische Landesbank":{"count":56},"Bendigo Bank":{"count":93},"Argenta":{"count":86},"AXA":{"count":68},"Axis Bank":{"count":61},"Banco Nación":{"count":67},"GE Money Bank":{"count":72},"Альфа-Банк":{"count":185},"Белагропромбанк":{"count":70},"Caja Círculo":{"count":65},"Banco Galicia":{"count":51},"Eurobank":{"count":97},"Banca Intesa":{"count":62},"Canara Bank":{"count":92},"Cajamar":{"count":77},"Banamex":{"count":149},"Crédit Mutuel de Bretagne":{"count":335},"Davivienda":{"count":83},"Bank Spółdzielczy":{"count":159},"Credit Agricole":{"count":157},"Bankinter":{"count":59},"Banque Nationale":{"count":63},"Bank of the West":{"count":96},"Key Bank":{"count":155},"Western Union":{"count":88},"Citizens Bank":{"count":115},"ПриватБанк":{"count":513},"Security Bank":{"count":78},"Millenium":{"count":60},"Bankia":{"count":149},"三菱東京UFJ銀行":{"count":159},"Caixa":{"count":117},"Banco de Costa Rica":{"count":63},"SunTrust Bank":{"count":73},"Itaú":{"count":338},"PBZ":{"count":52},"中国工商银行":{"count":51},"Bancolombia":{"count":89},"Райффайзен Банк Аваль":{"count":64},"Bancomer":{"count":115},"Banorte":{"count":80},"Alior Bank":{"count":81},"BOC":{"count":51},"Банк Москвы":{"count":118},"ВТБ":{"count":59},"Getin Bank":{"count":55},"Caja Duero":{"count":57},"Regions Bank":{"count":62},"Росбанк":{"count":177},"Banco Estado":{"count":72},"BCI":{"count":68},"SunTrust":{"count":68},"PNC Bank":{"count":254},"신한은행":{"count":217,"tags":{"name:en":"Sinhan Bank"}},"우리은행":{"count":291,"tags":{"name:en":"Uri Bank"}},"국민은행":{"count":165,"tags":{"name:en":"Gungmin Bank"}},"중소기업은행":{"count":52,"tags":{"name:en":"Industrial Bank of Korea"}},"광주은행":{"count":51,"tags":{"name:en":"Gwangju Bank"}},"Газпромбанк":{"count":100},"M&T Bank":{"count":92},"Caja de Burgos":{"count":51},"Santander Totta":{"count":69},"УкрСиббанк":{"count":192},"Ощадбанк":{"count":364},"Уралсиб":{"count":85},"りそな銀行":{"count":225,"tags":{"name:en":"Mizuho Bank"}},"Ecobank":{"count":66},"Cajero Automatico Bancared":{"count":145},"Промсвязьбанк":{"count":93},"三井住友銀行":{"count":129},"Banco Provincia":{"count":67},"BB&T":{"count":147},"Возрождение":{"count":59},"Capital One":{"count":59},"横浜銀行":{"count":51},"Bank Mandiri":{"count":62},"Banco de la Nación":{"count":92},"Banco G&T Continental":{"count":62},"Peoples Bank":{"count":60},"工商银行":{"count":51},"Совкомбанк":{"count":55},"Provincial":{"count":56},"Banco de Desarrollo Banrural":{"count":73},"Banco Bradesco":{"count":65},"Bicentenario":{"count":182},"ლიბერთი ბანკი":{"count":54,"tags":{"name:en":"Liberty Bank"}},"Banesco":{"count":108},"Mercantil":{"count":75},"Bank BRI":{"count":53},"Del Tesoro":{"count":91},"하나은행":{"count":77},"CityCommerce Bank":{"count":71},"De Venezuela":{"count":117}},"car_rental":{"Europcar":{"count":291},"Budget":{"count":92},"Sixt":{"count":161},"Avis":{"count":282},"Hertz":{"count":293},"Enterprise":{"count":199},"stadtmobil CarSharing-Station":{"count":148}},"pharmacy":{"Rowlands Pharmacy":{"count":71},"Boots":{"count":840},"Marien-Apotheke":{"count":314},"Mercury Drug":{"count":426},"Löwen-Apotheke":{"count":356},"Superdrug":{"count":117},"Sonnen-Apotheke":{"count":311},"Rathaus-Apotheke":{"count":132},"Engel-Apotheke":{"count":123},"Hirsch-Apotheke":{"count":83},"Stern-Apotheke":{"count":67},"Lloyds Pharmacy":{"count":295},"Rosen-Apotheke":{"count":208},"Stadt-Apotheke":{"count":302},"Markt-Apotheke":{"count":164},"Аптека":{"count":1989},"Pharmasave":{"count":64},"Brunnen-Apotheke":{"count":53},"Shoppers Drug Mart":{"count":430},"Apotheke am Markt":{"count":60},"Alte Apotheke":{"count":88},"Neue Apotheke":{"count":109},"Gintarinė vaistinė":{"count":101},"Rats-Apotheke":{"count":84},"Adler Apotheke":{"count":313},"Pharmacie Centrale":{"count":64},"Walgreens":{"count":1619},"Rite Aid":{"count":745},"Apotheke":{"count":165},"Linden-Apotheke":{"count":211},"Bahnhof-Apotheke":{"count":66},"Burg-Apotheke":{"count":55},"Jean Coutu":{"count":62},"Pharmaprix":{"count":60},"Farmacias Ahumada":{"count":104},"Farmacia Comunale":{"count":113},"Farmacias Cruz Verde":{"count":86},"Cruz Verde":{"count":99},"Hubertus Apotheke":{"count":52},"CVS":{"count":1560},"Farmacias SalcoBrand":{"count":133},"Фармация":{"count":120},"Bären-Apotheke":{"count":74},"Clicks":{"count":113},"セイジョー":{"count":53},"マツモトキヨシ":{"count":115},"Dr. Max":{"count":51},"Вита":{"count":106},"Радуга":{"count":70},"サンドラッグ":{"count":61},"Apteka":{"count":366},"Первая помощь":{"count":74},"Ригла":{"count":113},"Имплозия":{"count":63},"Kinney Drugs":{"count":68},"Классика":{"count":67},"Ljekarna":{"count":53},"SalcoBrand":{"count":88},"Аптека 36,6":{"count":224},"Фармакор":{"count":75},"スギ薬局":{"count":84},"Аптечный пункт":{"count":148},"Невис":{"count":60},"トモズ (Tomod's)":{"count":83},"Eurovaistinė":{"count":65},"Farmacity":{"count":68},"аптека":{"count":96},"The Generics Pharmacy":{"count":95},"Farmatodo":{"count":123},"Duane Reade":{"count":61},"H-E-B":{"count":262},"Фармленд":{"count":82},"ドラッグてらしま (Drug Terashima)":{"count":96},"Арніка":{"count":125},"ავერსი (Aversi)":{"count":62},"Farmahorro":{"count":58}},"cafe":{"Starbucks":{"count":4238,"tags":{"cuisine":"coffee_shop"}},"Cafeteria":{"count":115},"Costa":{"count":618},"Caffè Nero":{"count":169},"Кафе":{"count":226},"Café Central":{"count":61},"Second Cup":{"count":193},"Dunkin Donuts":{"count":428,"tags":{"cuisine":"donut"}},"Espresso House":{"count":53},"Segafredo":{"count":69},"Coffee Time":{"count":94},"Cafe Coffee Day":{"count":120},"Eiscafe Venezia":{"count":180},"スターバックス":{"count":251,"tags":{"name:en":"Starbucks"}},"Шоколадница":{"count":145},"Pret A Manger":{"count":119},"Столовая":{"count":391},"Jamba Juice":{"count":53},"ドトール":{"count":164,"tags":{"name:en":"DOUTOR"}},"Tchibo":{"count":100},"Кофе Хауз":{"count":104},"Caribou Coffee":{"count":100},"Уют":{"count":51},"Шашлычная":{"count":58},"คาเฟ่ อเมซอน":{"count":62},"Traveler's Coffee":{"count":60},"カフェ・ド・クリエ":{"count":67,"tags":{"name:en":"Cafe de CRIE"}},"Cafe Amazon":{"count":65}}},"shop":{"supermarket":{"Budgens":{"count":88},"Morrisons":{"count":411},"Interspar":{"count":142},"Merkur":{"count":107},"Sainsbury's":{"count":547},"Lidl":{"count":7130},"Edeka":{"count":2293},"Coles":{"count":400},"Iceland":{"count":315},"Coop":{"count":2100},"Tesco":{"count":1297},"Woolworths":{"count":541},"Zielpunkt":{"count":239},"Nahkauf":{"count":170},"Billa":{"count":1432},"Kaufland":{"count":1004},"Plus":{"count":120},"ALDI":{"count":5172},"Checkers":{"count":128},"Tesco Metro":{"count":137},"NP":{"count":153},"Penny":{"count":1759},"Norma":{"count":1068},"Asda":{"count":225},"Netto":{"count":4379},"Rewe":{"count":2645},"Aldi Süd":{"count":594},"Real":{"count":246},"Tesco Express":{"count":406},"King Soopers":{"count":72},"Kiwi":{"count":167},"Pick n Pay":{"count":241},"ICA":{"count":192},"Tengelmann":{"count":188},"Carrefour":{"count":1640},"Waitrose":{"count":258},"Spar":{"count":2386},"Hofer":{"count":442},"M-Preis":{"count":76},"tegut":{"count":210},"Sainsbury's Local":{"count":118},"E-Center":{"count":66},"Aldi Nord":{"count":210},"nahkauf":{"count":84},"Meijer":{"count":76},"Safeway":{"count":410},"Costco":{"count":152},"Albert":{"count":185},"Jumbo":{"count":194},"Shoprite":{"count":244},"MPreis":{"count":54},"Penny Market":{"count":429},"Tesco Extra":{"count":123},"Albert Heijn":{"count":476},"IGA":{"count":363},"Super U":{"count":488},"Metro":{"count":260},"Neukauf":{"count":77},"Migros":{"count":459},"Marktkauf":{"count":121},"Delikatesy Centrum":{"count":59},"C1000":{"count":307},"Hoogvliet":{"count":53},"Food Basics":{"count":75},"Casino":{"count":264},"Penny Markt":{"count":466},"Giant":{"count":191},"COOP Jednota":{"count":73},"Rema 1000":{"count":368},"Kaufpark":{"count":96},"ALDI SÜD":{"count":113},"Simply Market":{"count":330},"Konzum":{"count":230},"Carrefour Express":{"count":353},"Eurospar":{"count":270},"Mercator":{"count":125},"Famila":{"count":130},"Hemköp":{"count":82},"real,-":{"count":81},"Markant":{"count":88},"Volg":{"count":135},"Leader Price":{"count":267},"Treff 3000":{"count":94},"SuperBrugsen":{"count":67},"Kaiser's":{"count":256},"K+K":{"count":106},"Unimarkt":{"count":86},"Carrefour City":{"count":126},"Sobeys":{"count":122},"S-Market":{"count":109},"Combi":{"count":55},"Denner":{"count":276},"Konsum":{"count":133},"Franprix":{"count":312},"Monoprix":{"count":198},"Diska":{"count":69},"PENNY":{"count":79},"Dia":{"count":835},"Giant Eagle":{"count":85},"NORMA":{"count":115},"AD Delhaize":{"count":63},"Auchan":{"count":152},"Mercadona":{"count":769},"Consum":{"count":130},"Carrefour Market":{"count":80},"Whole Foods":{"count":210,"tags":{"shop":"supermarket"}},"Pam":{"count":56},"sky":{"count":105},"Despar":{"count":146},"Eroski":{"count":208},"Costcutter":{"count":63},"Maxi":{"count":108},"Colruyt":{"count":180},"The Co-operative":{"count":64},"Intermarché":{"count":1210},"Delhaize":{"count":207},"CBA":{"count":176},"Shopi":{"count":53},"Walmart":{"count":644},"Kroger":{"count":317},"Albertsons":{"count":242},"Trader Joe's":{"count":235},"Feneberg":{"count":58},"denn's Biomarkt":{"count":52},"dm":{"count":114},"Kvickly":{"count":55},"Makro":{"count":140},"Dico":{"count":53},"Nah & Frisch":{"count":73},"Champion":{"count":59},"ICA Supermarket":{"count":51},"Fakta":{"count":235},"Магнит":{"count":1760},"Caprabo":{"count":103},"Famiglia Cooperativa":{"count":64},"Народная 7Я семьЯ":{"count":154},"Esselunga":{"count":85},"Maxima":{"count":102},"Petit Casino":{"count":111},"Wasgau":{"count":60},"Pingo Doce":{"count":253},"Match":{"count":140},"Profi":{"count":60},"Lider":{"count":65},"Unimarc":{"count":177},"The Co-operative Food":{"count":190},"Santa Isabel":{"count":128},"Седьмой континент":{"count":79},"HIT":{"count":59},"Rimi":{"count":106},"Conad":{"count":304},"Фуршет":{"count":76},"Willys":{"count":56},"Farmfoods":{"count":64},"U Express":{"count":51},"Фора":{"count":52},"Dunnes Stores":{"count":73},"Сільпо":{"count":125},"マルエツ":{"count":59},"Piggly Wiggly":{"count":57},"Crai":{"count":54},"El Árbol":{"count":73},"Centre Commercial E. Leclerc":{"count":549},"Foodland":{"count":100},"Super Brugsen":{"count":67},"Дикси":{"count":683},"Пятёрочка":{"count":1344},"Publix":{"count":339},"Føtex":{"count":66},"coop":{"count":73},"Fressnapf":{"count":69},"Coop Konsum":{"count":79},"Carrefour Contact":{"count":83},"No Frills":{"count":105},"Plodine":{"count":52},"ADEG":{"count":68},"Minipreço":{"count":111},"Biedronka":{"count":1335},"Eurospin":{"count":155},"Семья":{"count":62},"Gadis":{"count":53},"Евроопт":{"count":68},"Centra":{"count":51},"Квартал":{"count":82},"New World":{"count":69},"Countdown":{"count":95},"Reliance Fresh":{"count":61},"Stokrotka":{"count":98},"Coop Jednota":{"count":74},"Fred Meyer":{"count":64},"Irma":{"count":58},"Continente":{"count":75},"Price Chopper":{"count":99},"Game":{"count":52},"Soriana":{"count":93},"Alimerka":{"count":64},"Piotr i Paweł":{"count":53},"Перекресток":{"count":312},"Maxima X":{"count":117},"Карусель":{"count":55},"ALDI Nord":{"count":51},"Condis":{"count":67},"Sam's Club":{"count":138},"Копейка":{"count":87},"Géant Casino":{"count":54},"ASDA":{"count":180},"Intermarche":{"count":115},"Stop & Shop":{"count":66},"Food Lion":{"count":216},"Harris Teeter":{"count":92},"Foodworks":{"count":62},"Polo Market":{"count":86},"Лента":{"count":51},"西友 (SEIYU)":{"count":58},"H-E-B":{"count":293},"Атак":{"count":53},"Полушка":{"count":139},"Extra":{"count":82},"Lewiatan":{"count":94},"Sigma":{"count":51},"АТБ":{"count":322},"Społem":{"count":55},"Bodega Aurrera":{"count":82},"Tesco Lotus":{"count":77},"Мария-Ра":{"count":108},"Магнолия":{"count":72},"Магазин":{"count":120},"Монетка":{"count":174},"Hy-Vee":{"count":75},"Walmart Supercenter":{"count":133},"Hannaford":{"count":57},"Wegmans":{"count":83},"業務スーパー":{"count":61},"Norfa XL":{"count":55},"ヨークマート (YorkMart)":{"count":64},"Leclerc Drive":{"count":76}},"electronics":{"Media Markt":{"count":285},"Maplin":{"count":65},"Best Buy":{"count":345},"Future Shop":{"count":73},"Saturn":{"count":134},"Currys":{"count":80},"Radio Shack":{"count":269},"Euronics":{"count":115},"Expert":{"count":123},"Эльдорадо":{"count":184},"Darty":{"count":74},"М.Видео":{"count":89},"ヤマダ電機":{"count":51}},"convenience":{"Shell":{"count":255},"Spar":{"count":1119},"McColl's":{"count":100},"Tesco Express":{"count":426},"Sainsbury's Local":{"count":104},"Aral":{"count":56},"One Stop":{"count":146},"The Co-operative Food":{"count":115},"Londis":{"count":352},"7-Eleven":{"count":4440},"CBA":{"count":135},"Coop":{"count":678},"Sale":{"count":80},"Statoil":{"count":69},"Sheetz":{"count":54},"Konzum":{"count":173},"Siwa":{"count":216},"Mercator":{"count":57},"Esso":{"count":67},"COOP Jednota":{"count":181},"Mac's":{"count":152},"Alepa":{"count":62},"Hasty Market":{"count":54},"K-Market":{"count":54},"Costcutter":{"count":292},"Valintatalo":{"count":62},"Casino":{"count":90},"Franprix":{"count":61},"Circle K":{"count":289},"セブンイレブン":{"count":3011,"tags":{"name:en":"7-Eleven"}},"ローソン":{"count":1596,"tags":{"name:en":"LAWSON"}},"BP":{"count":163},"Tesco":{"count":55},"Petit Casino":{"count":233},"Volg":{"count":116},"Mace":{"count":115},"Mini Market":{"count":272},"Nisa Local":{"count":77},"Dorfladen":{"count":75},"Продукты":{"count":4285},"Mini Stop":{"count":228},"LAWSON":{"count":419},"デイリーヤマザキ":{"count":141},"Biedronka":{"count":83},"Надежда":{"count":56},"Mobil":{"count":66},"Nisa":{"count":51},"Premier":{"count":129},"ABC":{"count":152},"ミニストップ":{"count":316,"tags":{"name:en":"MINISTOP"}},"サンクス":{"count":560,"tags":{"name:en":"sunkus"}},"スリーエフ":{"count":88},"8 à Huit":{"count":61},"Tchibo":{"count":56},"Żabka":{"count":546},"Almacen":{"count":229},"Vival":{"count":194},"FamilyMart":{"count":529},"ファミリーマート":{"count":1608,"tags":{"name:en":"FamilyMart"}},"Carrefour City":{"count":57},"Sunkus":{"count":62},"Casey's General Store":{"count":95},"セブンイレブン(Seven-Eleven)":{"count":65},"Jednota":{"count":58},"Магазин":{"count":915},"Гастроном":{"count":152},"Centra":{"count":111},"Магнит":{"count":701},"サークルK":{"count":538,"tags":{"name:en":"Circle K"}},"Wawa":{"count":135},"Proxi":{"count":123},"Универсам":{"count":78},"Перекресток":{"count":51},"Groszek":{"count":65},"Select":{"count":62},"Večerka":{"count":51},"Potraviny":{"count":249},"Смак":{"count":78},"Эконом":{"count":55},"Березка":{"count":77},"Społem":{"count":93},"Carrefour Express":{"count":84},"Cumberland Farms":{"count":63},"Chevron":{"count":59},"Coop Jednota":{"count":66},"Tesco Lotus Express":{"count":67},"Kiosk":{"count":55},"Sklep spożywczy":{"count":130},"24 часа":{"count":58},"Минимаркет":{"count":102},"Oxxo":{"count":669},"Пятёрочка":{"count":398},"abc":{"count":74},"7/11":{"count":51},"Stewart's":{"count":255},"Продукти":{"count":171},"ローソンストア100 (LAWSON STORE 100)":{"count":85},"Дикси":{"count":119},"Радуга":{"count":86},"ローソンストア100":{"count":76},"เซเว่นอีเลฟเว่น":{"count":185},"Delikatesy Centrum":{"count":53},"Citgo":{"count":62},"Фортуна":{"count":51},"Kum & Go":{"count":59},"Мария-Ра":{"count":76},"Picard":{"count":57},"Four Square":{"count":52},"Визит":{"count":57},"Авоська":{"count":55},"Dollar General":{"count":127},"Studenac":{"count":76},"Central Convenience Store":{"count":55},"Монетка":{"count":62},"продукты":{"count":114},"Теремок":{"count":56},"Kwik Trip":{"count":69},"Кулинария":{"count":55},"全家":{"count":90},"Мечта":{"count":54},"Epicerie":{"count":102},"Кировский":{"count":67},"Food Mart":{"count":117},"Delikatesy":{"count":81},"ポプラ":{"count":54},"Lewiatan":{"count":135},"Продуктовый магазин":{"count":149},"Продуктовый":{"count":84},"セイコーマート (Seicomart)":{"count":72},"Виктория":{"count":70},"Весна":{"count":57},"Mini Market Non-Stop":{"count":60},"QuikTrip":{"count":75},"Копеечка":{"count":51},"Royal Farms":{"count":51},"Alfamart":{"count":103},"Indomaret":{"count":141},"магазин":{"count":171},"全家便利商店":{"count":156},"Boutique":{"count":59},"მარკეტი (Market)":{"count":144},"Stores":{"count":61}},"chemist":{"dm":{"count":939},"Müller":{"count":212},"Schlecker":{"count":187},"Etos":{"count":467},"Bipa":{"count":289},"Rossmann":{"count":1669},"DM Drogeriemarkt":{"count":55},"Ihr Platz":{"count":73},"Douglas":{"count":62},"Kruidvat":{"count":123}},"car_repair":{"Peugeot":{"count":83},"Kwik Fit":{"count":128},"ATU":{"count":261},"Midas":{"count":202},"Feu Vert":{"count":113},"Norauto":{"count":152},"Speedy":{"count":115},"Автозапчасти":{"count":212},"Renault":{"count":171},"Pit Stop":{"count":58},"Jiffy Lube":{"count":198},"Шиномонтаж":{"count":1157},"СТО":{"count":395},"O'Reilly Auto Parts":{"count":81},"Carglass":{"count":112},"шиномонтаж":{"count":62},"Citroen":{"count":51},"Euromaster":{"count":87},"Firestone":{"count":88},"Автосервис":{"count":361},"Advance Auto Parts":{"count":52},"Roady":{"count":56}},"furniture":{"IKEA":{"count":169},"Jysk":{"count":109},"Roller":{"count":78},"Dänisches Bettenlager":{"count":309},"Conforama":{"count":99},"Matratzen Concord":{"count":52},"Мебель":{"count":210},"But":{"count":63}},"doityourself":{"Hornbach":{"count":123},"B&Q":{"count":225},"Hubo":{"count":77},"Mr Bricolage":{"count":88},"Gamma":{"count":111},"OBI":{"count":422},"Lowes":{"count":1152},"Wickes":{"count":123},"Hagebau":{"count":59},"Max Bahr":{"count":79},"Castorama":{"count":153},"Rona":{"count":61},"Home Depot":{"count":865},"Toom Baumarkt":{"count":71},"Homebase":{"count":225},"Baumax":{"count":95},"Lagerhaus":{"count":79},"Bauhaus":{"count":186},"Canadian Tire":{"count":97},"Leroy Merlin":{"count":209},"Hellweg":{"count":58},"Brico":{"count":98},"Bricomarché":{"count":235},"Toom":{"count":67},"Hagebaumarkt":{"count":107},"Praktiker":{"count":122},"Menards":{"count":70},"Weldom":{"count":73},"Bunnings Warehouse":{"count":91},"Ace Hardware":{"count":147},"Home Hardware":{"count":72},"Хозтовары":{"count":86},"Стройматериалы":{"count":197},"Bricorama":{"count":60},"Point P":{"count":59}},"stationery":{"Staples":{"count":299},"McPaper":{"count":83},"Office Depot":{"count":98},"Канцтовары":{"count":63}},"car":{"Skoda":{"count":97},"BMW":{"count":149},"Citroen":{"count":277},"Renault":{"count":382},"Mercedes-Benz":{"count":235},"Volvo":{"count":96},"Ford":{"count":239},"Volkswagen":{"count":217},"Mazda":{"count":105},"Mitsubishi":{"count":73},"Fiat":{"count":93},"Автозапчасти":{"count":277},"Opel":{"count":165},"Audi":{"count":121},"Toyota":{"count":271},"Nissan":{"count":189},"Suzuki":{"count":75},"Honda":{"count":157},"Peugeot":{"count":308},"Шиномонтаж":{"count":259},"Hyundai":{"count":166},"Subaru":{"count":58},"Chevrolet":{"count":86},"Автомагазин":{"count":72}},"clothes":{"Matalan":{"count":90},"KiK":{"count":1219},"H&M":{"count":658},"Urban Outfitters":{"count":63},"Vögele":{"count":132},"Zeeman":{"count":121},"Takko":{"count":515},"Adler":{"count":55},"C&A":{"count":506},"Zara":{"count":217},"Vero Moda":{"count":95},"NKD":{"count":486},"Ernsting's family":{"count":312},"Winners":{"count":65},"River Island":{"count":59},"Next":{"count":176},"Gap":{"count":81},"Adidas":{"count":92},"Woolworths":{"count":117},"Mr Price":{"count":88},"Jet":{"count":61},"Pep":{"count":134},"Edgars":{"count":110},"Ackermans":{"count":91},"Truworths":{"count":65},"Ross":{"count":93},"Burton":{"count":51},"Dorothy Perkins":{"count":53},"Deichmann":{"count":61},"Lindex":{"count":73},"s.Oliver":{"count":56},"Cecil":{"count":51},"Dress Barn":{"count":52},"Old Navy":{"count":174},"Jack & Jones":{"count":52},"Pimkie":{"count":73},"Esprit":{"count":231},"Primark":{"count":92},"Bonita":{"count":155},"Mexx":{"count":67},"Gerry Weber":{"count":71},"Tally Weijl":{"count":70},"Mango":{"count":133},"TK Maxx":{"count":84},"Benetton":{"count":101},"Ulla Popken":{"count":61},"AWG":{"count":66},"Tommy Hilfiger":{"count":75},"New Yorker":{"count":180},"Orsay":{"count":73},"Jeans Fritz":{"count":51},"Charles Vögele":{"count":69},"New Look":{"count":126},"Lacoste":{"count":78},"Etam":{"count":53},"Kiabi":{"count":148},"Jack Wolfskin":{"count":60},"American Apparel":{"count":57},"Men's Wearhouse":{"count":54},"Intimissimi":{"count":52},"United Colors of Benetton":{"count":96},"Jules":{"count":63},"Second Hand":{"count":53},"AOKI":{"count":57},"Calzedonia":{"count":68},"洋服の青山":{"count":100},"Levi's":{"count":63},"Celio":{"count":74},"TJ Maxx":{"count":57},"Promod":{"count":82},"Street One":{"count":72},"ユニクロ":{"count":59},"Banana Republic":{"count":57},"Одежда":{"count":75},"Marshalls":{"count":56},"La Halle":{"count":62},"Peacocks":{"count":89},"しまむら":{"count":60}},"books":{"Bruna":{"count":58},"Waterstones":{"count":90},"Libro":{"count":57},"Barnes & Noble":{"count":267},"Weltbild":{"count":74},"Thalia":{"count":121},"Книги":{"count":112}},"department_store":{"Debenhams":{"count":67},"Canadian Tire":{"count":75},"Karstadt":{"count":64},"Walmart":{"count":517},"Kmart":{"count":143},"Target":{"count":574},"Galeria Kaufhof":{"count":61},"Marks & Spencer":{"count":66},"Big W":{"count":57},"Woolworth":{"count":78},"Универмаг":{"count":72},"Sears":{"count":235},"Walmart Supercenter":{"count":101},"Kohl's":{"count":153},"Macy's":{"count":147},"Sam's Club":{"count":54},"JCPenney":{"count":66}},"alcohol":{"Alko":{"count":145},"The Beer Store":{"count":150},"Systembolaget":{"count":210},"LCBO":{"count":239},"Ароматный мир":{"count":62},"Bargain Booze":{"count":62},"Nicolas":{"count":119},"BWS":{"count":70},"Botilleria":{"count":77},"SAQ":{"count":72},"Gall & Gall":{"count":512},"Живое пиво":{"count":70}},"bakery":{"Kamps":{"count":252},"Banette":{"count":52},"Bäckerei Schmidt":{"count":57},"Anker":{"count":73},"Hofpfisterei":{"count":111},"Greggs":{"count":276},"Oebel":{"count":57},"Boulangerie":{"count":266},"Stadtbäckerei":{"count":57},"Steinecke":{"count":145},"Ihle":{"count":76},"Goldilocks":{"count":59},"Dat Backhus":{"count":67},"K&U":{"count":61},"Der Beck":{"count":96},"Thürmann":{"count":54},"Backwerk":{"count":95},"Schäfer's":{"count":51},"Panaderia":{"count":168},"Goeken backen":{"count":51},"Stadtbäckerei Junge":{"count":51},"Boulangerie Patisserie":{"count":119},"Paul":{"count":81},"Хлеб":{"count":89},"Пекарня":{"count":52},"Кулиничи":{"count":51}},"sports":{"Sports Direct":{"count":57},"Decathlon":{"count":309},"Intersport":{"count":283},"Sports Authority":{"count":75},"Спортмастер":{"count":87},"Sport 2000":{"count":90},"Dick's Sporting Goods":{"count":77}},"variety_store":{"Tedi":{"count":157},"Dollarama":{"count":103},"Family Dollar":{"count":61},"Dollar Tree":{"count":110},"Dollar General":{"count":80}},"pet":{"Fressnapf":{"count":318},"PetSmart":{"count":177},"Das Futterhaus":{"count":69},"Pets at Home":{"count":62},"Petco":{"count":101},"Зоомагазин":{"count":100}},"shoes":{"Deichmann":{"count":622},"Reno":{"count":183},"Ecco":{"count":55},"Clarks":{"count":109},"La Halle aux Chaussures":{"count":69},"Brantano":{"count":71},"Geox":{"count":51},"Salamander":{"count":51},"Обувь":{"count":100},"Payless Shoe Source":{"count":67},"Famous Footwear":{"count":59},"Quick Schuh":{"count":72},"Shoe Zone":{"count":55},"Foot Locker":{"count":82},"Bata":{"count":101},"ЦентрОбувь":{"count":51}},"toys":{"La Grande Récré":{"count":56},"Toys R Us":{"count":151,"tags":{"shop":"toys"}},"Intertoys":{"count":57},"Детский мир":{"count":86},"Игрушки":{"count":58}},"travel_agency":{"Flight Centre":{"count":92},"Thomas Cook":{"count":119}},"jewelry":{"Bijou Brigitte":{"count":57},"Christ":{"count":57},"Swarovski":{"count":74}},"optician":{"Fielmann":{"count":232},"Apollo Optik":{"count":150},"Vision Express":{"count":58},"Оптика":{"count":182},"Optic 2000":{"count":98},"Alain Afflelou":{"count":73},"Specsavers":{"count":124},"Krys":{"count":77},"Atol":{"count":55}},"video":{"Blockbuster":{"count":184},"World of Video":{"count":64}},"mobile_phone":{"Билайн":{"count":128},"ソフトバンクショップ (SoftBank shop)":{"count":255},"Vodafone":{"count":355},"O2":{"count":208},"Carphone Warehouse":{"count":127},"Orange":{"count":246},"Verizon Wireless":{"count":125},"Sprint":{"count":109},"T-Mobile":{"count":175},"МТС":{"count":352},"Евросеть":{"count":506},"Bell":{"count":190},"The Phone House":{"count":83},"SFR":{"count":71},"Связной":{"count":439},"Мегафон":{"count":251},"AT&T":{"count":124},"ドコモショップ (docomo shop)":{"count":114},"au":{"count":65},"Movistar":{"count":77},"Bitė":{"count":72}},"hifi":{},"computer":{"PC World":{"count":55},"DNS":{"count":128}},"hairdresser":{"Klier":{"count":119},"Supercuts":{"count":106},"Hairkiller":{"count":51},"Great Clips":{"count":182},"Парикмахерская":{"count":510},"Стиль":{"count":51},"Franck Provost":{"count":70},"Салон красоты":{"count":70}},"hardware":{"1000 мелочей":{"count":61},"Хозтовары":{"count":151},"Стройматериалы":{"count":54}},"motorcycle":{"Yamaha":{"count":67},"Honda":{"count":69}}}},"addressFormats":[{"format":[["housenumber","street"],["city","postcode"]]},{"countryCodes":["gb"],"format":[["housename"],["housenumber","street"],["city","postcode"]]},{"countryCodes":["ie"],"format":[["housename"],["housenumber","street"],["city"],["postcode"]]},{"countryCodes":["ad","at","ba","be","ch","cz","de","dk","es","fi","gr","hr","is","it","li","nl","no","pl","pt","se","si","sk","sm","va"],"format":[["street","housenumber"],["postcode","city"]]},{"countryCodes":["fr","lu","mo"],"format":[["housenumber","street"],["postcode","city"]]},{"countryCodes":["br"],"format":[["street"],["housenumber","suburb"],["city","postcode"]]},{"countryCodes":["vn"],"format":[["housenumber","street"],["subdistrict"],["district"],["city"],["province","postcode"]]},{"countryCodes":["us"],"format":[["housenumber","street"],["city","state","postcode"]]},{"countryCodes":["ca"],"format":[["housenumber","street"],["city","province","postcode"]]}]};