From a697339e9e617d20e22d40cf3bb5ccca3e19c92e Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 2 Apr 2013 14:27:48 -0700 Subject: [PATCH 01/14] Add railway=station preset --- data/locales.js | 4 ++++ data/presets.yaml | 3 +++ data/presets/presets.json | 12 ++++++++++++ data/presets/presets/railway/station.json | 12 ++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 data/presets/presets/railway/station.json diff --git a/data/locales.js b/data/locales.js index c7de27b73..cb299b379 100644 --- a/data/locales.js +++ b/data/locales.js @@ -1217,6 +1217,10 @@ locale.en = { "name": "Rail", "terms": "" }, + "railway/station": { + "name": "Railway Station", + "terms": "" + }, "railway/subway": { "name": "Subway", "terms": "" diff --git a/data/presets.yaml b/data/presets.yaml index 9f3cc37ae..31217f711 100644 --- a/data/presets.yaml +++ b/data/presets.yaml @@ -668,6 +668,9 @@ en: railway/rail: name: Rail terms: "" + railway/station: + name: Railway Station + terms: "" railway/subway: name: Subway terms: "" diff --git a/data/presets/presets.json b/data/presets/presets.json index 0ae11528c..466775c79 100644 --- a/data/presets/presets.json +++ b/data/presets/presets.json @@ -2702,6 +2702,18 @@ "terms": [], "name": "Rail" }, + "railway/station": { + "icon": "rail", + "geometry": [ + "point", + "vertex", + "area" + ], + "tags": { + "railway": "station" + }, + "name": "Railway Station" + }, "railway/subway": { "icon": "railway-subway", "fields": [ diff --git a/data/presets/presets/railway/station.json b/data/presets/presets/railway/station.json new file mode 100644 index 000000000..7cc779784 --- /dev/null +++ b/data/presets/presets/railway/station.json @@ -0,0 +1,12 @@ +{ + "icon": "rail", + "geometry": [ + "point", + "vertex", + "area" + ], + "tags": { + "railway": "station" + }, + "name": "Railway Station" +} \ No newline at end of file From fb16dc8af6f7c7ecb26509d1cde767b418158257 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 2 Apr 2013 12:17:13 -0700 Subject: [PATCH 02/14] Custom d3 3.1 build (fixes #1232) --- Makefile | 19 + js/id/connection.js | 2 +- js/id/renderer/background.js | 8 +- js/id/renderer/map.js | 20 +- js/lib/d3.v3.js | 12872 +++++++++++++-------------------- package.json | 2 + test/spec/actions/move.js | 12 +- test/spec/svg.js | 2 +- 8 files changed, 4943 insertions(+), 7994 deletions(-) diff --git a/Makefile b/Makefile index 7b6ba7766..28c81f974 100644 --- a/Makefile +++ b/Makefile @@ -87,3 +87,22 @@ clean: translations: node data/update_locales + +D3_FILES = \ + node_modules/d3/src/start.js \ + node_modules/d3/src/arrays/index.js \ + node_modules/d3/src/behavior/behavior.js \ + node_modules/d3/src/behavior/zoom.js \ + node_modules/d3/src/core/index.js \ + node_modules/d3/src/event/index.js \ + node_modules/d3/src/geo/mercator.js \ + node_modules/d3/src/geo/path.js \ + node_modules/d3/src/geo/stream.js \ + node_modules/d3/src/geom/polygon.js \ + node_modules/d3/src/selection/index.js \ + node_modules/d3/src/transition/index.js \ + node_modules/d3/src/xhr/index.js \ + node_modules/d3/src/end.js + +js/lib/d3.v3.js: $(D3_FILES) + node_modules/.bin/smash $(D3_FILES) > $@ diff --git a/js/id/connection.js b/js/id/connection.js index cae450222..d7b9e51a0 100644 --- a/js/id/connection.js +++ b/js/id/connection.js @@ -246,7 +246,7 @@ iD.Connection = function(context) { if (off) return; var scaleExtent = [16, 16], - s = projection.scale(), + s = projection.scale() * 2 * Math.PI, tiles = d3.geo.tile() .scaleExtent(scaleExtent) .scale(s) diff --git a/js/id/renderer/background.js b/js/id/renderer/background.js index 5dc33a7ef..dd727ae91 100644 --- a/js/id/renderer/background.js +++ b/js/id/renderer/background.js @@ -49,14 +49,14 @@ iD.Background = function(backgroundType) { // Update tiles based on current state of `projection`. function background(selection) { - tile.scale(projection.scale()) + tile.scale(projection.scale() * 2 * Math.PI) .translate(projection.translate()); tileOrigin = [ - projection.scale() / 2 - projection.translate()[0], - projection.scale() / 2 - projection.translate()[1]]; + projection.scale() * Math.PI - projection.translate()[0], + projection.scale() * Math.PI - projection.translate()[1]]; - z = Math.max(Math.log(projection.scale()) / Math.log(2) - 8, 0); + z = Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.log(2) - 8, 0); render(selection); } diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js index 03547dc76..4c35f220c 100644 --- a/js/id/renderer/map.js +++ b/js/id/renderer/map.js @@ -1,11 +1,11 @@ iD.Map = function(context) { var dimensions = [1, 1], dispatch = d3.dispatch('move', 'drawn'), - projection = d3.geo.mercator().scale(1024), + projection = d3.geo.mercator().scale(512 / Math.PI), roundedProjection = iD.svg.RoundProjection(projection), zoom = d3.behavior.zoom() .translate(projection.translate()) - .scale(projection.scale()) + .scale(projection.scale() * 2 * Math.PI) .scaleExtent([1024, 256 * Math.pow(2, 24)]) .on('zoom', zoomPan), dblclickEnabled = true, @@ -118,7 +118,7 @@ iD.Map = function(context) { function zoomPan() { if (d3.event && d3.event.sourceEvent.type === 'dblclick') { if (!dblclickEnabled) { - zoom.scale(projection.scale()) + zoom.scale(projection.scale() * 2 * Math.PI) .translate(projection.translate()); return d3.event.sourceEvent.preventDefault(); } @@ -133,7 +133,7 @@ iD.Map = function(context) { projection .translate(d3.event.translate) - .scale(d3.event.scale); + .scale(d3.event.scale / (2 * Math.PI)); var ascale = d3.event.scale; var bscale = transformStart[0]; @@ -202,7 +202,7 @@ iD.Map = function(context) { } transformStart = [ - projection.scale(), + projection.scale() * 2 * Math.PI, projection.translate().slice()]; return map; @@ -216,13 +216,13 @@ iD.Map = function(context) { function pointLocation(p) { var translate = projection.translate(), - scale = projection.scale(); + scale = projection.scale() * 2 * Math.PI; return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale]; } function locationPoint(l) { var translate = projection.translate(), - scale = projection.scale(); + scale = projection.scale() * 2 * Math.PI; return [l[0] * scale + translate[0], l[1] * scale + translate[1]]; } @@ -248,8 +248,8 @@ iD.Map = function(context) { center = pxCenter(), l = pointLocation(center); scale = Math.max(1024, Math.min(256 * Math.pow(2, 24), scale)); - projection.scale(scale); - zoom.scale(projection.scale()); + projection.scale(scale / (2 * Math.PI)); + zoom.scale(scale); var t = projection.translate(); l = locationPoint(l); t[0] += center[0] - l[0]; @@ -312,7 +312,7 @@ iD.Map = function(context) { map.zoom = function(z) { if (!arguments.length) { - return Math.max(Math.log(projection.scale()) / Math.LN2 - 8, 0); + return Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8, 0); } if (setZoom(z)) { diff --git a/js/lib/d3.v3.js b/js/lib/d3.v3.js index a27ded7ce..4fe49a2e7 100644 --- a/js/lib/d3.v3.js +++ b/js/lib/d3.v3.js @@ -1,8176 +1,5106 @@ -d3 = function() { - var π = Math.PI, ε = 1e-6, d3 = { - version: "3.0.8" - }, d3_radians = π / 180, d3_degrees = 180 / π, d3_document = document, d3_window = window; - function d3_target(d) { - return d.target; +d3 = (function(){ + var d3 = {version: "3.1.4"}; // semver +d3.ascending = function(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; +}; +d3.descending = function(a, b) { + return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; +}; +d3.min = function(array, f) { + var i = -1, + n = array.length, + a, + b; + if (arguments.length === 1) { + while (++i < n && ((a = array[i]) == null || a != a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && a > b) a = b; + } else { + while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; } - function d3_source(d) { - return d.source; + return a; +}; +d3.max = function(array, f) { + var i = -1, + n = array.length, + a, + b; + if (arguments.length === 1) { + while (++i < n && ((a = array[i]) == null || a != a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && b > a) a = b; + } else { + while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; } - function d3_acos(x) { - return Math.acos(Math.max(-1, Math.min(1, x))); - } - var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ]; - if (!Date.now) Date.now = function() { - return +new Date(); - }; - try { - d3_document.createElement("div").style.setProperty("opacity", 0, ""); - } catch (error) { - var d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; - d3_style_prototype.setProperty = function(name, value, priority) { - d3_style_setProperty.call(this, name, value + "", priority); - }; - } - function d3_class(ctor, properties) { - try { - for (var key in properties) { - Object.defineProperty(ctor.prototype, key, { - value: properties[key], - enumerable: false - }); - } - } catch (e) { - ctor.prototype = properties; + return a; +}; +d3.extent = function(array, f) { + var i = -1, + n = array.length, + a, + b, + c; + if (arguments.length === 1) { + while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined; + while (++i < n) if ((b = array[i]) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } else { + while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null) { + if (a > b) a = b; + if (c < b) c = b; } } - var d3_array = d3_arraySlice; - function d3_arrayCopy(pseudoarray) { - var i = -1, n = pseudoarray.length, array = []; - while (++i < n) array.push(pseudoarray[i]); - return array; + return [a, c]; +}; +d3.sum = function(array, f) { + var s = 0, + n = array.length, + a, + i = -1; + + if (arguments.length === 1) { + while (++i < n) if (!isNaN(a = +array[i])) s += a; + } else { + while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; } - function d3_arraySlice(pseudoarray) { - return Array.prototype.slice.call(pseudoarray); + + return s; +}; +function d3_number(x) { + return x != null && !isNaN(x); +} + +d3.mean = function(array, f) { + var n = array.length, + a, + m = 0, + i = -1, + j = 0; + if (arguments.length === 1) { + while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; + } else { + while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; } + return j ? m : undefined; +}; +// R-7 per +d3.quantile = function(values, p) { + var H = (values.length - 1) * p + 1, + h = Math.floor(H), + v = +values[h - 1], + e = H - h; + return e ? v + e * (values[h] - v) : v; +}; + +d3.median = function(array, f) { + if (arguments.length > 1) array = array.map(f); + array = array.filter(d3_number); + return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; +}; +d3.bisector = function(f) { + return { + left: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (f.call(a, a[mid], mid) < x) lo = mid + 1; + else hi = mid; + } + return lo; + }, + right: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (x < f.call(a, a[mid], mid)) hi = mid; + else lo = mid + 1; + } + return lo; + } + }; +}; + +var d3_bisector = d3.bisector(function(d) { return d; }); +d3.bisectLeft = d3_bisector.left; +d3.bisect = d3.bisectRight = d3_bisector.right; +d3.shuffle = function(array) { + var m = array.length, t, i; + while (m) { + i = Math.random() * m-- | 0; + t = array[m], array[m] = array[i], array[i] = t; + } + return array; +}; +d3.permute = function(array, indexes) { + var permutes = [], + i = -1, + n = indexes.length; + while (++i < n) permutes[i] = array[indexes[i]]; + return permutes; +}; + +d3.zip = function() { + if (!(n = arguments.length)) return []; + for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m;) { + for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n;) { + zip[j] = arguments[j][i]; + } + } + return zips; +}; + +function d3_zipLength(d) { + return d.length; +} + +d3.transpose = function(matrix) { + return d3.zip.apply(d3, matrix); +}; +d3.keys = function(map) { + var keys = []; + for (var key in map) keys.push(key); + return keys; +}; +d3.values = function(map) { + var values = []; + for (var key in map) values.push(map[key]); + return values; +}; +d3.entries = function(map) { + var entries = []; + for (var key in map) entries.push({key: key, value: map[key]}); + return entries; +}; +d3.merge = function(arrays) { + return Array.prototype.concat.apply([], arrays); +}; +d3.range = function(start, stop, step) { + if (arguments.length < 3) { + step = 1; + if (arguments.length < 2) { + stop = start; + start = 0; + } + } + if ((stop - start) / step === Infinity) throw new Error("infinite range"); + var range = [], + k = d3_range_integerScale(Math.abs(step)), + i = -1, + j; + start *= k, stop *= k, step *= k; + if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); + else while ((j = start + step * ++i) < stop) range.push(j / k); + return range; +}; + +function d3_range_integerScale(x) { + var k = 1; + while (x * k % 1) k *= 10; + return k; +} +function d3_class(ctor, properties) { try { - d3_array(d3_document.documentElement.childNodes)[0].nodeType; + for (var key in properties) { + Object.defineProperty(ctor.prototype, key, { + value: properties[key], + enumerable: false + }); + } } catch (e) { - d3_array = d3_arrayCopy; + ctor.prototype = properties; } - var d3_arraySubclass = [].__proto__ ? function(array, prototype) { - array.__proto__ = prototype; - } : function(array, prototype) { - for (var property in prototype) array[property] = prototype[property]; - }; - d3.map = function(object) { - var map = new d3_Map(); - for (var key in object) map.set(key, object[key]); - return map; - }; - function d3_Map() {} - d3_class(d3_Map, { - has: function(key) { - return d3_map_prefix + key in this; - }, - get: function(key) { - return this[d3_map_prefix + key]; - }, - set: function(key, value) { - return this[d3_map_prefix + key] = value; - }, - remove: function(key) { - key = d3_map_prefix + key; - return key in this && delete this[key]; - }, - keys: function() { - var keys = []; - this.forEach(function(key) { - keys.push(key); - }); - return keys; - }, - values: function() { - var values = []; - this.forEach(function(key, value) { - values.push(value); - }); - return values; - }, - entries: function() { - var entries = []; - this.forEach(function(key, value) { - entries.push({ - key: key, - value: value - }); - }); - return entries; - }, - forEach: function(f) { - for (var key in this) { - if (key.charCodeAt(0) === d3_map_prefixCode) { - f.call(this, key.substring(1), this[key]); - } +} + +d3.map = function(object) { + var map = new d3_Map; + for (var key in object) map.set(key, object[key]); + return map; +}; + +function d3_Map() {} + +d3_class(d3_Map, { + has: function(key) { + return d3_map_prefix + key in this; + }, + get: function(key) { + return this[d3_map_prefix + key]; + }, + set: function(key, value) { + return this[d3_map_prefix + key] = value; + }, + remove: function(key) { + key = d3_map_prefix + key; + return key in this && delete this[key]; + }, + keys: function() { + var keys = []; + this.forEach(function(key) { keys.push(key); }); + return keys; + }, + values: function() { + var values = []; + this.forEach(function(key, value) { values.push(value); }); + return values; + }, + entries: function() { + var entries = []; + this.forEach(function(key, value) { entries.push({key: key, value: value}); }); + return entries; + }, + forEach: function(f) { + for (var key in this) { + if (key.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, key.substring(1), this[key]); } } - }); - var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0); - d3.set = function(array) { - var set = new d3_Set(); - if (array) for (var i = 0; i < array.length; i++) set.add(array[i]); - return set; - }; - function d3_Set() {} - d3_class(d3_Set, { - has: function(value) { - return d3_map_prefix + value in this; - }, - add: function(value) { - this[d3_map_prefix + value] = true; - return value; - }, - remove: function(value) { - value = d3_map_prefix + value; - return value in this && delete this[value]; - }, - values: function() { - var values = []; - this.forEach(function(value) { - values.push(value); - }); - return values; - }, - forEach: function(f) { - for (var value in this) { - if (value.charCodeAt(0) === d3_map_prefixCode) { - f.call(this, value.substring(1)); - } - } - } - }); - function d3_identity(d) { - return d; } - function d3_true() { - return true; - } - function d3_functor(v) { - return typeof v === "function" ? v : function() { - return v; - }; - } - d3.functor = d3_functor; - d3.rebind = function(target, source) { - var i = 1, n = arguments.length, method; - while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); - return target; - }; - function d3_rebind(target, source, method) { - return function() { - var value = method.apply(source, arguments); - return value === source ? target : value; - }; - } - d3.ascending = function(a, b) { - return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; - }; - d3.descending = function(a, b) { - return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; - }; - d3.mean = function(array, f) { - var n = array.length, a, m = 0, i = -1, j = 0; - if (arguments.length === 1) { - while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; - } else { - while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; - } - return j ? m : undefined; - }; - d3.median = function(array, f) { - if (arguments.length > 1) array = array.map(f); - array = array.filter(d3_number); - return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; - }; - d3.min = function(array, f) { - var i = -1, n = array.length, a, b; - if (arguments.length === 1) { - while (++i < n && ((a = array[i]) == null || a != a)) a = undefined; - while (++i < n) if ((b = array[i]) != null && a > b) a = b; - } else { - while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined; - while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; - } - return a; - }; - d3.max = function(array, f) { - var i = -1, n = array.length, a, b; - if (arguments.length === 1) { - while (++i < n && ((a = array[i]) == null || a != a)) a = undefined; - while (++i < n) if ((b = array[i]) != null && b > a) a = b; - } else { - while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined; - while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; - } - return a; - }; - d3.extent = function(array, f) { - var i = -1, n = array.length, a, b, c; - if (arguments.length === 1) { - while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined; - while (++i < n) if ((b = array[i]) != null) { - if (a > b) a = b; - if (c < b) c = b; - } - } else { - while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined; - while (++i < n) if ((b = f.call(array, array[i], i)) != null) { - if (a > b) a = b; - if (c < b) c = b; - } - } - return [ a, c ]; - }; - d3.random = { - normal: function(µ, σ) { - var n = arguments.length; - if (n < 2) σ = 1; - if (n < 1) µ = 0; - return function() { - var x, y, r; - do { - x = Math.random() * 2 - 1; - y = Math.random() * 2 - 1; - r = x * x + y * y; - } while (!r || r > 1); - return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); - }; - }, - logNormal: function() { - var random = d3.random.normal.apply(d3, arguments); - return function() { - return Math.exp(random()); - }; - }, - irwinHall: function(m) { - return function() { - for (var s = 0, j = 0; j < m; j++) s += Math.random(); - return s / m; - }; - } - }; - function d3_number(x) { - return x != null && !isNaN(x); - } - d3.sum = function(array, f) { - var s = 0, n = array.length, a, i = -1; - if (arguments.length === 1) { - while (++i < n) if (!isNaN(a = +array[i])) s += a; - } else { - while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; - } - return s; - }; - d3.quantile = function(values, p) { - var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; - return e ? v + e * (values[h] - v) : v; - }; - d3.shuffle = function(array) { - var m = array.length, t, i; - while (m) { - i = Math.random() * m-- | 0; - t = array[m], array[m] = array[i], array[i] = t; - } - return array; - }; - d3.transpose = function(matrix) { - return d3.zip.apply(d3, matrix); - }; - d3.zip = function() { - if (!(n = arguments.length)) return []; - for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { - for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { - zip[j] = arguments[j][i]; - } - } - return zips; - }; - function d3_zipLength(d) { - return d.length; - } - d3.bisector = function(f) { - return { - left: function(a, x, lo, hi) { - if (arguments.length < 3) lo = 0; - if (arguments.length < 4) hi = a.length; - while (lo < hi) { - var mid = lo + hi >>> 1; - if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid; - } - return lo; - }, - right: function(a, x, lo, hi) { - if (arguments.length < 3) lo = 0; - if (arguments.length < 4) hi = a.length; - while (lo < hi) { - var mid = lo + hi >>> 1; - if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1; - } - return lo; - } - }; - }; - var d3_bisector = d3.bisector(function(d) { - return d; - }); - d3.bisectLeft = d3_bisector.left; - d3.bisect = d3.bisectRight = d3_bisector.right; - d3.nest = function() { - var nest = {}, keys = [], sortKeys = [], sortValues, rollup; - function map(mapType, array, depth) { - if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; - var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; - while (++i < n) { - if (values = valuesByKey.get(keyValue = key(object = array[i]))) { - values.push(object); - } else { - valuesByKey.set(keyValue, [ object ]); - } - } - if (mapType) { - object = mapType(); - setter = function(keyValue, values) { - object.set(keyValue, map(mapType, values, depth)); - }; +}); + +var d3_map_prefix = "\0", // prevent collision with built-ins + d3_map_prefixCode = d3_map_prefix.charCodeAt(0); + +d3.nest = function() { + var nest = {}, + keys = [], + sortKeys = [], + sortValues, + rollup; + + function map(mapType, array, depth) { + if (depth >= keys.length) return rollup + ? rollup.call(nest, array) : (sortValues + ? array.sort(sortValues) + : array); + + var i = -1, + n = array.length, + key = keys[depth++], + keyValue, + object, + setter, + valuesByKey = new d3_Map, + values; + + while (++i < n) { + if (values = valuesByKey.get(keyValue = key(object = array[i]))) { + values.push(object); } else { - object = {}; - setter = function(keyValue, values) { - object[keyValue] = map(mapType, values, depth); - }; + valuesByKey.set(keyValue, [object]); } - valuesByKey.forEach(setter); - return object; } - function entries(map, depth) { - if (depth >= keys.length) return map; - var array = [], sortKey = sortKeys[depth++]; - map.forEach(function(key, keyMap) { - array.push({ - key: key, - values: entries(keyMap, depth) - }); - }); - return sortKey ? array.sort(function(a, b) { - return sortKey(a.key, b.key); - }) : array; + + if (mapType) { + object = mapType(); + setter = function(keyValue, values) { + object.set(keyValue, map(mapType, values, depth)); + }; + } else { + object = {}; + setter = function(keyValue, values) { + object[keyValue] = map(mapType, values, depth); + }; } - nest.map = function(array, mapType) { - return map(mapType, array, 0); - }; - nest.entries = function(array) { - return entries(map(d3.map, array, 0), 0); - }; - nest.key = function(d) { - keys.push(d); - return nest; - }; - nest.sortKeys = function(order) { - sortKeys[keys.length - 1] = order; - return nest; - }; - nest.sortValues = function(order) { - sortValues = order; - return nest; - }; - nest.rollup = function(f) { - rollup = f; - return nest; - }; + + valuesByKey.forEach(setter); + return object; + } + + function entries(map, depth) { + if (depth >= keys.length) return map; + + var array = [], + sortKey = sortKeys[depth++]; + + map.forEach(function(key, keyMap) { + array.push({key: key, values: entries(keyMap, depth)}); + }); + + return sortKey + ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) + : array; + } + + nest.map = function(array, mapType) { + return map(mapType, array, 0); + }; + + nest.entries = function(array) { + return entries(map(d3.map, array, 0), 0); + }; + + nest.key = function(d) { + keys.push(d); return nest; }; - d3.keys = function(map) { - var keys = []; - for (var key in map) keys.push(key); - return keys; + + // Specifies the order for the most-recently specified key. + // Note: only applies to entries. Map keys are unordered! + nest.sortKeys = function(order) { + sortKeys[keys.length - 1] = order; + return nest; }; - d3.values = function(map) { + + // Specifies the order for leaf values. + // Applies to both maps and entries array. + nest.sortValues = function(order) { + sortValues = order; + return nest; + }; + + nest.rollup = function(f) { + rollup = f; + return nest; + }; + + return nest; +}; + +d3.set = function(array) { + var set = new d3_Set(); + if (array) for (var i = 0; i < array.length; i++) set.add(array[i]); + return set; +}; + +function d3_Set() {} + +d3_class(d3_Set, { + has: function(value) { + return d3_map_prefix + value in this; + }, + add: function(value) { + this[d3_map_prefix + value] = true; + return value; + }, + remove: function(value) { + value = d3_map_prefix + value; + return value in this && delete this[value]; + }, + values: function() { var values = []; - for (var key in map) values.push(map[key]); + this.forEach(function(value) { + values.push(value); + }); return values; - }; - d3.entries = function(map) { - var entries = []; - for (var key in map) entries.push({ - key: key, - value: map[key] - }); - return entries; - }; - d3.permute = function(array, indexes) { - var permutes = [], i = -1, n = indexes.length; - while (++i < n) permutes[i] = array[indexes[i]]; - return permutes; - }; - d3.merge = function(arrays) { - return Array.prototype.concat.apply([], arrays); - }; - function d3_collapse(s) { - return s.trim().replace(/\s+/g, " "); - } - d3.range = function(start, stop, step) { - if (arguments.length < 3) { - step = 1; - if (arguments.length < 2) { - stop = start; - start = 0; + }, + forEach: function(f) { + for (var value in this) { + if (value.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, value.substring(1)); } } - if ((stop - start) / step === Infinity) throw new Error("infinite range"); - var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j; - start *= k, stop *= k, step *= k; - if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); - return range; - }; - function d3_range_integerScale(x) { - var k = 1; - while (x * k % 1) k *= 10; - return k; } - d3.requote = function(s) { - return s.replace(d3_requote_re, "\\$&"); +}); +d3.behavior = {}; +var d3_document = document, + d3_window = window; +// Copies a variable number of methods from source to target. +d3.rebind = function(target, source) { + var i = 1, n = arguments.length, method; + while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); + return target; +}; + +// Method is assumed to be a standard D3 getter-setter: +// If passed with no arguments, gets the value. +// If passed with arguments, sets the value and returns the target. +function d3_rebind(target, source, method) { + return function() { + var value = method.apply(source, arguments); + return value === source ? target : value; }; - var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; - d3.round = function(x, n) { - return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); - }; - d3.xhr = function(url, mimeType, callback) { - var xhr = {}, dispatch = d3.dispatch("progress", "load", "error"), headers = {}, response = d3_identity, request = new (d3_window.XDomainRequest && /^(http(s)?:)?\/\//.test(url) ? XDomainRequest : XMLHttpRequest)(); - "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { - request.readyState > 3 && respond(); - }; - function respond() { - var s = request.status; - !s && request.responseText || s >= 200 && s < 300 || s === 304 ? dispatch.load.call(xhr, response.call(xhr, request)) : dispatch.error.call(xhr, request); +} + +d3.dispatch = function() { + var dispatch = new d3_dispatch, + i = -1, + n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + return dispatch; +}; + +function d3_dispatch() {} + +d3_dispatch.prototype.on = function(type, listener) { + var i = type.indexOf("."), + name = ""; + + // Extract optional namespace, e.g., "click.foo" + if (i >= 0) { + name = type.substring(i + 1); + type = type.substring(0, i); + } + + if (type) return arguments.length < 2 + ? this[type].on(name) + : this[type].on(name, listener); + + if (arguments.length === 2) { + if (listener == null) for (type in this) { + if (this.hasOwnProperty(type)) this[type].on(name, null); } - request.onprogress = function(event) { - var o = d3.event; - d3.event = event; + return this; + } +}; + +function d3_dispatch_event(dispatch) { + var listeners = [], + listenerByName = new d3_Map; + + function event() { + var z = listeners, // defensive reference + i = -1, + n = z.length, + l; + while (++i < n) if (l = z[i].on) l.apply(this, arguments); + return dispatch; + } + + event.on = function(name, listener) { + var l = listenerByName.get(name), + i; + + // return the current listener, if any + if (arguments.length < 2) return l && l.on; + + // remove the old listener, if any (with copy-on-write) + if (l) { + l.on = null; + listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); + listenerByName.remove(name); + } + + // add the new listener, if any + if (listener) listeners.push(listenerByName.set(name, {on: listener})); + + return dispatch; + }; + + return event; +} + +d3.event = null; + +function d3_eventCancel() { + d3.event.stopPropagation(); + d3.event.preventDefault(); +} + +function d3_eventSource() { + var e = d3.event, s; + while (s = e.sourceEvent) e = s; + return e; +} + +// Like d3.dispatch, but for custom events abstracting native UI events. These +// events have a target component (such as a brush), a target element (such as +// the svg:g element containing the brush) and the standard arguments `d` (the +// target element's data) and `i` (the selection index of the target element). +function d3_eventDispatch(target) { + var dispatch = new d3_dispatch, + i = 0, + n = arguments.length; + + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + + // Creates a dispatch context for the specified `thiz` (typically, the target + // DOM element that received the source event) and `argumentz` (typically, the + // data `d` and index `i` of the target element). The returned function can be + // used to dispatch an event to any registered listeners; the function takes a + // single argument as input, being the event to dispatch. The event must have + // a "type" attribute which corresponds to a type registered in the + // constructor. This context will automatically populate the "sourceEvent" and + // "target" attributes of the event, as well as setting the `d3.event` global + // for the duration of the notification. + dispatch.of = function(thiz, argumentz) { + return function(e1) { try { - dispatch.progress.call(xhr, request); + var e0 = + e1.sourceEvent = d3.event; + e1.target = target; + d3.event = e1; + dispatch[e1.type].apply(thiz, argumentz); } finally { - d3.event = o; + d3.event = e0; } }; - xhr.header = function(name, value) { - name = (name + "").toLowerCase(); - if (arguments.length < 2) return headers[name]; - if (value == null) delete headers[name]; else headers[name] = value + ""; - return xhr; - }; - xhr.mimeType = function(value) { - if (!arguments.length) return mimeType; - mimeType = value == null ? null : value + ""; - return xhr; - }; - xhr.response = function(value) { - response = value; - return xhr; - }; - [ "get", "post" ].forEach(function(method) { - xhr[method] = function() { - return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); - }; - }); - xhr.send = function(method, data, callback) { - if (arguments.length === 2 && typeof data === "function") callback = data, data = null; - request.open(method, url, true); - if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; - if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); - if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); - if (callback != null) xhr.on("error", callback).on("load", function(request) { - callback(null, request); - }); - request.send(data == null ? null : data); - return xhr; - }; - xhr.abort = function() { - request.abort(); - return xhr; - }; - d3.rebind(xhr, dispatch, "on"); - if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, - mimeType = null; - return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); }; - function d3_xhr_fixCallback(callback) { - return callback.length === 1 ? function(error, request) { - callback(error == null ? request : null); - } : callback; - } - d3.text = function() { - return d3.xhr.apply(d3, arguments).response(d3_text); - }; - function d3_text(request) { - return request.responseText; - } - d3.json = function(url, callback) { - return d3.xhr(url, "application/json", callback).response(d3_json); - }; - function d3_json(request) { - return JSON.parse(request.responseText); - } - d3.html = function(url, callback) { - return d3.xhr(url, "text/html", callback).response(d3_html); - }; - function d3_html(request) { - var range = d3_document.createRange(); - range.selectNode(d3_document.body); - return range.createContextualFragment(request.responseText); - } - d3.xml = function() { - return d3.xhr.apply(d3, arguments).response(d3_xml); - }; - function d3_xml(request) { - return request.responseXML; - } - var d3_nsPrefix = { - svg: "http://www.w3.org/2000/svg", - xhtml: "http://www.w3.org/1999/xhtml", - xlink: "http://www.w3.org/1999/xlink", - xml: "http://www.w3.org/XML/1998/namespace", - xmlns: "http://www.w3.org/2000/xmlns/" - }; - d3.ns = { - prefix: d3_nsPrefix, - qualify: function(name) { - var i = name.indexOf(":"), prefix = name; - if (i >= 0) { - prefix = name.substring(0, i); - name = name.substring(i + 1); - } - return d3_nsPrefix.hasOwnProperty(prefix) ? { - space: d3_nsPrefix[prefix], - local: name - } : name; - } - }; - d3.dispatch = function() { - var dispatch = new d3_dispatch(), i = -1, n = arguments.length; - while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); - return dispatch; - }; - function d3_dispatch() {} - d3_dispatch.prototype.on = function(type, listener) { - var i = type.indexOf("."), name = ""; - if (i > 0) { - name = type.substring(i + 1); - type = type.substring(0, i); - } - return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); - }; - function d3_dispatch_event(dispatch) { - var listeners = [], listenerByName = new d3_Map(); - function event() { - var z = listeners, i = -1, n = z.length, l; - while (++i < n) if (l = z[i].on) l.apply(this, arguments); - return dispatch; - } - event.on = function(name, listener) { - var l = listenerByName.get(name), i; - if (arguments.length < 2) return l && l.on; - if (l) { - l.on = null; - listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); - listenerByName.remove(name); - } - if (listener) listeners.push(listenerByName.set(name, { - on: listener - })); - return dispatch; - }; - return event; - } - d3.format = function(specifier) { - var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", basePrefix = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false; - if (precision) precision = +precision.substring(1); - if (zfill || fill === "0" && align === "=") { - zfill = fill = "0"; - align = "="; - if (comma) width -= Math.floor((width - 1) / 4); - } - switch (type) { - case "n": - comma = true; - type = "g"; - break; - case "%": - scale = 100; - suffix = "%"; - type = "f"; - break; + return dispatch; +} - case "p": - scale = 100; - suffix = "%"; - type = "r"; - break; +d3.mouse = function(container) { + return d3_mousePoint(container, d3_eventSource()); +}; - case "b": - case "o": - case "x": - case "X": - if (basePrefix) basePrefix = "0" + type.toLowerCase(); +// https://bugs.webkit.org/show_bug.cgi?id=44083 +var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0; - case "c": - case "d": - integer = true; - precision = 0; - break; - - case "s": - scale = -1; - type = "r"; - break; +function d3_mousePoint(container, e) { + var svg = container.ownerSVGElement || container; + if (svg.createSVGPoint) { + var point = svg.createSVGPoint(); + if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) { + svg = d3.select(d3_document.body).append("svg") + .style("position", "absolute") + .style("top", 0) + .style("left", 0); + var ctm = svg[0][0].getScreenCTM(); + d3_mouse_bug44083 = !(ctm.f || ctm.e); + svg.remove(); } - if (basePrefix === "#") basePrefix = ""; - if (type == "r" && !precision) type = "g"; - type = d3_format_types.get(type) || d3_format_typeDefault; - var zcomma = zfill && comma; - return function(value) { - if (integer && value % 1) return ""; - var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign; - if (scale < 0) { - var prefix = d3.formatPrefix(value, precision); - value = prefix.scale(value); - suffix = prefix.symbol; + if (d3_mouse_bug44083) { + point.x = e.pageX; + point.y = e.pageY; + } else { + point.x = e.clientX; + point.y = e.clientY; + } + point = point.matrixTransform(container.getScreenCTM().inverse()); + return [point.x, point.y]; + } + var rect = container.getBoundingClientRect(); + return [e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop]; +}; + +var d3_array = d3_arraySlice; // conversion for NodeLists + +function d3_arrayCopy(pseudoarray) { + var i = -1, n = pseudoarray.length, array = []; + while (++i < n) array.push(pseudoarray[i]); + return array; +} + +function d3_arraySlice(pseudoarray) { + return Array.prototype.slice.call(pseudoarray); +} + +try { + d3_array(d3_document.documentElement.childNodes)[0].nodeType; +} catch(e) { + d3_array = d3_arrayCopy; +} + +var d3_arraySubclass = [].__proto__? + +// Until ECMAScript supports array subclassing, prototype injection works well. +function(array, prototype) { + array.__proto__ = prototype; +}: + +// And if your browser doesn't support __proto__, we'll use direct extension. +function(array, prototype) { + for (var property in prototype) array[property] = prototype[property]; +}; + +d3.touches = function(container, touches) { + if (arguments.length < 2) touches = d3_eventSource().touches; + return touches ? d3_array(touches).map(function(touch) { + var point = d3_mousePoint(container, touch); + point.identifier = touch.identifier; + return point; + }) : []; +}; + +function d3_selection(groups) { + d3_arraySubclass(groups, d3_selectionPrototype); + return groups; +} + +var d3_select = function(s, n) { return n.querySelector(s); }, + d3_selectAll = function(s, n) { return n.querySelectorAll(s); }, + d3_selectRoot = d3_document.documentElement, + d3_selectMatcher = d3_selectRoot.matchesSelector || d3_selectRoot.webkitMatchesSelector || d3_selectRoot.mozMatchesSelector || d3_selectRoot.msMatchesSelector || d3_selectRoot.oMatchesSelector, + d3_selectMatches = function(n, s) { return d3_selectMatcher.call(n, s); }; + +// Prefer Sizzle, if available. +if (typeof Sizzle === "function") { + d3_select = function(s, n) { return Sizzle(s, n)[0] || null; }; + d3_selectAll = function(s, n) { return Sizzle.uniqueSort(Sizzle(s, n)); }; + d3_selectMatches = Sizzle.matchesSelector; +} + +var d3_selectionPrototype = []; + +d3.selection = function() { + return d3_selectionRoot; +}; + +d3.selection.prototype = d3_selectionPrototype; + + +d3_selectionPrototype.select = function(selector) { + var subgroups = [], + subgroup, + subnode, + group, + node; + + if (typeof selector !== "function") selector = d3_selection_selector(selector); + + for (var j = -1, m = this.length; ++j < m;) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = -1, n = group.length; ++i < n;) { + if (node = group[i]) { + subgroup.push(subnode = selector.call(node, node.__data__, i)); + if (subnode && "__data__" in node) subnode.__data__ = node.__data__; } else { - value *= scale; + subgroup.push(null); } - value = type(value, precision); - if (!zfill && comma) value = d3_format_group(value); - var length = basePrefix.length + value.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; - if (zcomma) value = d3_format_group(padding + value); - if (d3_format_decimalPoint) value.replace(".", d3_format_decimalPoint); - negative += basePrefix; - return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix; - }; - }; - var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/; - var d3_format_types = d3.map({ - b: function(x) { - return x.toString(2); - }, - c: function(x) { - return String.fromCharCode(x); - }, - o: function(x) { - return x.toString(8); - }, - x: function(x) { - return x.toString(16); - }, - X: function(x) { - return x.toString(16).toUpperCase(); - }, - g: function(x, p) { - return x.toPrecision(p); - }, - e: function(x, p) { - return x.toExponential(p); - }, - f: function(x, p) { - return x.toFixed(p); - }, - r: function(x, p) { - return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p)))); } - }); - function d3_format_precision(x, p) { - return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); } - function d3_format_typeDefault(x) { - return x + ""; - } - var d3_format_group = d3_identity; - if (d3_format_grouping) { - var d3_format_groupingLength = d3_format_grouping.length; - d3_format_group = function(value) { - var i = value.lastIndexOf("."), f = i >= 0 ? "." + value.substring(i + 1) : (i = value.length, - ""), t = [], j = 0, g = d3_format_grouping[0]; - while (i > 0 && g > 0) { - t.push(value.substring(i -= g, i + g)); - g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength]; + + return d3_selection(subgroups); +}; + +function d3_selection_selector(selector) { + return function() { + return d3_select(selector, this); + }; +} + +d3_selectionPrototype.selectAll = function(selector) { + var subgroups = [], + subgroup, + node; + + if (typeof selector !== "function") selector = d3_selection_selectorAll(selector); + + for (var j = -1, m = this.length; ++j < m;) { + for (var group = this[j], i = -1, n = group.length; ++i < n;) { + if (node = group[i]) { + subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i))); + subgroup.parentNode = node; } - return t.reverse().join(d3_format_thousandsSeparator || "") + f; - }; + } } - var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); - d3.formatPrefix = function(value, precision) { - var i = 0; + + return d3_selection(subgroups); +}; + +function d3_selection_selectorAll(selector) { + return function() { + return d3_selectAll(selector, this); + }; +} +var d3_nsPrefix = { + svg: "http://www.w3.org/2000/svg", + xhtml: "http://www.w3.org/1999/xhtml", + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" +}; + +d3.ns = { + prefix: d3_nsPrefix, + qualify: function(name) { + var i = name.indexOf(":"), + prefix = name; + if (i >= 0) { + prefix = name.substring(0, i); + name = name.substring(i + 1); + } + return d3_nsPrefix.hasOwnProperty(prefix) + ? {space: d3_nsPrefix[prefix], local: name} + : name; + } +}; + +d3_selectionPrototype.attr = function(name, value) { + if (arguments.length < 2) { + + // For attr(string), return the attribute value for the first node. + if (typeof name === "string") { + var node = this.node(); + name = d3.ns.qualify(name); + return name.local + ? node.getAttributeNS(name.space, name.local) + : node.getAttribute(name); + } + + // For attr(object), the object specifies the names and values of the + // attributes to set or remove. The values may be functions that are + // evaluated for each element. + for (value in name) this.each(d3_selection_attr(value, name[value])); + return this; + } + + return this.each(d3_selection_attr(name, value)); +}; + +function d3_selection_attr(name, value) { + name = d3.ns.qualify(name); + + // For attr(string, null), remove the attribute with the specified name. + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + + // For attr(string, string), set the attribute with the specified name. + function attrConstant() { + this.setAttribute(name, value); + } + function attrConstantNS() { + this.setAttributeNS(name.space, name.local, value); + } + + // For attr(string, function), evaluate the function for each element, and set + // or remove the attribute as appropriate. + function attrFunction() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttribute(name); + else this.setAttribute(name, x); + } + function attrFunctionNS() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttributeNS(name.space, name.local); + else this.setAttributeNS(name.space, name.local, x); + } + + return value == null + ? (name.local ? attrNullNS : attrNull) : (typeof value === "function" + ? (name.local ? attrFunctionNS : attrFunction) + : (name.local ? attrConstantNS : attrConstant)); +} +function d3_collapse(s) { + return s.trim().replace(/\s+/g, " "); +} +d3.requote = function(s) { + return s.replace(d3_requote_re, "\\$&"); +}; + +var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; + +d3_selectionPrototype.classed = function(name, value) { + if (arguments.length < 2) { + + // For classed(string), return true only if the first node has the specified + // class or classes. Note that even if the browser supports DOMTokenList, it + // probably doesn't support it on SVG elements (which can be animated). + if (typeof name === "string") { + var node = this.node(), + n = (name = name.trim().split(/^|\s+/g)).length, + i = -1; + if (value = node.classList) { + while (++i < n) if (!value.contains(name[i])) return false; + } else { + value = node.getAttribute("class"); + while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; + } + return true; + } + + // For classed(object), the object specifies the names of classes to add or + // remove. The values may be functions that are evaluated for each element. + for (value in name) this.each(d3_selection_classed(value, name[value])); + return this; + } + + // Otherwise, both a name and a value are specified, and are handled as below. + return this.each(d3_selection_classed(name, value)); +}; + +function d3_selection_classedRe(name) { + return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); +} + +// Multiple class names are allowed (e.g., "foo bar"). +function d3_selection_classed(name, value) { + name = name.trim().split(/\s+/).map(d3_selection_classedName); + var n = name.length; + + function classedConstant() { + var i = -1; + while (++i < n) name[i](this, value); + } + + // When the value is a function, the function is still evaluated only once per + // element even if there are multiple class names. + function classedFunction() { + var i = -1, x = value.apply(this, arguments); + while (++i < n) name[i](this, x); + } + + return typeof value === "function" + ? classedFunction + : classedConstant; +} + +function d3_selection_classedName(name) { + var re = d3_selection_classedRe(name); + return function(node, value) { + if (c = node.classList) return value ? c.add(name) : c.remove(name); + var c = node.getAttribute("class") || ""; if (value) { - if (value < 0) value *= -1; - if (precision) value = d3.round(value, d3_format_precision(value, precision)); - i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); - i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); - } - return d3_formatPrefixes[8 + i / 3]; - }; - function d3_formatPrefix(d, i) { - var k = Math.pow(10, Math.abs(8 - i) * 3); - return { - scale: i > 8 ? function(d) { - return d / k; - } : function(d) { - return d * k; - }, - symbol: d - }; - } - var d3_ease_default = function() { - return d3_identity; - }; - var d3_ease = d3.map({ - linear: d3_ease_default, - poly: d3_ease_poly, - quad: function() { - return d3_ease_quad; - }, - cubic: function() { - return d3_ease_cubic; - }, - sin: function() { - return d3_ease_sin; - }, - exp: function() { - return d3_ease_exp; - }, - circle: function() { - return d3_ease_circle; - }, - elastic: d3_ease_elastic, - back: d3_ease_back, - bounce: function() { - return d3_ease_bounce; - } - }); - var d3_ease_mode = d3.map({ - "in": d3_identity, - out: d3_ease_reverse, - "in-out": d3_ease_reflect, - "out-in": function(f) { - return d3_ease_reflect(d3_ease_reverse(f)); - } - }); - d3.ease = function(name) { - var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in"; - t = d3_ease.get(t) || d3_ease_default; - m = d3_ease_mode.get(m) || d3_identity; - return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); - }; - function d3_ease_clamp(f) { - return function(t) { - return t <= 0 ? 0 : t >= 1 ? 1 : f(t); - }; - } - function d3_ease_reverse(f) { - return function(t) { - return 1 - f(1 - t); - }; - } - function d3_ease_reflect(f) { - return function(t) { - return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); - }; - } - function d3_ease_quad(t) { - return t * t; - } - function d3_ease_cubic(t) { - return t * t * t; - } - function d3_ease_cubicInOut(t) { - if (t <= 0) return 0; - if (t >= 1) return 1; - var t2 = t * t, t3 = t2 * t; - return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); - } - function d3_ease_poly(e) { - return function(t) { - return Math.pow(t, e); - }; - } - function d3_ease_sin(t) { - return 1 - Math.cos(t * π / 2); - } - function d3_ease_exp(t) { - return Math.pow(2, 10 * (t - 1)); - } - function d3_ease_circle(t) { - return 1 - Math.sqrt(1 - t * t); - } - function d3_ease_elastic(a, p) { - var s; - if (arguments.length < 2) p = .45; - if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); else a = 1, s = p / 4; - return function(t) { - return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p); - }; - } - function d3_ease_back(s) { - if (!s) s = 1.70158; - return function(t) { - return t * t * ((s + 1) * t - s); - }; - } - function d3_ease_bounce(t) { - return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; - } - d3.event = null; - function d3_eventCancel() { - d3.event.stopPropagation(); - d3.event.preventDefault(); - } - function d3_eventSource() { - var e = d3.event, s; - while (s = e.sourceEvent) e = s; - return e; - } - function d3_eventDispatch(target) { - var dispatch = new d3_dispatch(), i = 0, n = arguments.length; - while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); - dispatch.of = function(thiz, argumentz) { - return function(e1) { - try { - var e0 = e1.sourceEvent = d3.event; - e1.target = target; - d3.event = e1; - dispatch[e1.type].apply(thiz, argumentz); - } finally { - d3.event = e0; - } - }; - }; - return dispatch; - } - d3.transform = function(string) { - var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); - return (d3.transform = function(string) { - g.setAttribute("transform", string); - var t = g.transform.baseVal.consolidate(); - return new d3_transform(t ? t.matrix : d3_transformIdentity); - })(string); - }; - function d3_transform(m) { - var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; - if (r0[0] * r1[1] < r1[0] * r0[1]) { - r0[0] *= -1; - r0[1] *= -1; - kx *= -1; - kz *= -1; - } - this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; - this.translate = [ m.e, m.f ]; - this.scale = [ kx, ky ]; - this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; - } - d3_transform.prototype.toString = function() { - return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; - }; - function d3_transformDot(a, b) { - return a[0] * b[0] + a[1] * b[1]; - } - function d3_transformNormalize(a) { - var k = Math.sqrt(d3_transformDot(a, a)); - if (k) { - a[0] /= k; - a[1] /= k; - } - return k; - } - function d3_transformCombine(a, b, k) { - a[0] += k * b[0]; - a[1] += k * b[1]; - return a; - } - var d3_transformIdentity = { - a: 1, - b: 0, - c: 0, - d: 1, - e: 0, - f: 0 - }; - d3.interpolate = function(a, b) { - var i = d3.interpolators.length, f; - while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; - return f; - }; - d3.interpolateNumber = function(a, b) { - b -= a; - return function(t) { - return a + b * t; - }; - }; - d3.interpolateRound = function(a, b) { - b -= a; - return function(t) { - return Math.round(a + b * t); - }; - }; - d3.interpolateString = function(a, b) { - var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; - d3_interpolate_number.lastIndex = 0; - for (i = 0; m = d3_interpolate_number.exec(b); ++i) { - if (m.index) s.push(b.substring(s0, s1 = m.index)); - q.push({ - i: s.length, - x: m[0] - }); - s.push(null); - s0 = d3_interpolate_number.lastIndex; - } - if (s0 < b.length) s.push(b.substring(s0)); - for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { - o = q[i]; - if (o.x == m[0]) { - if (o.i) { - if (s[o.i + 1] == null) { - s[o.i - 1] += o.x; - s.splice(o.i, 1); - for (j = i + 1; j < n; ++j) q[j].i--; - } else { - s[o.i - 1] += o.x + s[o.i + 1]; - s.splice(o.i, 2); - for (j = i + 1; j < n; ++j) q[j].i -= 2; - } - } else { - if (s[o.i + 1] == null) { - s[o.i] = o.x; - } else { - s[o.i] = o.x + s[o.i + 1]; - s.splice(o.i + 1, 1); - for (j = i + 1; j < n; ++j) q[j].i--; - } - } - q.splice(i, 1); - n--; - i--; - } else { - o.x = d3.interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); - } - } - while (i < n) { - o = q.pop(); - if (s[o.i + 1] == null) { - s[o.i] = o.x; - } else { - s[o.i] = o.x + s[o.i + 1]; - s.splice(o.i + 1, 1); - } - n--; - } - if (s.length === 1) { - return s[0] == null ? q[0].x : function() { - return b; - }; - } - return function(t) { - for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); - return s.join(""); - }; - }; - d3.interpolateTransform = function(a, b) { - var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; - if (ta[0] != tb[0] || ta[1] != tb[1]) { - s.push("translate(", null, ",", null, ")"); - q.push({ - i: 1, - x: d3.interpolateNumber(ta[0], tb[0]) - }, { - i: 3, - x: d3.interpolateNumber(ta[1], tb[1]) - }); - } else if (tb[0] || tb[1]) { - s.push("translate(" + tb + ")"); + re.lastIndex = 0; + if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); } else { - s.push(""); + node.setAttribute("class", d3_collapse(c.replace(re, " "))); } - if (ra != rb) { - if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; - q.push({ - i: s.push(s.pop() + "rotate(", null, ")") - 2, - x: d3.interpolateNumber(ra, rb) - }); - } else if (rb) { - s.push(s.pop() + "rotate(" + rb + ")"); - } - if (wa != wb) { - q.push({ - i: s.push(s.pop() + "skewX(", null, ")") - 2, - x: d3.interpolateNumber(wa, wb) - }); - } else if (wb) { - s.push(s.pop() + "skewX(" + wb + ")"); - } - if (ka[0] != kb[0] || ka[1] != kb[1]) { - n = s.push(s.pop() + "scale(", null, ",", null, ")"); - q.push({ - i: n - 4, - x: d3.interpolateNumber(ka[0], kb[0]) - }, { - i: n - 2, - x: d3.interpolateNumber(ka[1], kb[1]) - }); - } else if (kb[0] != 1 || kb[1] != 1) { - s.push(s.pop() + "scale(" + kb + ")"); - } - n = q.length; - return function(t) { - var i = -1, o; - while (++i < n) s[(o = q[i]).i] = o.x(t); - return s.join(""); - }; }; - d3.interpolateRgb = function(a, b) { - a = d3.rgb(a); - b = d3.rgb(b); - var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; - return function(t) { - return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); - }; - }; - d3.interpolateHsl = function(a, b) { - a = d3.hsl(a); - b = d3.hsl(b); - var h0 = a.h, s0 = a.s, l0 = a.l, h1 = b.h - h0, s1 = b.s - s0, l1 = b.l - l0; - if (h1 > 180) h1 -= 360; else if (h1 < -180) h1 += 360; - return function(t) { - return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t) + ""; - }; - }; - d3.interpolateLab = function(a, b) { - a = d3.lab(a); - b = d3.lab(b); - var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; - return function(t) { - return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; - }; - }; - d3.interpolateHcl = function(a, b) { - a = d3.hcl(a); - b = d3.hcl(b); - var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; - if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; - return function(t) { - return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; - }; - }; - d3.interpolateArray = function(a, b) { - var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; - for (i = 0; i < n0; ++i) x.push(d3.interpolate(a[i], b[i])); - for (;i < na; ++i) c[i] = a[i]; - for (;i < nb; ++i) c[i] = b[i]; - return function(t) { - for (i = 0; i < n0; ++i) c[i] = x[i](t); - return c; - }; - }; - d3.interpolateObject = function(a, b) { - var i = {}, c = {}, k; - for (k in a) { - if (k in b) { - i[k] = d3_interpolateByName(k)(a[k], b[k]); - } else { - c[k] = a[k]; - } - } - for (k in b) { - if (!(k in a)) { - c[k] = b[k]; - } - } - return function(t) { - for (k in i) c[k] = i[k](t); - return c; - }; - }; - var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; - function d3_interpolateByName(name) { - return name == "transform" ? d3.interpolateTransform : d3.interpolate; - } - d3.interpolators = [ d3.interpolateObject, function(a, b) { - return Array.isArray(b) && d3.interpolateArray(a, b); - }, function(a, b) { - return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + ""); - }, function(a, b) { - return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Color) && d3.interpolateRgb(a, b); - }, function(a, b) { - return !isNaN(a = +a) && !isNaN(b = +b) && d3.interpolateNumber(a, b); - } ]; - function d3_uninterpolateNumber(a, b) { - b = b - (a = +a) ? 1 / (b - a) : 0; - return function(x) { - return (x - a) * b; - }; - } - function d3_uninterpolateClamp(a, b) { - b = b - (a = +a) ? 1 / (b - a) : 0; - return function(x) { - return Math.max(0, Math.min(1, (x - a) * b)); - }; - } - function d3_Color() {} - d3_Color.prototype.toString = function() { - return this.rgb() + ""; - }; - d3.rgb = function(r, g, b) { - return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b); - }; - function d3_rgb(r, g, b) { - return new d3_Rgb(r, g, b); - } - function d3_Rgb(r, g, b) { - this.r = r; - this.g = g; - this.b = b; - } - var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color(); - d3_rgbPrototype.brighter = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - var r = this.r, g = this.g, b = this.b, i = 30; - if (!r && !g && !b) return d3_rgb(i, i, i); - if (r && r < i) r = i; - if (g && g < i) g = i; - if (b && b < i) b = i; - return d3_rgb(Math.min(255, Math.floor(r / k)), Math.min(255, Math.floor(g / k)), Math.min(255, Math.floor(b / k))); - }; - d3_rgbPrototype.darker = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - return d3_rgb(Math.floor(k * this.r), Math.floor(k * this.g), Math.floor(k * this.b)); - }; - d3_rgbPrototype.hsl = function() { - return d3_rgb_hsl(this.r, this.g, this.b); - }; - d3_rgbPrototype.toString = function() { - return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); - }; - function d3_rgb_hex(v) { - return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); - } - function d3_rgb_parse(format, rgb, hsl) { - var r = 0, g = 0, b = 0, m1, m2, name; - m1 = /([a-z]+)\((.*)\)/i.exec(format); - if (m1) { - m2 = m1[2].split(","); - switch (m1[1]) { - case "hsl": - { - return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); - } +} - case "rgb": - { - return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); - } - } +d3_selectionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + + // For style(object) or style(object, string), the object specifies the + // names and values of the attributes to set or remove. The values may be + // functions that are evaluated for each element. The optional string + // specifies the priority. + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); + return this; } - if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); - if (format != null && format.charAt(0) === "#") { - if (format.length === 4) { - r = format.charAt(1); - r += r; - g = format.charAt(2); - g += g; - b = format.charAt(3); - b += b; - } else if (format.length === 7) { - r = format.substring(1, 3); - g = format.substring(3, 5); - b = format.substring(5, 7); - } - r = parseInt(r, 16); - g = parseInt(g, 16); - b = parseInt(b, 16); - } - return rgb(r, g, b); + + // For style(string), return the computed style value for the first node. + if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name); + + // For style(string, string) or style(string, function), use the default + // priority. The priority is ignored for style(string, null). + priority = ""; } - function d3_rgb_hsl(r, g, b) { - var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; - if (d) { - s = l < .5 ? d / (max + min) : d / (2 - max - min); - if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; - h *= 60; - } else { - s = h = 0; - } - return d3_hsl(h, s, l); + + // Otherwise, a name, value and priority are specified, and handled as below. + return this.each(d3_selection_style(name, value, priority)); +}; + +function d3_selection_style(name, value, priority) { + + // For style(name, null) or style(name, null, priority), remove the style + // property with the specified name. The priority is ignored. + function styleNull() { + this.style.removeProperty(name); } - function d3_rgb_lab(r, g, b) { - r = d3_rgb_xyz(r); - g = d3_rgb_xyz(g); - b = d3_rgb_xyz(b); - var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); - return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); + + // For style(name, string) or style(name, string, priority), set the style + // property with the specified name, using the specified priority. + function styleConstant() { + this.style.setProperty(name, value, priority); } - function d3_rgb_xyz(r) { - return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); + + // For style(name, function) or style(name, function, priority), evaluate the + // function for each element, and set or remove the style property as + // appropriate. When setting, use the specified priority. + function styleFunction() { + var x = value.apply(this, arguments); + if (x == null) this.style.removeProperty(name); + else this.style.setProperty(name, x, priority); } - function d3_rgb_parseNumber(c) { - var f = parseFloat(c); - return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; + + return value == null + ? styleNull : (typeof value === "function" + ? styleFunction : styleConstant); +} + +d3_selectionPrototype.property = function(name, value) { + if (arguments.length < 2) { + + // For property(string), return the property value for the first node. + if (typeof name === "string") return this.node()[name]; + + // For property(object), the object specifies the names and values of the + // properties to set or remove. The values may be functions that are + // evaluated for each element. + for (value in name) this.each(d3_selection_property(value, name[value])); + return this; } - var d3_rgb_names = d3.map({ - aliceblue: "#f0f8ff", - antiquewhite: "#faebd7", - aqua: "#00ffff", - aquamarine: "#7fffd4", - azure: "#f0ffff", - beige: "#f5f5dc", - bisque: "#ffe4c4", - black: "#000000", - blanchedalmond: "#ffebcd", - blue: "#0000ff", - blueviolet: "#8a2be2", - brown: "#a52a2a", - burlywood: "#deb887", - cadetblue: "#5f9ea0", - chartreuse: "#7fff00", - chocolate: "#d2691e", - coral: "#ff7f50", - cornflowerblue: "#6495ed", - cornsilk: "#fff8dc", - crimson: "#dc143c", - cyan: "#00ffff", - darkblue: "#00008b", - darkcyan: "#008b8b", - darkgoldenrod: "#b8860b", - darkgray: "#a9a9a9", - darkgreen: "#006400", - darkgrey: "#a9a9a9", - darkkhaki: "#bdb76b", - darkmagenta: "#8b008b", - darkolivegreen: "#556b2f", - darkorange: "#ff8c00", - darkorchid: "#9932cc", - darkred: "#8b0000", - darksalmon: "#e9967a", - darkseagreen: "#8fbc8f", - darkslateblue: "#483d8b", - darkslategray: "#2f4f4f", - darkslategrey: "#2f4f4f", - darkturquoise: "#00ced1", - darkviolet: "#9400d3", - deeppink: "#ff1493", - deepskyblue: "#00bfff", - dimgray: "#696969", - dimgrey: "#696969", - dodgerblue: "#1e90ff", - firebrick: "#b22222", - floralwhite: "#fffaf0", - forestgreen: "#228b22", - fuchsia: "#ff00ff", - gainsboro: "#dcdcdc", - ghostwhite: "#f8f8ff", - gold: "#ffd700", - goldenrod: "#daa520", - gray: "#808080", - green: "#008000", - greenyellow: "#adff2f", - grey: "#808080", - honeydew: "#f0fff0", - hotpink: "#ff69b4", - indianred: "#cd5c5c", - indigo: "#4b0082", - ivory: "#fffff0", - khaki: "#f0e68c", - lavender: "#e6e6fa", - lavenderblush: "#fff0f5", - lawngreen: "#7cfc00", - lemonchiffon: "#fffacd", - lightblue: "#add8e6", - lightcoral: "#f08080", - lightcyan: "#e0ffff", - lightgoldenrodyellow: "#fafad2", - lightgray: "#d3d3d3", - lightgreen: "#90ee90", - lightgrey: "#d3d3d3", - lightpink: "#ffb6c1", - lightsalmon: "#ffa07a", - lightseagreen: "#20b2aa", - lightskyblue: "#87cefa", - lightslategray: "#778899", - lightslategrey: "#778899", - lightsteelblue: "#b0c4de", - lightyellow: "#ffffe0", - lime: "#00ff00", - limegreen: "#32cd32", - linen: "#faf0e6", - magenta: "#ff00ff", - maroon: "#800000", - mediumaquamarine: "#66cdaa", - mediumblue: "#0000cd", - mediumorchid: "#ba55d3", - mediumpurple: "#9370db", - mediumseagreen: "#3cb371", - mediumslateblue: "#7b68ee", - mediumspringgreen: "#00fa9a", - mediumturquoise: "#48d1cc", - mediumvioletred: "#c71585", - midnightblue: "#191970", - mintcream: "#f5fffa", - mistyrose: "#ffe4e1", - moccasin: "#ffe4b5", - navajowhite: "#ffdead", - navy: "#000080", - oldlace: "#fdf5e6", - olive: "#808000", - olivedrab: "#6b8e23", - orange: "#ffa500", - orangered: "#ff4500", - orchid: "#da70d6", - palegoldenrod: "#eee8aa", - palegreen: "#98fb98", - paleturquoise: "#afeeee", - palevioletred: "#db7093", - papayawhip: "#ffefd5", - peachpuff: "#ffdab9", - peru: "#cd853f", - pink: "#ffc0cb", - plum: "#dda0dd", - powderblue: "#b0e0e6", - purple: "#800080", - red: "#ff0000", - rosybrown: "#bc8f8f", - royalblue: "#4169e1", - saddlebrown: "#8b4513", - salmon: "#fa8072", - sandybrown: "#f4a460", - seagreen: "#2e8b57", - seashell: "#fff5ee", - sienna: "#a0522d", - silver: "#c0c0c0", - skyblue: "#87ceeb", - slateblue: "#6a5acd", - slategray: "#708090", - slategrey: "#708090", - snow: "#fffafa", - springgreen: "#00ff7f", - steelblue: "#4682b4", - tan: "#d2b48c", - teal: "#008080", - thistle: "#d8bfd8", - tomato: "#ff6347", - turquoise: "#40e0d0", - violet: "#ee82ee", - wheat: "#f5deb3", - white: "#ffffff", - whitesmoke: "#f5f5f5", - yellow: "#ffff00", - yellowgreen: "#9acd32" + + // Otherwise, both a name and a value are specified, and are handled as below. + return this.each(d3_selection_property(name, value)); +}; + +function d3_selection_property(name, value) { + + // For property(name, null), remove the property with the specified name. + function propertyNull() { + delete this[name]; + } + + // For property(name, string), set the property with the specified name. + function propertyConstant() { + this[name] = value; + } + + // For property(name, function), evaluate the function for each element, and + // set or remove the property as appropriate. + function propertyFunction() { + var x = value.apply(this, arguments); + if (x == null) delete this[name]; + else this[name] = x; + } + + return value == null + ? propertyNull : (typeof value === "function" + ? propertyFunction : propertyConstant); +} + +d3_selectionPrototype.text = function(value) { + return arguments.length + ? this.each(typeof value === "function" + ? function() { var v = value.apply(this, arguments); this.textContent = v == null ? "" : v; } : value == null + ? function() { this.textContent = ""; } + : function() { this.textContent = value; }) + : this.node().textContent; +}; + +d3_selectionPrototype.html = function(value) { + return arguments.length + ? this.each(typeof value === "function" + ? function() { var v = value.apply(this, arguments); this.innerHTML = v == null ? "" : v; } : value == null + ? function() { this.innerHTML = ""; } + : function() { this.innerHTML = value; }) + : this.node().innerHTML; +}; + +// TODO append(node)? +// TODO append(function)? +d3_selectionPrototype.append = function(name) { + name = d3.ns.qualify(name); + + function append() { + return this.appendChild(d3_document.createElementNS(this.namespaceURI, name)); + } + + function appendNS() { + return this.appendChild(d3_document.createElementNS(name.space, name.local)); + } + + return this.select(name.local ? appendNS : append); +}; + +d3_selectionPrototype.insert = function(name, before) { + name = d3.ns.qualify(name); + + if (typeof before !== "function") before = d3_selection_selector(before); + + function insert(d, i) { + return this.insertBefore( + d3_document.createElementNS(this.namespaceURI, name), + before.call(this, d, i)); + } + + function insertNS(d, i) { + return this.insertBefore( + d3_document.createElementNS(name.space, name.local), + before.call(this, d, i)); + } + + return this.select(name.local ? insertNS : insert); +}; + +// TODO remove(selector)? +// TODO remove(node)? +// TODO remove(function)? +d3_selectionPrototype.remove = function() { + return this.each(function() { + var parent = this.parentNode; + if (parent) parent.removeChild(this); }); - d3_rgb_names.forEach(function(key, value) { - d3_rgb_names.set(key, d3_rgb_parse(value, d3_rgb, d3_hsl_rgb)); - }); - d3.hsl = function(h, s, l) { - return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l); - }; - function d3_hsl(h, s, l) { - return new d3_Hsl(h, s, l); - } - function d3_Hsl(h, s, l) { - this.h = h; - this.s = s; - this.l = l; - } - var d3_hslPrototype = d3_Hsl.prototype = new d3_Color(); - d3_hslPrototype.brighter = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - return d3_hsl(this.h, this.s, this.l / k); - }; - d3_hslPrototype.darker = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - return d3_hsl(this.h, this.s, k * this.l); - }; - d3_hslPrototype.rgb = function() { - return d3_hsl_rgb(this.h, this.s, this.l); - }; - function d3_hsl_rgb(h, s, l) { - var m1, m2; - h = h % 360; - if (h < 0) h += 360; - s = s < 0 ? 0 : s > 1 ? 1 : s; - l = l < 0 ? 0 : l > 1 ? 1 : l; - m2 = l <= .5 ? l * (1 + s) : l + s - l * s; - m1 = 2 * l - m2; - function v(h) { - if (h > 360) h -= 360; else if (h < 0) h += 360; - if (h < 60) return m1 + (m2 - m1) * h / 60; - if (h < 180) return m2; - if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; - return m1; +}; + +d3_selectionPrototype.data = function(value, key) { + var i = -1, + n = this.length, + group, + node; + + // If no value is specified, return the first value. + if (!arguments.length) { + value = new Array(n = (group = this[0]).length); + while (++i < n) { + if (node = group[i]) { + value[i] = node.__data__; + } } - function vv(h) { - return Math.round(v(h) * 255); - } - return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); + return value; } - d3.hcl = function(h, c, l) { - return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l); - }; - function d3_hcl(h, c, l) { - return new d3_Hcl(h, c, l); - } - function d3_Hcl(h, c, l) { - this.h = h; - this.c = c; - this.l = l; - } - var d3_hclPrototype = d3_Hcl.prototype = new d3_Color(); - d3_hclPrototype.brighter = function(k) { - return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); - }; - d3_hclPrototype.darker = function(k) { - return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); - }; - d3_hclPrototype.rgb = function() { - return d3_hcl_lab(this.h, this.c, this.l).rgb(); - }; - function d3_hcl_lab(h, c, l) { - return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); - } - d3.lab = function(l, a, b) { - return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b); - }; - function d3_lab(l, a, b) { - return new d3_Lab(l, a, b); - } - function d3_Lab(l, a, b) { - this.l = l; - this.a = a; - this.b = b; - } - var d3_lab_K = 18; - var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; - var d3_labPrototype = d3_Lab.prototype = new d3_Color(); - d3_labPrototype.brighter = function(k) { - return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); - }; - d3_labPrototype.darker = function(k) { - return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); - }; - d3_labPrototype.rgb = function() { - return d3_lab_rgb(this.l, this.a, this.b); - }; - function d3_lab_rgb(l, a, b) { - var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; - x = d3_lab_xyz(x) * d3_lab_X; - y = d3_lab_xyz(y) * d3_lab_Y; - z = d3_lab_xyz(z) * d3_lab_Z; - return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); - } - function d3_lab_hcl(l, a, b) { - return d3_hcl(Math.atan2(b, a) / π * 180, Math.sqrt(a * a + b * b), l); - } - function d3_lab_xyz(x) { - return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; - } - function d3_xyz_lab(x) { - return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; - } - function d3_xyz_rgb(r) { - return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); - } - function d3_selection(groups) { - d3_arraySubclass(groups, d3_selectionPrototype); - return groups; - } - var d3_select = function(s, n) { - return n.querySelector(s); - }, d3_selectAll = function(s, n) { - return n.querySelectorAll(s); - }, d3_selectRoot = d3_document.documentElement, d3_selectMatcher = d3_selectRoot.matchesSelector || d3_selectRoot.webkitMatchesSelector || d3_selectRoot.mozMatchesSelector || d3_selectRoot.msMatchesSelector || d3_selectRoot.oMatchesSelector, d3_selectMatches = function(n, s) { - return d3_selectMatcher.call(n, s); - }; - if (typeof Sizzle === "function") { - d3_select = function(s, n) { - return Sizzle(s, n)[0] || null; - }; - d3_selectAll = function(s, n) { - return Sizzle.uniqueSort(Sizzle(s, n)); - }; - d3_selectMatches = Sizzle.matchesSelector; - } - var d3_selectionPrototype = []; - d3.selection = function() { - return d3_selectionRoot; - }; - d3.selection.prototype = d3_selectionPrototype; - d3_selectionPrototype.select = function(selector) { - var subgroups = [], subgroup, subnode, group, node; - if (typeof selector !== "function") selector = d3_selection_selector(selector); - for (var j = -1, m = this.length; ++j < m; ) { - subgroups.push(subgroup = []); - subgroup.parentNode = (group = this[j]).parentNode; - for (var i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - subgroup.push(subnode = selector.call(node, node.__data__, i)); - if (subnode && "__data__" in node) subnode.__data__ = node.__data__; + + function bind(group, groupData) { + var i, + n = group.length, + m = groupData.length, + n0 = Math.min(n, m), + updateNodes = new Array(m), + enterNodes = new Array(m), + exitNodes = new Array(n), + node, + nodeData; + + if (key) { + var nodeByKeyValue = new d3_Map, + dataByKeyValue = new d3_Map, + keyValues = [], + keyValue; + + for (i = -1; ++i < n;) { + keyValue = key.call(node = group[i], node.__data__, i); + if (nodeByKeyValue.has(keyValue)) { + exitNodes[i] = node; // duplicate selection key } else { - subgroup.push(null); + nodeByKeyValue.set(keyValue, node); } + keyValues.push(keyValue); } - } - return d3_selection(subgroups); - }; - function d3_selection_selector(selector) { - return function() { - return d3_select(selector, this); - }; - } - d3_selectionPrototype.selectAll = function(selector) { - var subgroups = [], subgroup, node; - if (typeof selector !== "function") selector = d3_selection_selectorAll(selector); - for (var j = -1, m = this.length; ++j < m; ) { - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i))); - subgroup.parentNode = node; + + for (i = -1; ++i < m;) { + keyValue = key.call(groupData, nodeData = groupData[i], i); + if (node = nodeByKeyValue.get(keyValue)) { + updateNodes[i] = node; + node.__data__ = nodeData; + } else if (!dataByKeyValue.has(keyValue)) { // no duplicate data key + enterNodes[i] = d3_selection_dataNode(nodeData); } + dataByKeyValue.set(keyValue, nodeData); + nodeByKeyValue.remove(keyValue); } - } - return d3_selection(subgroups); - }; - function d3_selection_selectorAll(selector) { - return function() { - return d3_selectAll(selector, this); - }; - } - d3_selectionPrototype.attr = function(name, value) { - if (arguments.length < 2) { - if (typeof name === "string") { - var node = this.node(); - name = d3.ns.qualify(name); - return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); - } - for (value in name) this.each(d3_selection_attr(value, name[value])); - return this; - } - return this.each(d3_selection_attr(name, value)); - }; - function d3_selection_attr(name, value) { - name = d3.ns.qualify(name); - function attrNull() { - this.removeAttribute(name); - } - function attrNullNS() { - this.removeAttributeNS(name.space, name.local); - } - function attrConstant() { - this.setAttribute(name, value); - } - function attrConstantNS() { - this.setAttributeNS(name.space, name.local, value); - } - function attrFunction() { - var x = value.apply(this, arguments); - if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); - } - function attrFunctionNS() { - var x = value.apply(this, arguments); - if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); - } - return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; - } - d3_selectionPrototype.classed = function(name, value) { - if (arguments.length < 2) { - if (typeof name === "string") { - var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1; - if (value = node.classList) { - while (++i < n) if (!value.contains(name[i])) return false; - } else { - value = node.className; - if (value.baseVal != null) value = value.baseVal; - while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; - } - return true; - } - for (value in name) this.each(d3_selection_classed(value, name[value])); - return this; - } - return this.each(d3_selection_classed(name, value)); - }; - function d3_selection_classedRe(name) { - return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); - } - function d3_selection_classed(name, value) { - name = name.trim().split(/\s+/).map(d3_selection_classedName); - var n = name.length; - function classedConstant() { - var i = -1; - while (++i < n) name[i](this, value); - } - function classedFunction() { - var i = -1, x = value.apply(this, arguments); - while (++i < n) name[i](this, x); - } - return typeof value === "function" ? classedFunction : classedConstant; - } - function d3_selection_classedName(name) { - var re = d3_selection_classedRe(name); - return function(node, value) { - if (c = node.classList) return value ? c.add(name) : c.remove(name); - var c = node.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c; - if (value) { - re.lastIndex = 0; - if (!re.test(cv)) { - cv = d3_collapse(cv + " " + name); - if (cb) c.baseVal = cv; else node.className = cv; - } - } else if (cv) { - cv = d3_collapse(cv.replace(re, " ")); - if (cb) c.baseVal = cv; else node.className = cv; - } - }; - } - d3_selectionPrototype.style = function(name, value, priority) { - var n = arguments.length; - if (n < 3) { - if (typeof name !== "string") { - if (n < 2) value = ""; - for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); - return this; - } - if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name); - priority = ""; - } - return this.each(d3_selection_style(name, value, priority)); - }; - function d3_selection_style(name, value, priority) { - function styleNull() { - this.style.removeProperty(name); - } - function styleConstant() { - this.style.setProperty(name, value, priority); - } - function styleFunction() { - var x = value.apply(this, arguments); - if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); - } - return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; - } - d3_selectionPrototype.property = function(name, value) { - if (arguments.length < 2) { - if (typeof name === "string") return this.node()[name]; - for (value in name) this.each(d3_selection_property(value, name[value])); - return this; - } - return this.each(d3_selection_property(name, value)); - }; - function d3_selection_property(name, value) { - function propertyNull() { - delete this[name]; - } - function propertyConstant() { - this[name] = value; - } - function propertyFunction() { - var x = value.apply(this, arguments); - if (x == null) delete this[name]; else this[name] = x; - } - return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; - } - d3_selectionPrototype.text = function(value) { - return arguments.length ? this.each(typeof value === "function" ? function() { - var v = value.apply(this, arguments); - this.textContent = v == null ? "" : v; - } : value == null ? function() { - this.textContent = ""; - } : function() { - this.textContent = value; - }) : this.node().textContent; - }; - d3_selectionPrototype.html = function(value) { - return arguments.length ? this.each(typeof value === "function" ? function() { - var v = value.apply(this, arguments); - this.innerHTML = v == null ? "" : v; - } : value == null ? function() { - this.innerHTML = ""; - } : function() { - this.innerHTML = value; - }) : this.node().innerHTML; - }; - d3_selectionPrototype.append = function(name) { - name = d3.ns.qualify(name); - function append() { - return this.appendChild(d3_document.createElementNS(this.namespaceURI, name)); - } - function appendNS() { - return this.appendChild(d3_document.createElementNS(name.space, name.local)); - } - return this.select(name.local ? appendNS : append); - }; - d3_selectionPrototype.insert = function(name, before) { - name = d3.ns.qualify(name); - if (typeof before !== "function") before = d3_selection_selector(before); - function insert(d, i) { - return this.insertBefore(d3_document.createElementNS(this.namespaceURI, name), before.call(this, d, i)); - } - function insertNS(d, i) { - return this.insertBefore(d3_document.createElementNS(name.space, name.local), before.call(this, d, i)); - } - return this.select(name.local ? insertNS : insert); - }; - d3_selectionPrototype.remove = function() { - return this.each(function() { - var parent = this.parentNode; - if (parent) parent.removeChild(this); - }); - }; - d3_selectionPrototype.data = function(value, key) { - var i = -1, n = this.length, group, node; - if (!arguments.length) { - value = new Array(n = (group = this[0]).length); - while (++i < n) { - if (node = group[i]) { - value[i] = node.__data__; - } - } - return value; - } - function bind(group, groupData) { - var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData; - if (key) { - var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue; - for (i = -1; ++i < n; ) { - keyValue = key.call(node = group[i], node.__data__, i); - if (nodeByKeyValue.has(keyValue)) { - exitNodes[i] = node; - } else { - nodeByKeyValue.set(keyValue, node); - } - keyValues.push(keyValue); - } - for (i = -1; ++i < m; ) { - keyValue = key.call(groupData, nodeData = groupData[i], i); - if (node = nodeByKeyValue.get(keyValue)) { - updateNodes[i] = node; - node.__data__ = nodeData; - } else if (!dataByKeyValue.has(keyValue)) { - enterNodes[i] = d3_selection_dataNode(nodeData); - } - dataByKeyValue.set(keyValue, nodeData); - nodeByKeyValue.remove(keyValue); - } - for (i = -1; ++i < n; ) { - if (nodeByKeyValue.has(keyValues[i])) { - exitNodes[i] = group[i]; - } - } - } else { - for (i = -1; ++i < n0; ) { - node = group[i]; - nodeData = groupData[i]; - if (node) { - node.__data__ = nodeData; - updateNodes[i] = node; - } else { - enterNodes[i] = d3_selection_dataNode(nodeData); - } - } - for (;i < m; ++i) { - enterNodes[i] = d3_selection_dataNode(groupData[i]); - } - for (;i < n; ++i) { + + for (i = -1; ++i < n;) { + if (nodeByKeyValue.has(keyValues[i])) { exitNodes[i] = group[i]; } } - enterNodes.update = updateNodes; - enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; - enter.push(enterNodes); - update.push(updateNodes); - exit.push(exitNodes); - } - var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); - if (typeof value === "function") { - while (++i < n) { - bind(group = this[i], value.call(group, group.parentNode.__data__, i)); - } } else { - while (++i < n) { - bind(group = this[i], value); - } - } - update.enter = function() { - return enter; - }; - update.exit = function() { - return exit; - }; - return update; - }; - function d3_selection_dataNode(data) { - return { - __data__: data - }; - } - d3_selectionPrototype.datum = function(value) { - return arguments.length ? this.property("__data__", value) : this.property("__data__"); - }; - d3_selectionPrototype.filter = function(filter) { - var subgroups = [], subgroup, group, node; - if (typeof filter !== "function") filter = d3_selection_filter(filter); - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - subgroup.parentNode = (group = this[j]).parentNode; - for (var i = 0, n = group.length; i < n; i++) { - if ((node = group[i]) && filter.call(node, node.__data__, i)) { - subgroup.push(node); + for (i = -1; ++i < n0;) { + node = group[i]; + nodeData = groupData[i]; + if (node) { + node.__data__ = nodeData; + updateNodes[i] = node; + } else { + enterNodes[i] = d3_selection_dataNode(nodeData); } } - } - return d3_selection(subgroups); - }; - function d3_selection_filter(selector) { - return function() { - return d3_selectMatches(this, selector); - }; - } - d3_selectionPrototype.order = function() { - for (var j = -1, m = this.length; ++j < m; ) { - for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { - if (node = group[i]) { - if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); - next = node; - } + for (; i < m; ++i) { + enterNodes[i] = d3_selection_dataNode(groupData[i]); + } + for (; i < n; ++i) { + exitNodes[i] = group[i]; } } - return this; - }; - d3_selectionPrototype.sort = function(comparator) { - comparator = d3_selection_sortComparator.apply(this, arguments); - for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); - return this.order(); - }; - function d3_selection_sortComparator(comparator) { - if (!arguments.length) comparator = d3.ascending; - return function(a, b) { - return !a - !b || comparator(a.__data__, b.__data__); - }; + + enterNodes.update + = updateNodes; + + enterNodes.parentNode + = updateNodes.parentNode + = exitNodes.parentNode + = group.parentNode; + + enter.push(enterNodes); + update.push(updateNodes); + exit.push(exitNodes); } - d3_selectionPrototype.on = function(type, listener, capture) { - var n = arguments.length; - if (n < 3) { - if (typeof type !== "string") { - if (n < 2) listener = false; - for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); - return this; - } - if (n < 2) return (n = this.node()["__on" + type]) && n._; - capture = false; + + var enter = d3_selection_enter([]), + update = d3_selection([]), + exit = d3_selection([]); + + if (typeof value === "function") { + while (++i < n) { + bind(group = this[i], value.call(group, group.parentNode.__data__, i)); } - return this.each(d3_selection_on(type, listener, capture)); + } else { + while (++i < n) { + bind(group = this[i], value); + } + } + + update.enter = function() { return enter; }; + update.exit = function() { return exit; }; + return update; +}; + +function d3_selection_dataNode(data) { + return {__data__: data}; +} + +d3_selectionPrototype.datum = function(value) { + return arguments.length + ? this.property("__data__", value) + : this.property("__data__"); +}; + +d3_selectionPrototype.filter = function(filter) { + var subgroups = [], + subgroup, + group, + node; + + if (typeof filter !== "function") filter = d3_selection_filter(filter); + + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); + } + } + } + + return d3_selection(subgroups); +}; + +function d3_selection_filter(selector) { + return function() { + return d3_selectMatches(this, selector); }; - function d3_selection_on(type, listener, capture) { - var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; - if (i > 0) type = type.substring(0, i); - var filter = d3_selection_onFilters.get(type); - if (filter) type = filter, wrap = d3_selection_onFilter; - function onRemove() { - var l = this[name]; - if (l) { - this.removeEventListener(type, l, l.$); +} + +d3_selectionPrototype.order = function() { + for (var j = -1, m = this.length; ++j < m;) { + for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0;) { + if (node = group[i]) { + if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); + next = node; + } + } + } + return this; +}; + +d3_selectionPrototype.sort = function(comparator) { + comparator = d3_selection_sortComparator.apply(this, arguments); + for (var j = -1, m = this.length; ++j < m;) this[j].sort(comparator); + return this.order(); +}; + +function d3_selection_sortComparator(comparator) { + if (!arguments.length) comparator = d3.ascending; + return function(a, b) { + return (!a - !b) || comparator(a.__data__, b.__data__); + }; +} +function d3_noop() {} + +d3_selectionPrototype.on = function(type, listener, capture) { + var n = arguments.length; + if (n < 3) { + + // For on(object) or on(object, boolean), the object specifies the event + // types and listeners to add or remove. The optional boolean specifies + // whether the listener captures events. + if (typeof type !== "string") { + if (n < 2) listener = false; + for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); + return this; + } + + // For on(string), return the listener for the first node. + if (n < 2) return (n = this.node()["__on" + type]) && n._; + + // For on(string, function), use the default capture. + capture = false; + } + + // Otherwise, a type, listener and capture are specified, and handled as below. + return this.each(d3_selection_on(type, listener, capture)); +}; + +function d3_selection_on(type, listener, capture) { + var name = "__on" + type, + i = type.indexOf("."), + wrap = d3_selection_onListener; + + if (i > 0) type = type.substring(0, i); + var filter = d3_selection_onFilters.get(type); + if (filter) type = filter, wrap = d3_selection_onFilter; + + function onRemove() { + var l = this[name]; + if (l) { + this.removeEventListener(type, l, l.$); + delete this[name]; + } + } + + function onAdd() { + var l = wrap(listener, d3_array(arguments)); + onRemove.call(this); + this.addEventListener(type, this[name] = l, l.$ = capture); + l._ = listener; + } + + function removeAll() { + var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), + match; + for (var name in this) { + if (match = name.match(re)) { + var l = this[name]; + this.removeEventListener(match[1], l, l.$); delete this[name]; } } - function onAdd() { - var l = wrap(listener, d3_array(arguments)); - onRemove.call(this); - this.addEventListener(type, this[name] = l, l.$ = capture); - l._ = listener; - } - return listener ? onAdd : onRemove; } - var d3_selection_onFilters = d3.map({ - mouseenter: "mouseover", - mouseleave: "mouseout" - }); - d3_selection_onFilters.forEach(function(k) { - if ("on" + k in document) d3_selection_onFilters.remove(k); - }); - function d3_selection_onListener(listener, argumentz) { - return function(e) { - var o = d3.event; - d3.event = e; - argumentz[0] = this.__data__; - try { - listener.apply(this, argumentz); - } finally { - d3.event = o; - } - }; - } - function d3_selection_onFilter(listener, argumentz) { - var l = d3_selection_onListener(listener, argumentz); - return function(e) { - var target = this, related = e.relatedTarget; - if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { - l.call(target, e); - } - }; - } - d3_selectionPrototype.each = function(callback) { - return d3_selection_each(this, function(node, i, j) { - callback.call(node, node.__data__, i, j); - }); - }; - function d3_selection_each(groups, callback) { - for (var j = 0, m = groups.length; j < m; j++) { - for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { - if (node = group[i]) callback(node, i, j); - } - } - return groups; - } - d3_selectionPrototype.call = function(callback) { - var args = d3_array(arguments); - callback.apply(args[0] = this, args); - return this; - }; - d3_selectionPrototype.empty = function() { - return !this.node(); - }; - d3_selectionPrototype.node = function() { - for (var j = 0, m = this.length; j < m; j++) { - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - var node = group[i]; - if (node) return node; - } - } - return null; - }; - d3_selectionPrototype.transition = function() { - var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = Object.create(d3_transitionInherit); - transition.time = Date.now(); - for (var j = -1, m = this.length; ++j < m; ) { - subgroups.push(subgroup = []); - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) d3_transitionNode(node, i, id, transition); - subgroup.push(node); - } - } - return d3_transition(subgroups, id); - }; - var d3_selectionRoot = d3_selection([ [ d3_document ] ]); - d3_selectionRoot[0].parentNode = d3_selectRoot; - d3.select = function(selector) { - return typeof selector === "string" ? d3_selectionRoot.select(selector) : d3_selection([ [ selector ] ]); - }; - d3.selectAll = function(selector) { - return typeof selector === "string" ? d3_selectionRoot.selectAll(selector) : d3_selection([ d3_array(selector) ]); - }; - function d3_selection_enter(selection) { - d3_arraySubclass(selection, d3_selection_enterPrototype); - return selection; - } - var d3_selection_enterPrototype = []; - d3.selection.enter = d3_selection_enter; - d3.selection.enter.prototype = d3_selection_enterPrototype; - d3_selection_enterPrototype.append = d3_selectionPrototype.append; - d3_selection_enterPrototype.insert = d3_selectionPrototype.insert; - d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; - d3_selection_enterPrototype.node = d3_selectionPrototype.node; - d3_selection_enterPrototype.select = function(selector) { - var subgroups = [], subgroup, subnode, upgroup, group, node; - for (var j = -1, m = this.length; ++j < m; ) { - upgroup = (group = this[j]).update; - subgroups.push(subgroup = []); - subgroup.parentNode = group.parentNode; - for (var i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i)); - subnode.__data__ = node.__data__; - } else { - subgroup.push(null); - } - } - } - return d3_selection(subgroups); - }; - function d3_transition(groups, id) { - d3_arraySubclass(groups, d3_transitionPrototype); - groups.id = id; - return groups; - } - var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit = { - ease: d3_ease_cubicInOut, - delay: 0, - duration: 250 - }; - d3_transitionPrototype.call = d3_selectionPrototype.call; - d3_transitionPrototype.empty = d3_selectionPrototype.empty; - d3_transitionPrototype.node = d3_selectionPrototype.node; - d3.transition = function(selection) { - return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition(); - }; - d3.transition.prototype = d3_transitionPrototype; - function d3_transitionNode(node, i, id, inherit) { - var lock = node.__transition__ || (node.__transition__ = { - active: 0, - count: 0 - }), transition = lock[id]; - if (!transition) { - var time = inherit.time; - transition = lock[id] = { - tween: new d3_Map(), - event: d3.dispatch("start", "end"), - time: time, - ease: inherit.ease, - delay: inherit.delay, - duration: inherit.duration - }; - ++lock.count; - d3.timer(function(elapsed) { - var d = node.__data__, ease = transition.ease, event = transition.event, delay = transition.delay, duration = transition.duration, tweened = []; - return delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time), 1; - function start(elapsed) { - if (lock.active > id) return stop(); - lock.active = id; - event.start.call(node, d, i); - transition.tween.forEach(function(key, value) { - if (value = value.call(node, d, i)) { - tweened.push(value); - } - }); - if (!tick(elapsed)) d3.timer(tick, 0, time); - return 1; - } - function tick(elapsed) { - if (lock.active !== id) return stop(); - var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length; - while (n > 0) { - tweened[--n].call(node, e); - } - if (t >= 1) { - stop(); - event.end.call(node, d, i); - return 1; - } - } - function stop() { - if (--lock.count) delete lock[id]; else delete node.__transition__; - return 1; - } - }, 0, time); - return transition; - } - } - d3_transitionPrototype.select = function(selector) { - var id = this.id, subgroups = [], subgroup, subnode, node; - if (typeof selector !== "function") selector = d3_selection_selector(selector); - for (var j = -1, m = this.length; ++j < m; ) { - subgroups.push(subgroup = []); - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i))) { - if ("__data__" in node) subnode.__data__ = node.__data__; - d3_transitionNode(subnode, i, id, node.__transition__[id]); - subgroup.push(subnode); - } else { - subgroup.push(null); - } - } - } - return d3_transition(subgroups, id); - }; - d3_transitionPrototype.selectAll = function(selector) { - var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition; - if (typeof selector !== "function") selector = d3_selection_selectorAll(selector); - for (var j = -1, m = this.length; ++j < m; ) { - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - transition = node.__transition__[id]; - subnodes = selector.call(node, node.__data__, i); - subgroups.push(subgroup = []); - for (var k = -1, o = subnodes.length; ++k < o; ) { - d3_transitionNode(subnode = subnodes[k], k, id, transition); - subgroup.push(subnode); - } - } - } - } - return d3_transition(subgroups, id); - }; - d3_transitionPrototype.filter = function(filter) { - var subgroups = [], subgroup, group, node; - if (typeof filter !== "function") filter = d3_selection_filter(filter); - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - if ((node = group[i]) && filter.call(node, node.__data__, i)) { - subgroup.push(node); - } - } - } - return d3_transition(subgroups, this.id, this.time).ease(this.ease()); - }; - d3_transitionPrototype.attr = function(nameNS, value) { - if (arguments.length < 2) { - for (value in nameNS) this.attr(value, nameNS[value]); - return this; - } - var interpolate = d3_interpolateByName(nameNS), name = d3.ns.qualify(nameNS); - function attrNull() { - this.removeAttribute(name); - } - function attrNullNS() { - this.removeAttributeNS(name.space, name.local); - } - return d3_transition_tween(this, "attr." + nameNS, value, function(b) { - function attrString() { - var a = this.getAttribute(name), i; - return a !== b && (i = interpolate(a, b), function(t) { - this.setAttribute(name, i(t)); - }); - } - function attrStringNS() { - var a = this.getAttributeNS(name.space, name.local), i; - return a !== b && (i = interpolate(a, b), function(t) { - this.setAttributeNS(name.space, name.local, i(t)); - }); - } - return b == null ? name.local ? attrNullNS : attrNull : (b += "", name.local ? attrStringNS : attrString); - }); - }; - d3_transitionPrototype.attrTween = function(nameNS, tween) { - var name = d3.ns.qualify(nameNS); - function attrTween(d, i) { - var f = tween.call(this, d, i, this.getAttribute(name)); - return f && function(t) { - this.setAttribute(name, f(t)); - }; - } - function attrTweenNS(d, i) { - var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); - return f && function(t) { - this.setAttributeNS(name.space, name.local, f(t)); - }; - } - return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); - }; - d3_transitionPrototype.style = function(name, value, priority) { - var n = arguments.length; - if (n < 3) { - if (typeof name !== "string") { - if (n < 2) value = ""; - for (priority in name) this.style(priority, name[priority], value); - return this; - } - priority = ""; - } - var interpolate = d3_interpolateByName(name); - function styleNull() { - this.style.removeProperty(name); - } - return d3_transition_tween(this, "style." + name, value, function(b) { - function styleString() { - var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i; - return a !== b && (i = interpolate(a, b), function(t) { - this.style.setProperty(name, i(t), priority); - }); - } - return b == null ? styleNull : (b += "", styleString); - }); - }; - d3_transitionPrototype.styleTween = function(name, tween, priority) { - if (arguments.length < 3) priority = ""; - return this.tween("style." + name, function(d, i) { - var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name)); - return f && function(t) { - this.style.setProperty(name, f(t), priority); - }; - }); - }; - d3_transitionPrototype.text = function(value) { - return d3_transition_tween(this, "text", value, d3_transition_text); - }; - function d3_transition_text(b) { - if (b == null) b = ""; - return function() { - this.textContent = b; - }; - } - d3_transitionPrototype.remove = function() { - return this.each("end.transition", function() { - var p; - if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); - }); - }; - d3_transitionPrototype.ease = function(value) { - var id = this.id; - if (arguments.length < 1) return this.node().__transition__[id].ease; - if (typeof value !== "function") value = d3.ease.apply(d3, arguments); - return d3_selection_each(this, function(node) { - node.__transition__[id].ease = value; - }); - }; - d3_transitionPrototype.delay = function(value) { - var id = this.id; - return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { - node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0; - } : (value |= 0, function(node) { - node.__transition__[id].delay = value; - })); - }; - d3_transitionPrototype.duration = function(value) { - var id = this.id; - return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { - node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0); - } : (value = Math.max(1, value | 0), function(node) { - node.__transition__[id].duration = value; - })); - }; - d3_transitionPrototype.each = function(type, listener) { - var id = this.id; - if (arguments.length < 2) { - var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; - d3_transitionInheritId = id; - d3_selection_each(this, function(node, i, j) { - d3_transitionInherit = node.__transition__[id]; - type.call(node, node.__data__, i, j); - }); - d3_transitionInherit = inherit; - d3_transitionInheritId = inheritId; - } else { - d3_selection_each(this, function(node) { - node.__transition__[id].event.on(type, listener); - }); - } - return this; - }; - d3_transitionPrototype.transition = function() { - var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition; - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - if (node = group[i]) { - transition = Object.create(node.__transition__[id0]); - transition.delay += transition.duration; - d3_transitionNode(node, i, id1, transition); - } - subgroup.push(node); - } - } - return d3_transition(subgroups, id1); - }; - d3_transitionPrototype.tween = function(name, tween) { - var id = this.id; - if (arguments.length < 2) return this.node().__transition__[id].tween.get(name); - return d3_selection_each(this, tween == null ? function(node) { - node.__transition__[id].tween.remove(name); - } : function(node) { - node.__transition__[id].tween.set(name, tween); - }); - }; - function d3_transition_tween(groups, name, value, tween) { - var id = groups.id; - return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { - node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j))); - } : (value = tween(value), function(node) { - node.__transition__[id].tween.set(name, value); - })); - } - var d3_timer_id = 0, d3_timer_byId = {}, d3_timer_queue = null, d3_timer_interval, d3_timer_timeout; - d3.timer = function(callback, delay, then) { - if (arguments.length < 3) { - if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return; - then = Date.now(); - } - var timer = d3_timer_byId[callback.id]; - if (timer && timer.callback === callback) { - timer.then = then; - timer.delay = delay; - } else d3_timer_byId[callback.id = ++d3_timer_id] = d3_timer_queue = { - callback: callback, - then: then, - delay: delay, - next: d3_timer_queue - }; - if (!d3_timer_interval) { - d3_timer_timeout = clearTimeout(d3_timer_timeout); - d3_timer_interval = 1; - d3_timer_frame(d3_timer_step); - } - }; - function d3_timer_step() { - var elapsed, now = Date.now(), t1 = d3_timer_queue; - while (t1) { - elapsed = now - t1.then; - if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed); - t1 = t1.next; - } - var delay = d3_timer_flush() - now; - if (delay > 24) { - if (isFinite(delay)) { - clearTimeout(d3_timer_timeout); - d3_timer_timeout = setTimeout(d3_timer_step, delay); - } - d3_timer_interval = 0; - } else { - d3_timer_interval = 1; - d3_timer_frame(d3_timer_step); - } - } - d3.timer.flush = function() { - var elapsed, now = Date.now(), t1 = d3_timer_queue; - while (t1) { - elapsed = now - t1.then; - if (!t1.delay) t1.flush = t1.callback(elapsed); - t1 = t1.next; - } - d3_timer_flush(); - }; - function d3_timer_flush() { - var t0 = null, t1 = d3_timer_queue, then = Infinity; - while (t1) { - if (t1.flush) { - delete d3_timer_byId[t1.callback.id]; - t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next; - } else { - then = Math.min(then, t1.then + t1.delay); - t1 = (t0 = t1).next; - } - } - return then; - } - var d3_timer_frame = d3_window.requestAnimationFrame || d3_window.webkitRequestAnimationFrame || d3_window.mozRequestAnimationFrame || d3_window.oRequestAnimationFrame || d3_window.msRequestAnimationFrame || function(callback) { - setTimeout(callback, 17); - }; - d3.mouse = function(container) { - return d3_mousePoint(container, d3_eventSource()); - }; - var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0; - function d3_mousePoint(container, e) { - var svg = container.ownerSVGElement || container; - if (svg.createSVGPoint) { - var point = svg.createSVGPoint(); - if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) { - svg = d3.select(d3_document.body).append("svg").style("position", "absolute").style("top", 0).style("left", 0); - var ctm = svg[0][0].getScreenCTM(); - d3_mouse_bug44083 = !(ctm.f || ctm.e); - svg.remove(); - } - if (d3_mouse_bug44083) { - point.x = e.pageX; - point.y = e.pageY; - } else { - point.x = e.clientX; - point.y = e.clientY; - } - point = point.matrixTransform(container.getScreenCTM().inverse()); - return [ point.x, point.y ]; - } - var rect = container.getBoundingClientRect(); - return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; - } - d3.touches = function(container, touches) { - if (arguments.length < 2) touches = d3_eventSource().touches; - return touches ? d3_array(touches).map(function(touch) { - var point = d3_mousePoint(container, touch); - point.identifier = touch.identifier; - return point; - }) : []; - }; - function d3_noop() {} - d3.scale = {}; - function d3_scaleExtent(domain) { - var start = domain[0], stop = domain[domain.length - 1]; - return start < stop ? [ start, stop ] : [ stop, start ]; - } - function d3_scaleRange(scale) { - return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); - } - function d3_scale_nice(domain, nice) { - var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; - if (x1 < x0) { - dx = i0, i0 = i1, i1 = dx; - dx = x0, x0 = x1, x1 = dx; - } - if (nice = nice(x1 - x0)) { - domain[i0] = nice.floor(x0); - domain[i1] = nice.ceil(x1); - } - return domain; - } - d3.scale.linear = function() { - return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3.interpolate, false); - }; - function d3_scale_linear(domain, range, interpolate, clamp) { - var output, input; - function rescale() { - var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; - output = linear(domain, range, uninterpolate, interpolate); - input = linear(range, domain, uninterpolate, d3.interpolate); - return scale; - } - function scale(x) { - return output(x); - } - scale.invert = function(y) { - return input(y); - }; - scale.domain = function(x) { - if (!arguments.length) return domain; - domain = x.map(Number); - return rescale(); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - return rescale(); - }; - scale.rangeRound = function(x) { - return scale.range(x).interpolate(d3.interpolateRound); - }; - scale.clamp = function(x) { - if (!arguments.length) return clamp; - clamp = x; - return rescale(); - }; - scale.interpolate = function(x) { - if (!arguments.length) return interpolate; - interpolate = x; - return rescale(); - }; - scale.ticks = function(m) { - return d3_scale_linearTicks(domain, m); - }; - scale.tickFormat = function(m) { - return d3_scale_linearTickFormat(domain, m); - }; - scale.nice = function() { - d3_scale_nice(domain, d3_scale_linearNice); - return rescale(); - }; - scale.copy = function() { - return d3_scale_linear(domain, range, interpolate, clamp); - }; - return rescale(); - } - function d3_scale_linearRebind(scale, linear) { - return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); - } - function d3_scale_linearNice(dx) { - dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1); - return dx && { - floor: function(x) { - return Math.floor(x / dx) * dx; - }, - ceil: function(x) { - return Math.ceil(x / dx) * dx; - } - }; - } - function d3_scale_linearTickRange(domain, m) { - var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; - if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; - extent[0] = Math.ceil(extent[0] / step) * step; - extent[1] = Math.floor(extent[1] / step) * step + step * .5; - extent[2] = step; - return extent; - } - function d3_scale_linearTicks(domain, m) { - return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); - } - function d3_scale_linearTickFormat(domain, m) { - return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f"); - } - function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { - var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); - return function(x) { - return i(u(x)); - }; - } - function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { - var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; - if (domain[k] < domain[0]) { - domain = domain.slice().reverse(); - range = range.slice().reverse(); - } - while (++j <= k) { - u.push(uninterpolate(domain[j - 1], domain[j])); - i.push(interpolate(range[j - 1], range[j])); - } - return function(x) { - var j = d3.bisect(domain, x, 1, k) - 1; - return i[j](u[j](x)); - }; - } - d3.scale.log = function() { - return d3_scale_log(d3.scale.linear().domain([ 0, Math.LN10 ]), 10, d3_scale_logp, d3_scale_powp); - }; - function d3_scale_log(linear, base, log, pow) { - function scale(x) { - return linear(log(x)); - } - scale.invert = function(x) { - return pow(linear.invert(x)); - }; - scale.domain = function(x) { - if (!arguments.length) return linear.domain().map(pow); - if (x[0] < 0) log = d3_scale_logn, pow = d3_scale_pown; else log = d3_scale_logp, - pow = d3_scale_powp; - linear.domain(x.map(log)); - return scale; - }; - scale.base = function(_) { - if (!arguments.length) return base; - base = +_; - return scale; - }; - scale.nice = function() { - linear.domain(d3_scale_nice(linear.domain(), d3_scale_logNice(base))); - return scale; - }; - scale.ticks = function() { - var extent = d3_scaleExtent(linear.domain()), ticks = []; - if (extent.every(isFinite)) { - var b = Math.log(base), i = Math.floor(extent[0] / b), j = Math.ceil(extent[1] / b), u = pow(extent[0]), v = pow(extent[1]), n = base % 1 ? 2 : base; - if (log === d3_scale_logn) { - ticks.push(-Math.pow(base, -i)); - for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(-Math.pow(base, -i) * k); - } else { - for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(Math.pow(base, i) * k); - ticks.push(Math.pow(base, i)); - } - for (i = 0; ticks[i] < u; i++) {} - for (j = ticks.length; ticks[j - 1] > v; j--) {} - ticks = ticks.slice(i, j); - } - return ticks; - }; - scale.tickFormat = function(n, format) { - if (arguments.length < 2) format = d3_scale_logFormat; - if (!arguments.length) return format; - var b = Math.log(base), k = Math.max(.1, n / scale.ticks().length), f = log === d3_scale_logn ? (e = -1e-12, - Math.floor) : (e = 1e-12, Math.ceil), e; - return function(d) { - return d / pow(b * f(log(d) / b + e)) <= k ? format(d) : ""; - }; - }; - scale.copy = function() { - return d3_scale_log(linear.copy(), base, log, pow); - }; - return d3_scale_linearRebind(scale, linear); - } - var d3_scale_logFormat = d3.format(".0e"); - function d3_scale_logp(x) { - return Math.log(x < 0 ? 0 : x); - } - function d3_scale_powp(x) { - return Math.exp(x); - } - function d3_scale_logn(x) { - return -Math.log(x > 0 ? 0 : -x); - } - function d3_scale_pown(x) { - return -Math.exp(-x); - } - function d3_scale_logNice(base) { - base = Math.log(base); - var nice = { - floor: function(x) { - return Math.floor(x / base) * base; - }, - ceil: function(x) { - return Math.ceil(x / base) * base; - } - }; - return function() { - return nice; - }; - } - d3.scale.pow = function() { - return d3_scale_pow(d3.scale.linear(), 1); - }; - function d3_scale_pow(linear, exponent) { - var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); - function scale(x) { - return linear(powp(x)); - } - scale.invert = function(x) { - return powb(linear.invert(x)); - }; - scale.domain = function(x) { - if (!arguments.length) return linear.domain().map(powb); - linear.domain(x.map(powp)); - return scale; - }; - scale.ticks = function(m) { - return d3_scale_linearTicks(scale.domain(), m); - }; - scale.tickFormat = function(m) { - return d3_scale_linearTickFormat(scale.domain(), m); - }; - scale.nice = function() { - return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice)); - }; - scale.exponent = function(x) { - if (!arguments.length) return exponent; - var domain = scale.domain(); - powp = d3_scale_powPow(exponent = x); - powb = d3_scale_powPow(1 / exponent); - return scale.domain(domain); - }; - scale.copy = function() { - return d3_scale_pow(linear.copy(), exponent); - }; - return d3_scale_linearRebind(scale, linear); - } - function d3_scale_powPow(e) { - return function(x) { - return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); - }; - } - d3.scale.sqrt = function() { - return d3.scale.pow().exponent(.5); - }; - d3.scale.ordinal = function() { - return d3_scale_ordinal([], { - t: "range", - a: [ [] ] - }); - }; - function d3_scale_ordinal(domain, ranger) { - var index, range, rangeBand; - function scale(x) { - return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length]; - } - function steps(start, step) { - return d3.range(domain.length).map(function(i) { - return start + step * i; - }); - } - scale.domain = function(x) { - if (!arguments.length) return domain; - domain = []; - index = new d3_Map(); - var i = -1, n = x.length, xi; - while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); - return scale[ranger.t].apply(scale, ranger.a); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - rangeBand = 0; - ranger = { - t: "range", - a: arguments - }; - return scale; - }; - scale.rangePoints = function(x, padding) { - if (arguments.length < 2) padding = 0; - var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding); - range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); - rangeBand = 0; - ranger = { - t: "rangePoints", - a: arguments - }; - return scale; - }; - scale.rangeBands = function(x, padding, outerPadding) { - if (arguments.length < 2) padding = 0; - if (arguments.length < 3) outerPadding = padding; - var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); - range = steps(start + step * outerPadding, step); - if (reverse) range.reverse(); - rangeBand = step * (1 - padding); - ranger = { - t: "rangeBands", - a: arguments - }; - return scale; - }; - scale.rangeRoundBands = function(x, padding, outerPadding) { - if (arguments.length < 2) padding = 0; - if (arguments.length < 3) outerPadding = padding; - var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step; - range = steps(start + Math.round(error / 2), step); - if (reverse) range.reverse(); - rangeBand = Math.round(step * (1 - padding)); - ranger = { - t: "rangeRoundBands", - a: arguments - }; - return scale; - }; - scale.rangeBand = function() { - return rangeBand; - }; - scale.rangeExtent = function() { - return d3_scaleExtent(ranger.a[0]); - }; - scale.copy = function() { - return d3_scale_ordinal(domain, ranger); - }; - return scale.domain(domain); - } - d3.scale.category10 = function() { - return d3.scale.ordinal().range(d3_category10); - }; - d3.scale.category20 = function() { - return d3.scale.ordinal().range(d3_category20); - }; - d3.scale.category20b = function() { - return d3.scale.ordinal().range(d3_category20b); - }; - d3.scale.category20c = function() { - return d3.scale.ordinal().range(d3_category20c); - }; - var d3_category10 = [ "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf" ]; - var d3_category20 = [ "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5" ]; - var d3_category20b = [ "#393b79", "#5254a3", "#6b6ecf", "#9c9ede", "#637939", "#8ca252", "#b5cf6b", "#cedb9c", "#8c6d31", "#bd9e39", "#e7ba52", "#e7cb94", "#843c39", "#ad494a", "#d6616b", "#e7969c", "#7b4173", "#a55194", "#ce6dbd", "#de9ed6" ]; - var d3_category20c = [ "#3182bd", "#6baed6", "#9ecae1", "#c6dbef", "#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", "#31a354", "#74c476", "#a1d99b", "#c7e9c0", "#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb", "#636363", "#969696", "#bdbdbd", "#d9d9d9" ]; - d3.scale.quantile = function() { - return d3_scale_quantile([], []); - }; - function d3_scale_quantile(domain, range) { - var thresholds; - function rescale() { - var k = 0, q = range.length; - thresholds = []; - while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); - return scale; - } - function scale(x) { - if (isNaN(x = +x)) return NaN; - return range[d3.bisect(thresholds, x)]; - } - scale.domain = function(x) { - if (!arguments.length) return domain; - domain = x.filter(function(d) { - return !isNaN(d); - }).sort(d3.ascending); - return rescale(); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - return rescale(); - }; - scale.quantiles = function() { - return thresholds; - }; - scale.copy = function() { - return d3_scale_quantile(domain, range); - }; - return rescale(); - } - d3.scale.quantize = function() { - return d3_scale_quantize(0, 1, [ 0, 1 ]); - }; - function d3_scale_quantize(x0, x1, range) { - var kx, i; - function scale(x) { - return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; - } - function rescale() { - kx = range.length / (x1 - x0); - i = range.length - 1; - return scale; - } - scale.domain = function(x) { - if (!arguments.length) return [ x0, x1 ]; - x0 = +x[0]; - x1 = +x[x.length - 1]; - return rescale(); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - return rescale(); - }; - scale.copy = function() { - return d3_scale_quantize(x0, x1, range); - }; - return rescale(); - } - d3.scale.threshold = function() { - return d3_scale_threshold([ .5 ], [ 0, 1 ]); - }; - function d3_scale_threshold(domain, range) { - function scale(x) { - return range[d3.bisect(domain, x)]; - } - scale.domain = function(_) { - if (!arguments.length) return domain; - domain = _; - return scale; - }; - scale.range = function(_) { - if (!arguments.length) return range; - range = _; - return scale; - }; - scale.copy = function() { - return d3_scale_threshold(domain, range); - }; - return scale; - } - d3.scale.identity = function() { - return d3_scale_identity([ 0, 1 ]); - }; - function d3_scale_identity(domain) { - function identity(x) { - return +x; - } - identity.invert = identity; - identity.domain = identity.range = function(x) { - if (!arguments.length) return domain; - domain = x.map(identity); - return identity; - }; - identity.ticks = function(m) { - return d3_scale_linearTicks(domain, m); - }; - identity.tickFormat = function(m) { - return d3_scale_linearTickFormat(domain, m); - }; - identity.copy = function() { - return d3_scale_identity(domain); - }; - return identity; - } - d3.svg = {}; - d3.svg.arc = function() { - var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; - function arc() { - var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, - a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1); - return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; - } - arc.innerRadius = function(v) { - if (!arguments.length) return innerRadius; - innerRadius = d3_functor(v); - return arc; - }; - arc.outerRadius = function(v) { - if (!arguments.length) return outerRadius; - outerRadius = d3_functor(v); - return arc; - }; - arc.startAngle = function(v) { - if (!arguments.length) return startAngle; - startAngle = d3_functor(v); - return arc; - }; - arc.endAngle = function(v) { - if (!arguments.length) return endAngle; - endAngle = d3_functor(v); - return arc; - }; - arc.centroid = function() { - var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; - return [ Math.cos(a) * r, Math.sin(a) * r ]; - }; - return arc; - }; - var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6; - function d3_svg_arcInnerRadius(d) { - return d.innerRadius; - } - function d3_svg_arcOuterRadius(d) { - return d.outerRadius; - } - function d3_svg_arcStartAngle(d) { - return d.startAngle; - } - function d3_svg_arcEndAngle(d) { - return d.endAngle; - } - function d3_svg_line(projection) { - var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; - function line(data) { - var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); - function segment() { - segments.push("M", interpolate(projection(points), tension)); - } - while (++i < n) { - if (defined.call(this, d = data[i], i)) { - points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); - } else if (points.length) { - segment(); - points = []; - } - } - if (points.length) segment(); - return segments.length ? segments.join("") : null; - } - line.x = function(_) { - if (!arguments.length) return x; - x = _; - return line; - }; - line.y = function(_) { - if (!arguments.length) return y; - y = _; - return line; - }; - line.defined = function(_) { - if (!arguments.length) return defined; - defined = _; - return line; - }; - line.interpolate = function(_) { - if (!arguments.length) return interpolateKey; - if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; - return line; - }; - line.tension = function(_) { - if (!arguments.length) return tension; - tension = _; - return line; - }; - return line; - } - d3.svg.line = function() { - return d3_svg_line(d3_identity); - }; - function d3_svg_lineX(d) { - return d[0]; - } - function d3_svg_lineY(d) { - return d[1]; - } - var d3_svg_lineInterpolators = d3.map({ - linear: d3_svg_lineLinear, - "linear-closed": d3_svg_lineLinearClosed, - "step-before": d3_svg_lineStepBefore, - "step-after": d3_svg_lineStepAfter, - basis: d3_svg_lineBasis, - "basis-open": d3_svg_lineBasisOpen, - "basis-closed": d3_svg_lineBasisClosed, - bundle: d3_svg_lineBundle, - cardinal: d3_svg_lineCardinal, - "cardinal-open": d3_svg_lineCardinalOpen, - "cardinal-closed": d3_svg_lineCardinalClosed, - monotone: d3_svg_lineMonotone - }); - d3_svg_lineInterpolators.forEach(function(key, value) { - value.key = key; - value.closed = /-closed$/.test(key); - }); - function d3_svg_lineLinear(points) { - return points.join("L"); - } - function d3_svg_lineLinearClosed(points) { - return d3_svg_lineLinear(points) + "Z"; - } - function d3_svg_lineStepBefore(points) { - var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; - while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); - return path.join(""); - } - function d3_svg_lineStepAfter(points) { - var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; - while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); - return path.join(""); - } - function d3_svg_lineCardinalOpen(points, tension) { - return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension)); - } - function d3_svg_lineCardinalClosed(points, tension) { - return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), - points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); - } - function d3_svg_lineCardinal(points, tension) { - return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); - } - function d3_svg_lineHermite(points, tangents) { - if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { - return d3_svg_lineLinear(points); - } - var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; - if (quad) { - path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; - p0 = points[1]; - pi = 2; - } - if (tangents.length > 1) { - t = tangents[1]; - p = points[pi]; - pi++; - path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; - for (var i = 2; i < tangents.length; i++, pi++) { - p = points[pi]; - t = tangents[i]; - path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; - } - } - if (quad) { - var lp = points[pi]; - path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; - } - return path; - } - function d3_svg_lineCardinalTangents(points, tension) { - var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; - while (++i < n) { - p0 = p1; - p1 = p2; - p2 = points[i]; - tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); - } - return tangents; - } - function d3_svg_lineBasis(points) { - if (points.length < 3) return d3_svg_lineLinear(points); - var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0 ]; - d3_svg_lineBasisBezier(path, px, py); - while (++i < n) { - pi = points[i]; - px.shift(); - px.push(pi[0]); - py.shift(); - py.push(pi[1]); - d3_svg_lineBasisBezier(path, px, py); - } - i = -1; - while (++i < 2) { - px.shift(); - px.push(pi[0]); - py.shift(); - py.push(pi[1]); - d3_svg_lineBasisBezier(path, px, py); - } - return path.join(""); - } - function d3_svg_lineBasisOpen(points) { - if (points.length < 4) return d3_svg_lineLinear(points); - var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; - while (++i < 3) { - pi = points[i]; - px.push(pi[0]); - py.push(pi[1]); - } - path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); - --i; - while (++i < n) { - pi = points[i]; - px.shift(); - px.push(pi[0]); - py.shift(); - py.push(pi[1]); - d3_svg_lineBasisBezier(path, px, py); - } - return path.join(""); - } - function d3_svg_lineBasisClosed(points) { - var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; - while (++i < 4) { - pi = points[i % n]; - px.push(pi[0]); - py.push(pi[1]); - } - path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; - --i; - while (++i < m) { - pi = points[i % n]; - px.shift(); - px.push(pi[0]); - py.shift(); - py.push(pi[1]); - d3_svg_lineBasisBezier(path, px, py); - } - return path.join(""); - } - function d3_svg_lineBundle(points, tension) { - var n = points.length - 1; - if (n) { - var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; - while (++i <= n) { - p = points[i]; - t = i / n; - p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); - p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); - } - } - return d3_svg_lineBasis(points); - } - function d3_svg_lineDot4(a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; - } - var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; - function d3_svg_lineBasisBezier(path, x, y) { - path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); - } - function d3_svg_lineSlope(p0, p1) { - return (p1[1] - p0[1]) / (p1[0] - p0[0]); - } - function d3_svg_lineFiniteDifferences(points) { - var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); - while (++i < j) { - m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; - } - m[i] = d; - return m; - } - function d3_svg_lineMonotoneTangents(points) { - var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; - while (++i < j) { - d = d3_svg_lineSlope(points[i], points[i + 1]); - if (Math.abs(d) < 1e-6) { - m[i] = m[i + 1] = 0; - } else { - a = m[i] / d; - b = m[i + 1] / d; - s = a * a + b * b; - if (s > 9) { - s = d * 3 / Math.sqrt(s); - m[i] = s * a; - m[i + 1] = s * b; - } - } - } - i = -1; - while (++i <= j) { - s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); - tangents.push([ s || 0, m[i] * s || 0 ]); - } - return tangents; - } - function d3_svg_lineMonotone(points) { - return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); - } - d3.svg.line.radial = function() { - var line = d3_svg_line(d3_svg_lineRadial); - line.radius = line.x, delete line.x; - line.angle = line.y, delete line.y; - return line; - }; - function d3_svg_lineRadial(points) { - var point, i = -1, n = points.length, r, a; - while (++i < n) { - point = points[i]; - r = point[0]; - a = point[1] + d3_svg_arcOffset; - point[0] = r * Math.cos(a); - point[1] = r * Math.sin(a); - } - return points; - } - function d3_svg_area(projection) { - var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; - function area(data) { - var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { - return x; - } : d3_functor(x1), fy1 = y0 === y1 ? function() { - return y; - } : d3_functor(y1), x, y; - function segment() { - segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); - } - while (++i < n) { - if (defined.call(this, d = data[i], i)) { - points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); - points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); - } else if (points0.length) { - segment(); - points0 = []; - points1 = []; - } - } - if (points0.length) segment(); - return segments.length ? segments.join("") : null; - } - area.x = function(_) { - if (!arguments.length) return x1; - x0 = x1 = _; - return area; - }; - area.x0 = function(_) { - if (!arguments.length) return x0; - x0 = _; - return area; - }; - area.x1 = function(_) { - if (!arguments.length) return x1; - x1 = _; - return area; - }; - area.y = function(_) { - if (!arguments.length) return y1; - y0 = y1 = _; - return area; - }; - area.y0 = function(_) { - if (!arguments.length) return y0; - y0 = _; - return area; - }; - area.y1 = function(_) { - if (!arguments.length) return y1; - y1 = _; - return area; - }; - area.defined = function(_) { - if (!arguments.length) return defined; - defined = _; - return area; - }; - area.interpolate = function(_) { - if (!arguments.length) return interpolateKey; - if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; - interpolateReverse = interpolate.reverse || interpolate; - L = interpolate.closed ? "M" : "L"; - return area; - }; - area.tension = function(_) { - if (!arguments.length) return tension; - tension = _; - return area; - }; - return area; - } - d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; - d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; - d3.svg.area = function() { - return d3_svg_area(d3_identity); - }; - d3.svg.area.radial = function() { - var area = d3_svg_area(d3_svg_lineRadial); - area.radius = area.x, delete area.x; - area.innerRadius = area.x0, delete area.x0; - area.outerRadius = area.x1, delete area.x1; - area.angle = area.y, delete area.y; - area.startAngle = area.y0, delete area.y0; - area.endAngle = area.y1, delete area.y1; - return area; - }; - d3.svg.chord = function() { - var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; - function chord(d, i) { - var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); - return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; - } - function subgroup(self, f, d, i) { - var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; - return { - r: r, - a0: a0, - a1: a1, - p0: [ r * Math.cos(a0), r * Math.sin(a0) ], - p1: [ r * Math.cos(a1), r * Math.sin(a1) ] - }; - } - function equals(a, b) { - return a.a0 == b.a0 && a.a1 == b.a1; - } - function arc(r, p, a) { - return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; - } - function curve(r0, p0, r1, p1) { - return "Q 0,0 " + p1; - } - chord.radius = function(v) { - if (!arguments.length) return radius; - radius = d3_functor(v); - return chord; - }; - chord.source = function(v) { - if (!arguments.length) return source; - source = d3_functor(v); - return chord; - }; - chord.target = function(v) { - if (!arguments.length) return target; - target = d3_functor(v); - return chord; - }; - chord.startAngle = function(v) { - if (!arguments.length) return startAngle; - startAngle = d3_functor(v); - return chord; - }; - chord.endAngle = function(v) { - if (!arguments.length) return endAngle; - endAngle = d3_functor(v); - return chord; - }; - return chord; - }; - function d3_svg_chordRadius(d) { - return d.radius; - } - d3.svg.diagonal = function() { - var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; - function diagonal(d, i) { - var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { - x: p0.x, - y: m - }, { - x: p3.x, - y: m - }, p3 ]; - p = p.map(projection); - return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; - } - diagonal.source = function(x) { - if (!arguments.length) return source; - source = d3_functor(x); - return diagonal; - }; - diagonal.target = function(x) { - if (!arguments.length) return target; - target = d3_functor(x); - return diagonal; - }; - diagonal.projection = function(x) { - if (!arguments.length) return projection; - projection = x; - return diagonal; - }; - return diagonal; - }; - function d3_svg_diagonalProjection(d) { - return [ d.x, d.y ]; - } - d3.svg.diagonal.radial = function() { - var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; - diagonal.projection = function(x) { - return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; - }; - return diagonal; - }; - function d3_svg_diagonalRadialProjection(projection) { - return function() { - var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset; - return [ r * Math.cos(a), r * Math.sin(a) ]; - }; - } - d3.svg.symbol = function() { - var type = d3_svg_symbolType, size = d3_svg_symbolSize; - function symbol(d, i) { - return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); - } - symbol.type = function(x) { - if (!arguments.length) return type; - type = d3_functor(x); - return symbol; - }; - symbol.size = function(x) { - if (!arguments.length) return size; - size = d3_functor(x); - return symbol; - }; - return symbol; - }; - function d3_svg_symbolSize() { - return 64; - } - function d3_svg_symbolType() { - return "circle"; - } - function d3_svg_symbolCircle(size) { - var r = Math.sqrt(size / π); - return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; - } - var d3_svg_symbols = d3.map({ - circle: d3_svg_symbolCircle, - cross: function(size) { - var r = Math.sqrt(size / 5) / 2; - return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; - }, - diamond: function(size) { - var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; - return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; - }, - square: function(size) { - var r = Math.sqrt(size) / 2; - return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; - }, - "triangle-down": function(size) { - var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; - return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; - }, - "triangle-up": function(size) { - var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; - return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; - } - }); - d3.svg.symbolTypes = d3_svg_symbols.keys(); - var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); - d3.svg.axis = function() { - var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0; - function axis(g) { - g.each(function() { - var g = d3.select(this); - var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_; - var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".tick.minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", ".tick").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1); - var tick = g.selectAll(".tick.major").data(ticks, String), tickEnter = tick.enter().insert("g", "path").attr("class", "tick major").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; - var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), - d3.transition(path)); - var scale1 = scale.copy(), scale0 = this.__chart__ || scale1; - this.__chart__ = scale1; - tickEnter.append("line"); - tickEnter.append("text"); - var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); - switch (orient) { - case "bottom": - { - tickTransform = d3_svg_axisX; - subtickEnter.attr("y2", tickMinorSize); - subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); - lineEnter.attr("y2", tickMajorSize); - textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding); - lineUpdate.attr("x2", 0).attr("y2", tickMajorSize); - textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding); - text.attr("dy", ".71em").style("text-anchor", "middle"); - pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); - break; - } - case "top": - { - tickTransform = d3_svg_axisX; - subtickEnter.attr("y2", -tickMinorSize); - subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); - lineEnter.attr("y2", -tickMajorSize); - textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); - lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize); - textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); - text.attr("dy", "0em").style("text-anchor", "middle"); - pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); - break; - } + return i + ? listener ? onAdd : onRemove + : listener ? d3_noop : removeAll; +} - case "left": - { - tickTransform = d3_svg_axisY; - subtickEnter.attr("x2", -tickMinorSize); - subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); - lineEnter.attr("x2", -tickMajorSize); - textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)); - lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0); - textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0); - text.attr("dy", ".32em").style("text-anchor", "end"); - pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); - break; - } +var d3_selection_onFilters = d3.map({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}); - case "right": - { - tickTransform = d3_svg_axisY; - subtickEnter.attr("x2", tickMinorSize); - subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); - lineEnter.attr("x2", tickMajorSize); - textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding); - lineUpdate.attr("x2", tickMajorSize).attr("y2", 0); - textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0); - text.attr("dy", ".32em").style("text-anchor", "start"); - pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); - break; - } - } - if (scale.ticks) { - tickEnter.call(tickTransform, scale0); - tickUpdate.call(tickTransform, scale1); - tickExit.call(tickTransform, scale1); - subtickEnter.call(tickTransform, scale0); - subtickUpdate.call(tickTransform, scale1); - subtickExit.call(tickTransform, scale1); - } else { - var dx = scale1.rangeBand() / 2, x = function(d) { - return scale1(d) + dx; - }; - tickEnter.call(tickTransform, x); - tickUpdate.call(tickTransform, x); - } - }); +d3_selection_onFilters.forEach(function(k) { + if ("on" + k in d3_document) d3_selection_onFilters.remove(k); +}); + +function d3_selection_onListener(listener, argumentz) { + return function(e) { + var o = d3.event; // Events can be reentrant (e.g., focus). + d3.event = e; + argumentz[0] = this.__data__; + try { + listener.apply(this, argumentz); + } finally { + d3.event = o; } - axis.scale = function(x) { - if (!arguments.length) return scale; - scale = x; - return axis; - }; - axis.orient = function(x) { - if (!arguments.length) return orient; - orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; - return axis; - }; - axis.ticks = function() { - if (!arguments.length) return tickArguments_; - tickArguments_ = arguments; - return axis; - }; - axis.tickValues = function(x) { - if (!arguments.length) return tickValues; - tickValues = x; - return axis; - }; - axis.tickFormat = function(x) { - if (!arguments.length) return tickFormat_; - tickFormat_ = x; - return axis; - }; - axis.tickSize = function(x, y) { - if (!arguments.length) return tickMajorSize; - var n = arguments.length - 1; - tickMajorSize = +x; - tickMinorSize = n > 1 ? +y : tickMajorSize; - tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; - return axis; - }; - axis.tickPadding = function(x) { - if (!arguments.length) return tickPadding; - tickPadding = +x; - return axis; - }; - axis.tickSubdivide = function(x) { - if (!arguments.length) return tickSubdivide; - tickSubdivide = +x; - return axis; - }; - return axis; }; - var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { - top: 1, - right: 1, - bottom: 1, - left: 1 +} + +function d3_selection_onFilter(listener, argumentz) { + var l = d3_selection_onListener(listener, argumentz); + return function(e) { + var target = this, related = e.relatedTarget; + if (!related || (related !== target && !(related.compareDocumentPosition(target) & 8))) { + l.call(target, e); + } }; - function d3_svg_axisX(selection, x) { - selection.attr("transform", function(d) { - return "translate(" + x(d) + ",0)"; - }); +} + +d3_selectionPrototype.each = function(callback) { + return d3_selection_each(this, function(node, i, j) { + callback.call(node, node.__data__, i, j); + }); +}; + +function d3_selection_each(groups, callback) { + for (var j = 0, m = groups.length; j < m; j++) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { + if (node = group[i]) callback(node, i, j); + } } - function d3_svg_axisY(selection, y) { - selection.attr("transform", function(d) { - return "translate(0," + y(d) + ")"; - }); + return groups; +} + +d3_selectionPrototype.call = function(callback) { + var args = d3_array(arguments); + callback.apply(args[0] = this, args); + return this; +}; + +d3_selectionPrototype.empty = function() { + return !this.node(); +}; + +d3_selectionPrototype.node = function() { + for (var j = 0, m = this.length; j < m; j++) { + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + var node = group[i]; + if (node) return node; + } } - function d3_svg_axisSubdivide(scale, ticks, m) { - subticks = []; - if (m && ticks.length > 1) { - var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v; - while (++i < n) { - for (j = m; --j > 0; ) { - if ((v = +ticks[i] - j * d) >= extent[0]) { - subticks.push(v); - } - } - } - for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) { - subticks.push(v); - } - } - return subticks; - } - d3.svg.brush = function() { - var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], extentDomain; - function brush(g) { - g.each(function() { - var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e; - g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); - bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); - fg.enter().append("rect").attr("class", "extent").style("cursor", "move"); - tz.enter().append("g").attr("class", function(d) { - return "resize " + d; - }).style("cursor", function(d) { - return d3_svg_brushCursor[d]; - }).append("rect").attr("x", function(d) { - return /[ew]$/.test(d) ? -3 : null; - }).attr("y", function(d) { - return /^[ns]/.test(d) ? -3 : null; - }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); - tz.style("display", brush.empty() ? "none" : null); - tz.exit().remove(); - if (x) { - e = d3_scaleRange(x); - bg.attr("x", e[0]).attr("width", e[1] - e[0]); - redrawX(g); - } - if (y) { - e = d3_scaleRange(y); - bg.attr("y", e[0]).attr("height", e[1] - e[0]); - redrawY(g); - } - redraw(g); - }); - } - function redraw(g) { - g.selectAll(".resize").attr("transform", function(d) { - return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")"; - }); - } - function redrawX(g) { - g.select(".extent").attr("x", extent[0][0]); - g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]); - } - function redrawY(g) { - g.select(".extent").attr("y", extent[0][1]); - g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]); - } - function brushstart() { - var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), center, origin = mouse(), offset; - var w = d3.select(d3_window).on("mousemove.brush", brushmove).on("mouseup.brush", brushend).on("touchmove.brush", brushmove).on("touchend.brush", brushend).on("keydown.brush", keydown).on("keyup.brush", keyup); - if (dragging) { - origin[0] = extent[0][0] - origin[0]; - origin[1] = extent[0][1] - origin[1]; - } else if (resizing) { - var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); - offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ]; - origin[0] = extent[ex][0]; - origin[1] = extent[ey][1]; - } else if (d3.event.altKey) center = origin.slice(); - g.style("pointer-events", "none").selectAll(".resize").style("display", null); - d3.select("body").style("cursor", eventTarget.style("cursor")); - event_({ - type: "brushstart" - }); - brushmove(); - d3_eventCancel(); - function mouse() { - var touches = d3.event.changedTouches; - return touches ? d3.touches(target, touches)[0] : d3.mouse(target); - } - function keydown() { - if (d3.event.keyCode == 32) { - if (!dragging) { - center = null; - origin[0] -= extent[1][0]; - origin[1] -= extent[1][1]; - dragging = 2; - } - d3_eventCancel(); - } - } - function keyup() { - if (d3.event.keyCode == 32 && dragging == 2) { - origin[0] += extent[1][0]; - origin[1] += extent[1][1]; - dragging = 0; - d3_eventCancel(); - } - } - function brushmove() { - var point = mouse(), moved = false; - if (offset) { - point[0] += offset[0]; - point[1] += offset[1]; - } - if (!dragging) { - if (d3.event.altKey) { - if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ]; - origin[0] = extent[+(point[0] < center[0])][0]; - origin[1] = extent[+(point[1] < center[1])][1]; - } else center = null; - } - if (resizingX && move1(point, x, 0)) { - redrawX(g); - moved = true; - } - if (resizingY && move1(point, y, 1)) { - redrawY(g); - moved = true; - } - if (moved) { - redraw(g); - event_({ - type: "brush", - mode: dragging ? "move" : "resize" - }); - } - } - function move1(point, scale, i) { - var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max; - if (dragging) { - r0 -= position; - r1 -= size + position; - } - min = Math.max(r0, Math.min(r1, point[i])); - if (dragging) { - max = (min += position) + size; - } else { - if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); - if (position < min) { - max = min; - min = position; - } else { - max = position; - } - } - if (extent[0][i] !== min || extent[1][i] !== max) { - extentDomain = null; - extent[0][i] = min; - extent[1][i] = max; - return true; - } - } - function brushend() { - brushmove(); - g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); - d3.select("body").style("cursor", null); - w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); - event_({ - type: "brushend" - }); - d3_eventCancel(); - } - } - brush.x = function(z) { - if (!arguments.length) return x; - x = z; - resizes = d3_svg_brushResizes[!x << 1 | !y]; - return brush; - }; - brush.y = function(z) { - if (!arguments.length) return y; - y = z; - resizes = d3_svg_brushResizes[!x << 1 | !y]; - return brush; - }; - brush.extent = function(z) { - var x0, x1, y0, y1, t; - if (!arguments.length) { - z = extentDomain || extent; - if (x) { - x0 = z[0][0], x1 = z[1][0]; - if (!extentDomain) { - x0 = extent[0][0], x1 = extent[1][0]; - if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); - if (x1 < x0) t = x0, x0 = x1, x1 = t; - } - } - if (y) { - y0 = z[0][1], y1 = z[1][1]; - if (!extentDomain) { - y0 = extent[0][1], y1 = extent[1][1]; - if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); - if (y1 < y0) t = y0, y0 = y1, y1 = t; - } - } - return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; - } - extentDomain = [ [ 0, 0 ], [ 0, 0 ] ]; - if (x) { - x0 = z[0], x1 = z[1]; - if (y) x0 = x0[0], x1 = x1[0]; - extentDomain[0][0] = x0, extentDomain[1][0] = x1; - if (x.invert) x0 = x(x0), x1 = x(x1); - if (x1 < x0) t = x0, x0 = x1, x1 = t; - extent[0][0] = x0 | 0, extent[1][0] = x1 | 0; - } - if (y) { - y0 = z[0], y1 = z[1]; - if (x) y0 = y0[1], y1 = y1[1]; - extentDomain[0][1] = y0, extentDomain[1][1] = y1; - if (y.invert) y0 = y(y0), y1 = y(y1); - if (y1 < y0) t = y0, y0 = y1, y1 = t; - extent[0][1] = y0 | 0, extent[1][1] = y1 | 0; - } - return brush; - }; - brush.clear = function() { - extentDomain = null; - extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0; - return brush; - }; - brush.empty = function() { - return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1]; - }; - return d3.rebind(brush, event, "on"); - }; - var d3_svg_brushCursor = { - n: "ns-resize", - e: "ew-resize", - s: "ns-resize", - w: "ew-resize", - nw: "nwse-resize", - ne: "nesw-resize", - se: "nwse-resize", - sw: "nesw-resize" - }; - var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; - d3.behavior = {}; - d3.behavior.drag = function() { - var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null; - function drag() { - this.on("mousedown.drag", mousedown).on("touchstart.drag", mousedown); - } - function mousedown() { - var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null, offset, origin_ = point(), moved = 0; - var w = d3.select(d3_window).on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", dragmove).on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", dragend, true); - if (origin) { - offset = origin.apply(target, arguments); - offset = [ offset.x - origin_[0], offset.y - origin_[1] ]; + return null; +}; + +function d3_selection_enter(selection) { + d3_arraySubclass(selection, d3_selection_enterPrototype); + return selection; +} + +var d3_selection_enterPrototype = []; + +d3.selection.enter = d3_selection_enter; +d3.selection.enter.prototype = d3_selection_enterPrototype; + +d3_selection_enterPrototype.append = d3_selectionPrototype.append; +d3_selection_enterPrototype.insert = d3_selectionPrototype.insert; +d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; +d3_selection_enterPrototype.node = d3_selectionPrototype.node; + + +d3_selection_enterPrototype.select = function(selector) { + var subgroups = [], + subgroup, + subnode, + upgroup, + group, + node; + + for (var j = -1, m = this.length; ++j < m;) { + upgroup = (group = this[j]).update; + subgroups.push(subgroup = []); + subgroup.parentNode = group.parentNode; + for (var i = -1, n = group.length; ++i < n;) { + if (node = group[i]) { + subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i)); + subnode.__data__ = node.__data__; } else { - offset = [ 0, 0 ]; - } - if (touchId == null) d3_eventCancel(); - event_({ - type: "dragstart" - }); - function point() { - var p = target.parentNode; - return touchId != null ? d3.touches(p).filter(function(p) { - return p.identifier === touchId; - })[0] : d3.mouse(p); - } - function dragmove() { - if (!target.parentNode) return dragend(); - var p = point(), dx = p[0] - origin_[0], dy = p[1] - origin_[1]; - moved |= dx | dy; - origin_ = p; - d3_eventCancel(); - event_({ - type: "drag", - x: p[0] + offset[0], - y: p[1] + offset[1], - dx: dx, - dy: dy - }); - } - function dragend() { - event_({ - type: "dragend" - }); - if (moved) { - d3_eventCancel(); - if (d3.event.target === eventTarget) w.on("click.drag", click, true); - } - w.on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", null).on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", null); - } - function click() { - d3_eventCancel(); - w.on("click.drag", null); + subgroup.push(null); } } - drag.origin = function(x) { - if (!arguments.length) return origin; - origin = x; - return drag; - }; - return d3.rebind(drag, event, "on"); + } + + return d3_selection(subgroups); +}; + +d3_selectionPrototype.transition = function() { + var id = d3_transitionInheritId || ++d3_transitionId, + subgroups = [], + subgroup, + node, + transition = Object.create(d3_transitionInherit); + + transition.time = Date.now(); + + for (var j = -1, m = this.length; ++j < m;) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n;) { + if (node = group[i]) d3_transitionNode(node, i, id, transition); + subgroup.push(node); + } + } + + return d3_transition(subgroups, id); +}; + +var d3_selectionRoot = d3_selection([[d3_document]]); + +d3_selectionRoot[0].parentNode = d3_selectRoot; + +// TODO fast singleton implementation! +// TODO select(function) +d3.select = function(selector) { + return typeof selector === "string" + ? d3_selectionRoot.select(selector) + : d3_selection([[selector]]); // assume node +}; + +// TODO selectAll(function) +d3.selectAll = function(selector) { + return typeof selector === "string" + ? d3_selectionRoot.selectAll(selector) + : d3_selection([d3_array(selector)]); // assume node[] +}; + +d3.behavior.zoom = function() { + var translate = [0, 0], + translate0, // translate when we started zooming (to avoid drift) + scale = 1, + scale0, // scale when we started touching + scaleExtent = d3_behavior_zoomInfinity, + event = d3_eventDispatch(zoom, "zoom"), + x0, + x1, + y0, + y1, + touchtime; // time of last touchstart (to detect double-tap) + + function zoom() { + this.on("mousedown.zoom", mousedown) + .on("mousemove.zoom", mousemove) + .on(d3_behavior_zoomWheel + ".zoom", mousewheel) + .on("dblclick.zoom", dblclick) + .on("touchstart.zoom", touchstart) + .on("touchmove.zoom", touchmove) + .on("touchend.zoom", touchstart); + } + + zoom.translate = function(x) { + if (!arguments.length) return translate; + translate = x.map(Number); + rescale(); + return zoom; }; - d3.behavior.zoom = function() { - var translate = [ 0, 0 ], translate0, scale = 1, scale0, scaleExtent = d3_behavior_zoomInfinity, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1, touchtime; - function zoom() { - this.on("mousedown.zoom", mousedown).on("mousemove.zoom", mousemove).on(d3_behavior_zoomWheel + ".zoom", mousewheel).on("dblclick.zoom", dblclick).on("touchstart.zoom", touchstart).on("touchmove.zoom", touchmove).on("touchend.zoom", touchstart); - } - zoom.translate = function(x) { - if (!arguments.length) return translate; - translate = x.map(Number); - rescale(); - return zoom; - }; - zoom.scale = function(x) { - if (!arguments.length) return scale; - scale = +x; - rescale(); - return zoom; - }; - zoom.scaleExtent = function(x) { - if (!arguments.length) return scaleExtent; - scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number); - return zoom; - }; - zoom.x = function(z) { - if (!arguments.length) return x1; - x1 = z; - x0 = z.copy(); - translate = [ 0, 0 ]; - scale = 1; - return zoom; - }; - zoom.y = function(z) { - if (!arguments.length) return y1; - y1 = z; - y0 = z.copy(); - translate = [ 0, 0 ]; - scale = 1; - return zoom; - }; - function location(p) { - return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ]; - } - function point(l) { - return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ]; - } - function scaleTo(s) { - scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); - } - function translateTo(p, l) { - l = point(l); - translate[0] += p[0] - l[0]; - translate[1] += p[1] - l[1]; - } - function rescale() { - if (x1) x1.domain(x0.range().map(function(x) { - return (x - translate[0]) / scale; - }).map(x0.invert)); - if (y1) y1.domain(y0.range().map(function(y) { - return (y - translate[1]) / scale; - }).map(y0.invert)); - } - function dispatch(event) { - rescale(); - d3.event.preventDefault(); - event({ - type: "zoom", - scale: scale, - translate: translate - }); - } - function mousedown() { - var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, moved = 0, w = d3.select(d3_window).on("mousemove.zoom", mousemove).on("mouseup.zoom", mouseup), l = location(d3.mouse(target)); - d3_window.focus(); - d3_eventCancel(); - function mousemove() { - moved = 1; - translateTo(d3.mouse(target), l); - dispatch(event_); - } - function mouseup() { - if (moved) d3_eventCancel(); - w.on("mousemove.zoom", null).on("mouseup.zoom", null); - if (moved && d3.event.target === eventTarget) { - w.on("click.zoom", click, true); - window.setTimeout(function() { - // Remove click block if click didn't fire - w.on("click.zoom", null); - }, 0); - } - } - function click() { - d3_eventCancel(); - w.on("click.zoom", null); - } - } - function mousewheel() { - if (!translate0) translate0 = location(d3.mouse(this)); - scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale); - translateTo(d3.mouse(this), translate0); - dispatch(event.of(this, arguments)); - } + + zoom.scale = function(x) { + if (!arguments.length) return scale; + scale = +x; + rescale(); + return zoom; + }; + + zoom.scaleExtent = function(x) { + if (!arguments.length) return scaleExtent; + scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number); + return zoom; + }; + + zoom.x = function(z) { + if (!arguments.length) return x1; + x1 = z; + x0 = z.copy(); + translate = [0, 0]; + scale = 1; + return zoom; + }; + + zoom.y = function(z) { + if (!arguments.length) return y1; + y1 = z; + y0 = z.copy(); + translate = [0, 0]; + scale = 1; + return zoom; + }; + + function location(p) { + return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale]; + } + + function point(l) { + return [l[0] * scale + translate[0], l[1] * scale + translate[1]]; + } + + function scaleTo(s) { + scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); + } + + function translateTo(p, l) { + l = point(l); + translate[0] += p[0] - l[0]; + translate[1] += p[1] - l[1]; + } + + function rescale() { + if (x1) x1.domain(x0.range().map(function(x) { return (x - translate[0]) / scale; }).map(x0.invert)); + if (y1) y1.domain(y0.range().map(function(y) { return (y - translate[1]) / scale; }).map(y0.invert)); + } + + function dispatch(event) { + rescale(); + d3.event.preventDefault(); + event({type: "zoom", scale: scale, translate: translate}); + } + + function mousedown() { + var target = this, + event_ = event.of(target, arguments), + eventTarget = d3.event.target, + moved = 0, + w = d3.select(d3_window).on("mousemove.zoom", mousemove).on("mouseup.zoom", mouseup), + l = location(d3.mouse(target)); + + d3_window.focus(); + d3_eventCancel(); + function mousemove() { - translate0 = null; + moved = 1; + translateTo(d3.mouse(target), l); + dispatch(event_); } - function dblclick() { - var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2; - scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1)); - translateTo(p, l); - dispatch(event.of(this, arguments)); + + function mouseup() { + if (moved) d3_eventCancel(); + w.on("mousemove.zoom", null).on("mouseup.zoom", null); + if (moved && d3.event.target === eventTarget) w.on("click.zoom", click, true); } - function touchstart() { - var touches = d3.touches(this), now = Date.now(); - scale0 = scale; - translate0 = {}; - touches.forEach(function(t) { - translate0[t.identifier] = location(t); - }); + + function click() { d3_eventCancel(); - if (touches.length === 1) { - if (now - touchtime < 500) { - var p = touches[0], l = location(touches[0]); - scaleTo(scale * 2); - translateTo(p, l); - dispatch(event.of(this, arguments)); - } - touchtime = now; - } + w.on("click.zoom", null); } - function touchmove() { - var touches = d3.touches(this), p0 = touches[0], l0 = translate0[p0.identifier]; - if (p1 = touches[1]) { - var p1, l1 = translate0[p1.identifier]; - p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; - l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; - scaleTo(d3.event.scale * scale0); + } + + function mousewheel() { + if (!translate0) translate0 = location(d3.mouse(this)); + scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale); + translateTo(d3.mouse(this), translate0); + dispatch(event.of(this, arguments)); + } + + function mousemove() { + translate0 = null; + } + + function dblclick() { + var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2; + scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1)); + translateTo(p, l); + dispatch(event.of(this, arguments)); + } + + function touchstart() { + var touches = d3.touches(this), + now = Date.now(); + + scale0 = scale; + translate0 = {}; + touches.forEach(function(t) { translate0[t.identifier] = location(t); }); + d3_eventCancel(); + + if (touches.length === 1) { + if (now - touchtime < 500) { // dbltap + var p = touches[0], l = location(touches[0]); + scaleTo(scale * 2); + translateTo(p, l); + dispatch(event.of(this, arguments)); } - translateTo(p0, l0); - touchtime = null; - dispatch(event.of(this, arguments)); + touchtime = now; } - return d3.rebind(zoom, event, "on"); + } + + function touchmove() { + var touches = d3.touches(this), + p0 = touches[0], + l0 = translate0[p0.identifier]; + if (p1 = touches[1]) { + var p1, l1 = translate0[p1.identifier]; + p0 = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2]; + l0 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2]; + scaleTo(d3.event.scale * scale0); + } + translateTo(p0, l0); + touchtime = null; + dispatch(event.of(this, arguments)); + } + + return d3.rebind(zoom, event, "on"); +}; + +var d3_behavior_zoomInfinity = [0, Infinity]; // default scale extent + +// https://developer.mozilla.org/en-US/docs/Mozilla_event_reference/wheel +var d3_behavior_zoomDelta, d3_behavior_zoomWheel + = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); }, "wheel") + : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { return d3.event.wheelDelta; }, "mousewheel") + : (d3_behavior_zoomDelta = function() { return -d3.event.detail; }, "MozMousePixelScroll"); +function d3_functor(v) { + return typeof v === "function" ? v : function() { return v; }; +} + +d3.functor = d3_functor; + +var d3_timer_id = 0, + d3_timer_byId = {}, + d3_timer_queue = null, + d3_timer_interval, // is an interval (or frame) active? + d3_timer_timeout; // is a timeout active? + +// The timer will continue to fire until callback returns true. +d3.timer = function(callback, delay, then) { + if (arguments.length < 3) { + if (arguments.length < 2) delay = 0; + else if (!isFinite(delay)) return; + then = Date.now(); + } + + // If the callback's already in the queue, update it. + var timer = d3_timer_byId[callback.id]; + if (timer && timer.callback === callback) { + timer.then = then; + timer.delay = delay; + } + + // Otherwise, add the callback to the queue. + else d3_timer_byId[callback.id = ++d3_timer_id] = d3_timer_queue = { + callback: callback, + then: then, + delay: delay, + next: d3_timer_queue }; - var d3_behavior_zoomInfinity = [ 0, Infinity ]; - var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in document ? (d3_behavior_zoomDelta = function() { - return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); - }, "wheel") : "onmousewheel" in document ? (d3_behavior_zoomDelta = function() { - return d3.event.wheelDelta; - }, "mousewheel") : (d3_behavior_zoomDelta = function() { - return -d3.event.detail; - }, "MozMousePixelScroll"); - d3.layout = {}; - d3.layout.bundle = function() { - return function(links) { - var paths = [], i = -1, n = links.length; - while (++i < n) paths.push(d3_layout_bundlePath(links[i])); - return paths; - }; - }; - function d3_layout_bundlePath(link) { - var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; - while (start !== lca) { - start = start.parent; - points.push(start); + + // Start animatin'! + if (!d3_timer_interval) { + d3_timer_timeout = clearTimeout(d3_timer_timeout); + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } +}; + +function d3_timer_step() { + var elapsed, + now = Date.now(), + t1 = d3_timer_queue; + + while (t1) { + elapsed = now - t1.then; + if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed); + t1 = t1.next; + } + + var delay = d3_timer_flush() - now; + if (delay > 24) { + if (isFinite(delay)) { + clearTimeout(d3_timer_timeout); + d3_timer_timeout = setTimeout(d3_timer_step, delay); } - var k = points.length; - while (end !== lca) { - points.splice(k, 0, end); - end = end.parent; - } - return points; + d3_timer_interval = 0; + } else { + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); } - function d3_layout_bundleAncestors(node) { - var ancestors = [], parent = node.parent; - while (parent != null) { - ancestors.push(node); - node = parent; - parent = parent.parent; - } - ancestors.push(node); - return ancestors; +} + +d3.timer.flush = function() { + var elapsed, + now = Date.now(), + t1 = d3_timer_queue; + + while (t1) { + elapsed = now - t1.then; + if (!t1.delay) t1.flush = t1.callback(elapsed); + t1 = t1.next; } - function d3_layout_bundleLeastCommonAncestor(a, b) { - if (a === b) return a; - var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; - while (aNode === bNode) { - sharedNode = aNode; - aNode = aNodes.pop(); - bNode = bNodes.pop(); - } - return sharedNode; - } - d3.layout.chord = function() { - var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; - function relayout() { - var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; - chords = []; - groups = []; - k = 0, i = -1; - while (++i < n) { - x = 0, j = -1; - while (++j < n) { - x += matrix[i][j]; - } - groupSums.push(x); - subgroupIndex.push(d3.range(n)); - k += x; - } - if (sortGroups) { - groupIndex.sort(function(a, b) { - return sortGroups(groupSums[a], groupSums[b]); - }); - } - if (sortSubgroups) { - subgroupIndex.forEach(function(d, i) { - d.sort(function(a, b) { - return sortSubgroups(matrix[i][a], matrix[i][b]); - }); - }); - } - k = (2 * π - padding * n) / k; - x = 0, i = -1; - while (++i < n) { - x0 = x, j = -1; - while (++j < n) { - var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; - subgroups[di + "-" + dj] = { - index: di, - subindex: dj, - startAngle: a0, - endAngle: a1, - value: v - }; - } - groups[di] = { - index: di, - startAngle: x0, - endAngle: x, - value: (x - x0) / k - }; - x += padding; - } - i = -1; - while (++i < n) { - j = i - 1; - while (++j < n) { - var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; - if (source.value || target.value) { - chords.push(source.value < target.value ? { - source: target, - target: source - } : { - source: source, - target: target - }); - } - } - } - if (sortChords) resort(); - } - function resort() { - chords.sort(function(a, b) { - return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); - }); - } - chord.matrix = function(x) { - if (!arguments.length) return matrix; - n = (matrix = x) && matrix.length; - chords = groups = null; - return chord; - }; - chord.padding = function(x) { - if (!arguments.length) return padding; - padding = x; - chords = groups = null; - return chord; - }; - chord.sortGroups = function(x) { - if (!arguments.length) return sortGroups; - sortGroups = x; - chords = groups = null; - return chord; - }; - chord.sortSubgroups = function(x) { - if (!arguments.length) return sortSubgroups; - sortSubgroups = x; - chords = null; - return chord; - }; - chord.sortChords = function(x) { - if (!arguments.length) return sortChords; - sortChords = x; - if (chords) resort(); - return chord; - }; - chord.chords = function() { - if (!chords) relayout(); - return chords; - }; - chord.groups = function() { - if (!groups) relayout(); - return groups; - }; - return chord; - }; - d3.layout.force = function() { - var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges; - function repulse(node) { - return function(quad, x1, _, x2) { - if (quad.point !== node) { - var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy); - if ((x2 - x1) * dn < theta) { - var k = quad.charge * dn * dn; - node.px -= dx * k; - node.py -= dy * k; - return true; - } - if (quad.point && isFinite(dn)) { - var k = quad.pointCharge * dn * dn; - node.px -= dx * k; - node.py -= dy * k; - } - } - return !quad.charge; - }; - } - force.tick = function() { - if ((alpha *= .99) < .005) { - event.end({ - type: "end", - alpha: alpha = 0 - }); - return true; - } - var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; - for (i = 0; i < m; ++i) { - o = links[i]; - s = o.source; - t = o.target; - x = t.x - s.x; - y = t.y - s.y; - if (l = x * x + y * y) { - l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; - x *= l; - y *= l; - t.x -= x * (k = s.weight / (t.weight + s.weight)); - t.y -= y * k; - s.x += x * (k = 1 - k); - s.y += y * k; - } - } - if (k = alpha * gravity) { - x = size[0] / 2; - y = size[1] / 2; - i = -1; - if (k) while (++i < n) { - o = nodes[i]; - o.x += (x - o.x) * k; - o.y += (y - o.y) * k; - } - } - if (charge) { - d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); - i = -1; - while (++i < n) { - if (!(o = nodes[i]).fixed) { - q.visit(repulse(o)); - } - } - } - i = -1; - while (++i < n) { - o = nodes[i]; - if (o.fixed) { - o.x = o.px; - o.y = o.py; - } else { - o.x -= (o.px - (o.px = o.x)) * friction; - o.y -= (o.py - (o.py = o.y)) * friction; - } - } - event.tick({ - type: "tick", - alpha: alpha - }); - }; - force.nodes = function(x) { - if (!arguments.length) return nodes; - nodes = x; - return force; - }; - force.links = function(x) { - if (!arguments.length) return links; - links = x; - return force; - }; - force.size = function(x) { - if (!arguments.length) return size; - size = x; - return force; - }; - force.linkDistance = function(x) { - if (!arguments.length) return linkDistance; - linkDistance = typeof x === "function" ? x : +x; - return force; - }; - force.distance = force.linkDistance; - force.linkStrength = function(x) { - if (!arguments.length) return linkStrength; - linkStrength = typeof x === "function" ? x : +x; - return force; - }; - force.friction = function(x) { - if (!arguments.length) return friction; - friction = +x; - return force; - }; - force.charge = function(x) { - if (!arguments.length) return charge; - charge = typeof x === "function" ? x : +x; - return force; - }; - force.gravity = function(x) { - if (!arguments.length) return gravity; - gravity = +x; - return force; - }; - force.theta = function(x) { - if (!arguments.length) return theta; - theta = +x; - return force; - }; - force.alpha = function(x) { - if (!arguments.length) return alpha; - x = +x; - if (alpha) { - if (x > 0) alpha = x; else alpha = 0; - } else if (x > 0) { - event.start({ - type: "start", - alpha: alpha = x - }); - d3.timer(force.tick); - } - return force; - }; - force.start = function() { - var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; - for (i = 0; i < n; ++i) { - (o = nodes[i]).index = i; - o.weight = 0; - } - for (i = 0; i < m; ++i) { - o = links[i]; - if (typeof o.source == "number") o.source = nodes[o.source]; - if (typeof o.target == "number") o.target = nodes[o.target]; - ++o.source.weight; - ++o.target.weight; - } - for (i = 0; i < n; ++i) { - o = nodes[i]; - if (isNaN(o.x)) o.x = position("x", w); - if (isNaN(o.y)) o.y = position("y", h); - if (isNaN(o.px)) o.px = o.x; - if (isNaN(o.py)) o.py = o.y; - } - distances = []; - if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance; - strengths = []; - if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength; - charges = []; - if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge; - function position(dimension, size) { - var neighbors = neighbor(i), j = -1, m = neighbors.length, x; - while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x; - return Math.random() * size; - } - function neighbor() { - if (!neighbors) { - neighbors = []; - for (j = 0; j < n; ++j) { - neighbors[j] = []; - } - for (j = 0; j < m; ++j) { - var o = links[j]; - neighbors[o.source.index].push(o.target); - neighbors[o.target.index].push(o.source); - } - } - return neighbors[i]; - } - return force.resume(); - }; - force.resume = function() { - return force.alpha(.1); - }; - force.stop = function() { - return force.alpha(0); - }; - force.drag = function() { - if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend); - if (!arguments.length) return drag; - this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); - }; - function dragmove(d) { - d.px = d3.event.x, d.py = d3.event.y; - force.resume(); - } - return d3.rebind(force, event, "on"); - }; - function d3_layout_forceDragstart(d) { - d.fixed |= 2; - } - function d3_layout_forceDragend(d) { - d.fixed &= ~6; - } - function d3_layout_forceMouseover(d) { - d.fixed |= 4; - d.px = d.x, d.py = d.y; - } - function d3_layout_forceMouseout(d) { - d.fixed &= ~4; - } - function d3_layout_forceAccumulate(quad, alpha, charges) { - var cx = 0, cy = 0; - quad.charge = 0; - if (!quad.leaf) { - var nodes = quad.nodes, n = nodes.length, i = -1, c; - while (++i < n) { - c = nodes[i]; - if (c == null) continue; - d3_layout_forceAccumulate(c, alpha, charges); - quad.charge += c.charge; - cx += c.charge * c.cx; - cy += c.charge * c.cy; - } - } - if (quad.point) { - if (!quad.leaf) { - quad.point.x += Math.random() - .5; - quad.point.y += Math.random() - .5; - } - var k = alpha * charges[quad.point.index]; - quad.charge += quad.pointCharge = k; - cx += k * quad.point.x; - cy += k * quad.point.y; - } - quad.cx = cx / quad.charge; - quad.cy = cy / quad.charge; - } - var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1; - d3.layout.partition = function() { - var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; - function position(node, x, dx, dy) { - var children = node.children; - node.x = x; - node.y = node.depth * dy; - node.dx = dx; - node.dy = dy; - if (children && (n = children.length)) { - var i = -1, n, c, d; - dx = node.value ? dx / node.value : 0; - while (++i < n) { - position(c = children[i], x, d = c.value * dx, dy); - x += d; - } - } - } - function depth(node) { - var children = node.children, d = 0; - if (children && (n = children.length)) { - var i = -1, n; - while (++i < n) d = Math.max(d, depth(children[i])); - } - return 1 + d; - } - function partition(d, i) { - var nodes = hierarchy.call(this, d, i); - position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); - return nodes; - } - partition.size = function(x) { - if (!arguments.length) return size; - size = x; - return partition; - }; - return d3_layout_hierarchyRebind(partition, hierarchy); - }; - d3.layout.pie = function() { - var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * π; - function pie(data) { - var values = data.map(function(d, i) { - return +value.call(pie, d, i); - }); - var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle); - var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - startAngle) / d3.sum(values); - var index = d3.range(data.length); - if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { - return values[j] - values[i]; - } : function(i, j) { - return sort(data[i], data[j]); - }); - var arcs = []; - index.forEach(function(i) { - var d; - arcs[i] = { - data: data[i], - value: d = values[i], - startAngle: a, - endAngle: a += d * k - }; - }); - return arcs; - } - pie.value = function(x) { - if (!arguments.length) return value; - value = x; - return pie; - }; - pie.sort = function(x) { - if (!arguments.length) return sort; - sort = x; - return pie; - }; - pie.startAngle = function(x) { - if (!arguments.length) return startAngle; - startAngle = x; - return pie; - }; - pie.endAngle = function(x) { - if (!arguments.length) return endAngle; - endAngle = x; - return pie; - }; - return pie; - }; - var d3_layout_pieSortByValue = {}; - d3.layout.stack = function() { - var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; - function stack(data, index) { - var series = data.map(function(d, i) { - return values.call(stack, d, i); - }); - var points = series.map(function(d) { - return d.map(function(v, i) { - return [ x.call(stack, v, i), y.call(stack, v, i) ]; - }); - }); - var orders = order.call(stack, points, index); - series = d3.permute(series, orders); - points = d3.permute(points, orders); - var offsets = offset.call(stack, points, index); - var n = series.length, m = series[0].length, i, j, o; - for (j = 0; j < m; ++j) { - out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); - for (i = 1; i < n; ++i) { - out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); - } - } - return data; - } - stack.values = function(x) { - if (!arguments.length) return values; - values = x; - return stack; - }; - stack.order = function(x) { - if (!arguments.length) return order; - order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; - return stack; - }; - stack.offset = function(x) { - if (!arguments.length) return offset; - offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; - return stack; - }; - stack.x = function(z) { - if (!arguments.length) return x; - x = z; - return stack; - }; - stack.y = function(z) { - if (!arguments.length) return y; - y = z; - return stack; - }; - stack.out = function(z) { - if (!arguments.length) return out; - out = z; - return stack; - }; - return stack; - }; - function d3_layout_stackX(d) { - return d.x; - } - function d3_layout_stackY(d) { - return d.y; - } - function d3_layout_stackOut(d, y0, y) { - d.y0 = y0; - d.y = y; - } - var d3_layout_stackOrders = d3.map({ - "inside-out": function(data) { - var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { - return max[a] - max[b]; - }), top = 0, bottom = 0, tops = [], bottoms = []; - for (i = 0; i < n; ++i) { - j = index[i]; - if (top < bottom) { - top += sums[j]; - tops.push(j); - } else { - bottom += sums[j]; - bottoms.push(j); - } - } - return bottoms.reverse().concat(tops); - }, - reverse: function(data) { - return d3.range(data.length).reverse(); - }, - "default": d3_layout_stackOrderDefault - }); - var d3_layout_stackOffsets = d3.map({ - silhouette: function(data) { - var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; - for (j = 0; j < m; ++j) { - for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; - if (o > max) max = o; - sums.push(o); - } - for (j = 0; j < m; ++j) { - y0[j] = (max - sums[j]) / 2; - } - return y0; - }, - wiggle: function(data) { - var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; - y0[0] = o = o0 = 0; - for (j = 1; j < m; ++j) { - for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; - for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { - for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { - s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; - } - s2 += s3 * data[i][j][1]; - } - y0[j] = o -= s1 ? s2 / s1 * dx : 0; - if (o < o0) o0 = o; - } - for (j = 0; j < m; ++j) y0[j] -= o0; - return y0; - }, - expand: function(data) { - var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; - for (j = 0; j < m; ++j) { - for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; - if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; - } - for (j = 0; j < m; ++j) y0[j] = 0; - return y0; - }, - zero: d3_layout_stackOffsetZero - }); - function d3_layout_stackOrderDefault(data) { - return d3.range(data.length); - } - function d3_layout_stackOffsetZero(data) { - var j = -1, m = data[0].length, y0 = []; - while (++j < m) y0[j] = 0; - return y0; - } - function d3_layout_stackMaxIndex(array) { - var i = 1, j = 0, v = array[0][1], k, n = array.length; - for (;i < n; ++i) { - if ((k = array[i][1]) > v) { - j = i; - v = k; - } - } - return j; - } - function d3_layout_stackReduceSum(d) { - return d.reduce(d3_layout_stackSum, 0); - } - function d3_layout_stackSum(p, d) { - return p + d[1]; - } - d3.layout.histogram = function() { - var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; - function histogram(data, i) { - var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; - while (++i < m) { - bin = bins[i] = []; - bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); - bin.y = 0; - } - if (m > 0) { - i = -1; - while (++i < n) { - x = values[i]; - if (x >= range[0] && x <= range[1]) { - bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; - bin.y += k; - bin.push(data[i]); - } - } - } - return bins; - } - histogram.value = function(x) { - if (!arguments.length) return valuer; - valuer = x; - return histogram; - }; - histogram.range = function(x) { - if (!arguments.length) return ranger; - ranger = d3_functor(x); - return histogram; - }; - histogram.bins = function(x) { - if (!arguments.length) return binner; - binner = typeof x === "number" ? function(range) { - return d3_layout_histogramBinFixed(range, x); - } : d3_functor(x); - return histogram; - }; - histogram.frequency = function(x) { - if (!arguments.length) return frequency; - frequency = !!x; - return histogram; - }; - return histogram; - }; - function d3_layout_histogramBinSturges(range, values) { - return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); - } - function d3_layout_histogramBinFixed(range, n) { - var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; - while (++x <= n) f[x] = m * x + b; - return f; - } - function d3_layout_histogramRange(values) { - return [ d3.min(values), d3.max(values) ]; - } - d3.layout.hierarchy = function() { - var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; - function recurse(node, depth, nodes) { - var childs = children.call(hierarchy, node, depth); - node.depth = depth; - nodes.push(node); - if (childs && (n = childs.length)) { - var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d; - while (++i < n) { - d = recurse(childs[i], j, nodes); - d.parent = node; - c.push(d); - v += d.value; - } - if (sort) c.sort(sort); - if (value) node.value = v; - } else if (value) { - node.value = +value.call(hierarchy, node, depth) || 0; - } - return node; - } - function revalue(node, depth) { - var children = node.children, v = 0; - if (children && (n = children.length)) { - var i = -1, n, j = depth + 1; - while (++i < n) v += revalue(children[i], j); - } else if (value) { - v = +value.call(hierarchy, node, depth) || 0; - } - if (value) node.value = v; - return v; - } - function hierarchy(d) { - var nodes = []; - recurse(d, 0, nodes); - return nodes; - } - hierarchy.sort = function(x) { - if (!arguments.length) return sort; - sort = x; - return hierarchy; - }; - hierarchy.children = function(x) { - if (!arguments.length) return children; - children = x; - return hierarchy; - }; - hierarchy.value = function(x) { - if (!arguments.length) return value; - value = x; - return hierarchy; - }; - hierarchy.revalue = function(root) { - revalue(root, 0); - return root; - }; - return hierarchy; - }; - function d3_layout_hierarchyRebind(object, hierarchy) { - d3.rebind(object, hierarchy, "sort", "children", "value"); - object.nodes = object; - object.links = d3_layout_hierarchyLinks; - return object; - } - function d3_layout_hierarchyChildren(d) { - return d.children; - } - function d3_layout_hierarchyValue(d) { - return d.value; - } - function d3_layout_hierarchySort(a, b) { - return b.value - a.value; - } - function d3_layout_hierarchyLinks(nodes) { - return d3.merge(nodes.map(function(parent) { - return (parent.children || []).map(function(child) { - return { - source: parent, - target: child - }; - }); - })); - } - d3.layout.pack = function() { - var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ]; - function pack(d, i) { - var nodes = hierarchy.call(this, d, i), root = nodes[0]; - root.x = 0; - root.y = 0; - d3_layout_treeVisitAfter(root, function(d) { - d.r = Math.sqrt(d.value); - }); - d3_layout_treeVisitAfter(root, d3_layout_packSiblings); - var w = size[0], h = size[1], k = Math.max(2 * root.r / w, 2 * root.r / h); - if (padding > 0) { - var dr = padding * k / 2; - d3_layout_treeVisitAfter(root, function(d) { - d.r += dr; - }); - d3_layout_treeVisitAfter(root, d3_layout_packSiblings); - d3_layout_treeVisitAfter(root, function(d) { - d.r -= dr; - }); - k = Math.max(2 * root.r / w, 2 * root.r / h); - } - d3_layout_packTransform(root, w / 2, h / 2, 1 / k); - return nodes; - } - pack.size = function(x) { - if (!arguments.length) return size; - size = x; - return pack; - }; - pack.padding = function(_) { - if (!arguments.length) return padding; - padding = +_; - return pack; - }; - return d3_layout_hierarchyRebind(pack, hierarchy); - }; - function d3_layout_packSort(a, b) { - return a.value - b.value; - } - function d3_layout_packInsert(a, b) { - var c = a._pack_next; - a._pack_next = b; - b._pack_prev = a; - b._pack_next = c; - c._pack_prev = b; - } - function d3_layout_packSplice(a, b) { - a._pack_next = b; - b._pack_prev = a; - } - function d3_layout_packIntersects(a, b) { - var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; - return dr * dr - dx * dx - dy * dy > .001; - } - function d3_layout_packSiblings(node) { - if (!(nodes = node.children) || !(n = nodes.length)) return; - var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; - function bound(node) { - xMin = Math.min(node.x - node.r, xMin); - xMax = Math.max(node.x + node.r, xMax); - yMin = Math.min(node.y - node.r, yMin); - yMax = Math.max(node.y + node.r, yMax); - } - nodes.forEach(d3_layout_packLink); - a = nodes[0]; - a.x = -a.r; - a.y = 0; - bound(a); - if (n > 1) { - b = nodes[1]; - b.x = b.r; - b.y = 0; - bound(b); - if (n > 2) { - c = nodes[2]; - d3_layout_packPlace(a, b, c); - bound(c); - d3_layout_packInsert(a, c); - a._pack_prev = c; - d3_layout_packInsert(c, b); - b = a._pack_next; - for (i = 3; i < n; i++) { - d3_layout_packPlace(a, b, c = nodes[i]); - var isect = 0, s1 = 1, s2 = 1; - for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { - if (d3_layout_packIntersects(j, c)) { - isect = 1; - break; - } - } - if (isect == 1) { - for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { - if (d3_layout_packIntersects(k, c)) { - break; - } - } - } - if (isect) { - if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); - i--; - } else { - d3_layout_packInsert(a, c); - b = c; - bound(c); - } - } - } - } - var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; - for (i = 0; i < n; i++) { - c = nodes[i]; - c.x -= cx; - c.y -= cy; - cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); - } - node.r = cr; - nodes.forEach(d3_layout_packUnlink); - } - function d3_layout_packLink(node) { - node._pack_next = node._pack_prev = node; - } - function d3_layout_packUnlink(node) { - delete node._pack_next; - delete node._pack_prev; - } - function d3_layout_packTransform(node, x, y, k) { - var children = node.children; - node.x = x += k * node.x; - node.y = y += k * node.y; - node.r *= k; - if (children) { - var i = -1, n = children.length; - while (++i < n) d3_layout_packTransform(children[i], x, y, k); - } - } - function d3_layout_packPlace(a, b, c) { - var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; - if (db && (dx || dy)) { - var da = b.r + c.r, dc = dx * dx + dy * dy; - da *= da; - db *= db; - var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); - c.x = a.x + x * dx + y * dy; - c.y = a.y + x * dy - y * dx; + + d3_timer_flush(); +}; + +// Flush after callbacks to avoid concurrent queue modification. +function d3_timer_flush() { + var t0 = null, + t1 = d3_timer_queue, + then = Infinity; + while (t1) { + if (t1.flush) { + delete d3_timer_byId[t1.callback.id]; + t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next; } else { - c.x = a.x + db; - c.y = a.y; + then = Math.min(then, t1.then + t1.delay); + t1 = (t0 = t1).next; } } - d3.layout.cluster = function() { - var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ]; - function cluster(d, i) { - var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; - d3_layout_treeVisitAfter(root, function(node) { - var children = node.children; - if (children && children.length) { - node.x = d3_layout_clusterX(children); - node.y = d3_layout_clusterY(children); - } else { - node.x = previousNode ? x += separation(node, previousNode) : 0; - node.y = 0; - previousNode = node; - } - }); - var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; - d3_layout_treeVisitAfter(root, function(node) { - node.x = (node.x - x0) / (x1 - x0) * size[0]; - node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; - }); - return nodes; + return then; +} + +var d3_timer_frame = d3_window.requestAnimationFrame + || d3_window.webkitRequestAnimationFrame + || d3_window.mozRequestAnimationFrame + || d3_window.oRequestAnimationFrame + || d3_window.msRequestAnimationFrame + || function(callback) { setTimeout(callback, 17); }; +var π = Math.PI, + ε = 1e-6, + d3_radians = π / 180, + d3_degrees = 180 / π; + +function d3_sgn(x) { + return x > 0 ? 1 : x < 0 ? -1 : 0; +} + +function d3_acos(x) { + return Math.acos(Math.max(-1, Math.min(1, x))); +} + +function d3_asin(x) { + return x > 1 ? π / 2 : x < -1 ? -π / 2 : Math.asin(x); +} + +function d3_sinh(x) { + return (Math.exp(x) - Math.exp(-x)) / 2; +} + +function d3_cosh(x) { + return (Math.exp(x) + Math.exp(-x)) / 2; +} + +function d3_haversin(x) { + return (x = Math.sin(x / 2)) * x; +} +d3.geo = {}; +function d3_identity(d) { + return d; +} +function d3_true() { + return true; +} + +function d3_geo_spherical(cartesian) { + return [ + Math.atan2(cartesian[1], cartesian[0]), + Math.asin(Math.max(-1, Math.min(1, cartesian[2]))) + ]; +} + +function d3_geo_sphericalEqual(a, b) { + return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε; +} + +// General spherical polygon clipping algorithm: takes a polygon, cuts it into +// visible line segments and rejoins the segments by interpolating along the +// clip edge. +function d3_geo_clipPolygon(segments, compare, inside, interpolate, listener) { + var subject = [], + clip = []; + + segments.forEach(function(segment) { + if ((n = segment.length - 1) <= 0) return; + var n, p0 = segment[0], p1 = segment[n]; + + // If the first and last points of a segment are coincident, then treat as + // a closed ring. + // TODO if all rings are closed, then the winding order of the exterior + // ring should be checked. + if (d3_geo_sphericalEqual(p0, p1)) { + listener.lineStart(); + for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); + listener.lineEnd(); + return; } - cluster.separation = function(x) { - if (!arguments.length) return separation; - separation = x; - return cluster; - }; - cluster.size = function(x) { - if (!arguments.length) return size; - size = x; - return cluster; - }; - return d3_layout_hierarchyRebind(cluster, hierarchy); - }; - function d3_layout_clusterY(children) { - return 1 + d3.max(children, function(child) { - return child.y; - }); + + var a = {point: p0, points: segment, other: null, visited: false, entry: true, subject: true}, + b = {point: p0, points: [p0], other: a, visited: false, entry: false, subject: false}; + a.other = b; + subject.push(a); + clip.push(b); + a = {point: p1, points: [p1], other: null, visited: false, entry: false, subject: true}; + b = {point: p1, points: [p1], other: a, visited: false, entry: true, subject: false}; + a.other = b; + subject.push(a); + clip.push(b); + }); + clip.sort(compare); + d3_geo_clipPolygonLinkCircular(subject); + d3_geo_clipPolygonLinkCircular(clip); + if (!subject.length) return; + + if (inside) for (var i = 1, e = !inside(clip[0].point), n = clip.length; i < n; ++i) { + clip[i].entry = (e = !e); } - function d3_layout_clusterX(children) { - return children.reduce(function(x, child) { - return x + child.x; - }, 0) / children.length; - } - function d3_layout_clusterLeft(node) { - var children = node.children; - return children && children.length ? d3_layout_clusterLeft(children[0]) : node; - } - function d3_layout_clusterRight(node) { - var children = node.children, n; - return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; - } - d3.layout.tree = function() { - var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ]; - function tree(d, i) { - var nodes = hierarchy.call(this, d, i), root = nodes[0]; - function firstWalk(node, previousSibling) { - var children = node.children, layout = node._tree; - if (children && (n = children.length)) { - var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1; - while (++i < n) { - child = children[i]; - firstWalk(child, previousChild); - ancestor = apportion(child, previousChild, ancestor); - previousChild = child; - } - d3_layout_treeShift(node); - var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim); - if (previousSibling) { - layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); - layout.mod = layout.prelim - midpoint; - } else { - layout.prelim = midpoint; - } - } else { - if (previousSibling) { - layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); - } - } - } - function secondWalk(node, x) { - node.x = node._tree.prelim + x; - var children = node.children; - if (children && (n = children.length)) { - var i = -1, n; - x += node._tree.mod; - while (++i < n) { - secondWalk(children[i], x); - } - } - } - function apportion(node, previousSibling, ancestor) { - if (previousSibling) { - var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift; - while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { - vom = d3_layout_treeLeft(vom); - vop = d3_layout_treeRight(vop); - vop._tree.ancestor = node; - shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip); - if (shift > 0) { - d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift); - sip += shift; - sop += shift; - } - sim += vim._tree.mod; - sip += vip._tree.mod; - som += vom._tree.mod; - sop += vop._tree.mod; - } - if (vim && !d3_layout_treeRight(vop)) { - vop._tree.thread = vim; - vop._tree.mod += sim - sop; - } - if (vip && !d3_layout_treeLeft(vom)) { - vom._tree.thread = vip; - vom._tree.mod += sip - som; - ancestor = node; - } - } - return ancestor; - } - d3_layout_treeVisitAfter(root, function(node, previousSibling) { - node._tree = { - ancestor: node, - prelim: 0, - mod: 0, - change: 0, - shift: 0, - number: previousSibling ? previousSibling._tree.number + 1 : 0 - }; - }); - firstWalk(root); - secondWalk(root, -root._tree.prelim); - var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1; - d3_layout_treeVisitAfter(root, function(node) { - node.x = (node.x - x0) / (x1 - x0) * size[0]; - node.y = node.depth / y1 * size[1]; - delete node._tree; - }); - return nodes; - } - tree.separation = function(x) { - if (!arguments.length) return separation; - separation = x; - return tree; - }; - tree.size = function(x) { - if (!arguments.length) return size; - size = x; - return tree; - }; - return d3_layout_hierarchyRebind(tree, hierarchy); - }; - function d3_layout_treeSeparation(a, b) { - return a.parent == b.parent ? 1 : 2; - } - function d3_layout_treeLeft(node) { - var children = node.children; - return children && children.length ? children[0] : node._tree.thread; - } - function d3_layout_treeRight(node) { - var children = node.children, n; - return children && (n = children.length) ? children[n - 1] : node._tree.thread; - } - function d3_layout_treeSearch(node, compare) { - var children = node.children; - if (children && (n = children.length)) { - var child, n, i = -1; - while (++i < n) { - if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) { - node = child; - } - } - } - return node; - } - function d3_layout_treeRightmost(a, b) { - return a.x - b.x; - } - function d3_layout_treeLeftmost(a, b) { - return b.x - a.x; - } - function d3_layout_treeDeepest(a, b) { - return a.depth - b.depth; - } - function d3_layout_treeVisitAfter(node, callback) { - function visit(node, previousSibling) { - var children = node.children; - if (children && (n = children.length)) { - var child, previousChild = null, i = -1, n; - while (++i < n) { - child = children[i]; - visit(child, previousChild); - previousChild = child; - } - } - callback(node, previousSibling); - } - visit(node, null); - } - function d3_layout_treeShift(node) { - var shift = 0, change = 0, children = node.children, i = children.length, child; - while (--i >= 0) { - child = children[i]._tree; - child.prelim += shift; - child.mod += shift; - shift += child.shift + (change += child.change); - } - } - function d3_layout_treeMove(ancestor, node, shift) { - ancestor = ancestor._tree; - node = node._tree; - var change = shift / (node.number - ancestor.number); - ancestor.change += change; - node.change -= change; - node.shift += shift; - node.prelim += shift; - node.mod += shift; - } - function d3_layout_treeAncestor(vim, node, ancestor) { - return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor; - } - d3.layout.treemap = function() { - var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5)); - function scale(children, k) { - var i = -1, n = children.length, child, area; - while (++i < n) { - area = (child = children[i]).value * (k < 0 ? 0 : k); - child.area = isNaN(area) || area <= 0 ? 0 : area; - } - } - function squarify(node) { - var children = node.children; - if (children && children.length) { - var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n; - scale(remaining, rect.dx * rect.dy / node.value); - row.area = 0; - while ((n = remaining.length) > 0) { - row.push(child = remaining[n - 1]); - row.area += child.area; - if (mode !== "squarify" || (score = worst(row, u)) <= best) { - remaining.pop(); - best = score; - } else { - row.area -= row.pop().area; - position(row, u, rect, false); - u = Math.min(rect.dx, rect.dy); - row.length = row.area = 0; - best = Infinity; - } - } - if (row.length) { - position(row, u, rect, true); - row.length = row.area = 0; - } - children.forEach(squarify); - } - } - function stickify(node) { - var children = node.children; - if (children && children.length) { - var rect = pad(node), remaining = children.slice(), child, row = []; - scale(remaining, rect.dx * rect.dy / node.value); - row.area = 0; - while (child = remaining.pop()) { - row.push(child); - row.area += child.area; - if (child.z != null) { - position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); - row.length = row.area = 0; - } - } - children.forEach(stickify); - } - } - function worst(row, u) { - var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; - while (++i < n) { - if (!(r = row[i].area)) continue; - if (r < rmin) rmin = r; - if (r > rmax) rmax = r; - } - s *= s; - u *= u; - return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; - } - function position(row, u, rect, flush) { - var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; - if (u == rect.dx) { - if (flush || v > rect.dy) v = rect.dy; - while (++i < n) { - o = row[i]; - o.x = x; - o.y = y; - o.dy = v; - x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); - } - o.z = true; - o.dx += rect.x + rect.dx - x; - rect.y += v; - rect.dy -= v; - } else { - if (flush || v > rect.dx) v = rect.dx; - while (++i < n) { - o = row[i]; - o.x = x; - o.y = y; - o.dx = v; - y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); - } - o.z = false; - o.dy += rect.y + rect.dy - y; - rect.x += v; - rect.dx -= v; - } - } - function treemap(d) { - var nodes = stickies || hierarchy(d), root = nodes[0]; - root.x = 0; - root.y = 0; - root.dx = size[0]; - root.dy = size[1]; - if (stickies) hierarchy.revalue(root); - scale([ root ], root.dx * root.dy / root.value); - (stickies ? stickify : squarify)(root); - if (sticky) stickies = nodes; - return nodes; - } - treemap.size = function(x) { - if (!arguments.length) return size; - size = x; - return treemap; - }; - treemap.padding = function(x) { - if (!arguments.length) return padding; - function padFunction(node) { - var p = x.call(treemap, node, node.depth); - return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); - } - function padConstant(node) { - return d3_layout_treemapPad(node, x); - } - var type; - pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], - padConstant) : padConstant; - return treemap; - }; - treemap.round = function(x) { - if (!arguments.length) return round != Number; - round = x ? Math.round : Number; - return treemap; - }; - treemap.sticky = function(x) { - if (!arguments.length) return sticky; - sticky = x; - stickies = null; - return treemap; - }; - treemap.ratio = function(x) { - if (!arguments.length) return ratio; - ratio = x; - return treemap; - }; - treemap.mode = function(x) { - if (!arguments.length) return mode; - mode = x + ""; - return treemap; - }; - return d3_layout_hierarchyRebind(treemap, hierarchy); - }; - function d3_layout_treemapPadNull(node) { - return { - x: node.x, - y: node.y, - dx: node.dx, - dy: node.dy - }; - } - function d3_layout_treemapPad(node, padding) { - var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; - if (dx < 0) { - x += dx / 2; - dx = 0; - } - if (dy < 0) { - y += dy / 2; - dy = 0; - } - return { - x: x, - y: y, - dx: dx, - dy: dy - }; - } - d3.layout.voronoi = function() { - var size = null, x = d3_svg_lineX, y = d3_svg_lineY, clip; - function voronoi(data) { - var points = [], cells, fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length; - for (i = 0; i < n; ++i) points.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]); - cells = d3.geom.voronoi(points); - for (i = 0; i < n; ++i) cells[i].data = data[i]; - if (clip) for (i = 0; i < n; ++i) clip(cells[i]); - return cells; - } - voronoi.x = function(_) { - return arguments.length ? (x = _, voronoi) : x; - }; - voronoi.y = function(_) { - return arguments.length ? (y = _, voronoi) : y; - }; - voronoi.size = function(_) { - if (!arguments.length) return size; - if (_ == null) { - clip = null; - } else { - var w = +_[0], h = +_[1]; - clip = d3.geom.polygon([ [ 0, 0 ], [ 0, h ], [ w, h ], [ w, 0 ] ]).clip; - } - return voronoi; - }; - return voronoi; - }; - function d3_dsv(delimiter, mimeType) { - var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); - function dsv(url, row, callback) { - if (arguments.length < 3) callback = row, row = null; - var xhr = d3.xhr(url, mimeType, callback); - xhr.row = function(_) { - return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; - }; - return xhr.row(row); - } - function response(request) { - return dsv.parse(request.responseText); - } - function typedResponse(f) { - return function(request) { - return dsv.parse(request.responseText, f); - }; - } - dsv.parse = function(text, f) { - var o; - return dsv.parseRows(text, function(row, i) { - if (o) return o(row, i - 1); - var a = new Function("d", "return {" + row.map(function(name, i) { - return JSON.stringify(name) + ": d[" + i + "]"; - }).join(",") + "}"); - o = f ? function(row, i) { - return f(a(row), i); - } : a; - }); - }; - dsv.parseRows = function(text, f) { - var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; - function token() { - if (I >= N) return EOF; - if (eol) return eol = false, EOL; - var j = I; - if (text.charCodeAt(j) === 34) { - var i = j; - while (i++ < N) { - if (text.charCodeAt(i) === 34) { - if (text.charCodeAt(i + 1) !== 34) break; - ++i; - } - } - I = i + 2; - var c = text.charCodeAt(i + 1); - if (c === 13) { - eol = true; - if (text.charCodeAt(i + 2) === 10) ++I; - } else if (c === 10) { - eol = true; - } - return text.substring(j + 1, i).replace(/""/g, '"'); - } - while (I < N) { - var c = text.charCodeAt(I++), k = 1; - if (c === 10) eol = true; else if (c === 13) { - eol = true; - if (text.charCodeAt(I) === 10) ++I, ++k; - } else if (c !== delimiterCode) continue; - return text.substring(j, I - k); - } - return text.substring(j); - } - while ((t = token()) !== EOF) { - var a = []; - while (t !== EOL && t !== EOF) { - a.push(t); - t = token(); - } - if (f && !(a = f(a, n++))) continue; - rows.push(a); - } - return rows; - }; - dsv.format = function(rows) { - if (Array.isArray(rows[0])) return dsv.formatRows(rows); - var fieldSet = new d3_Set(), fields = []; - rows.forEach(function(row) { - for (var field in row) { - if (!fieldSet.has(field)) { - fields.push(fieldSet.add(field)); - } - } - }); - return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { - return fields.map(function(field) { - return formatValue(row[field]); - }).join(delimiter); - })).join("\n"); - }; - dsv.formatRows = function(rows) { - return rows.map(formatRow).join("\n"); - }; - function formatRow(row) { - return row.map(formatValue).join(delimiter); - } - function formatValue(text) { - return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; - } - return dsv; - } - d3.csv = d3_dsv(",", "text/csv"); - d3.tsv = d3_dsv(" ", "text/tab-separated-values"); - d3.geo = {}; - d3.geo.stream = function(object, listener) { - if (d3_geo_streamObjectType.hasOwnProperty(object.type)) { - d3_geo_streamObjectType[object.type](object, listener); - } else { - d3_geo_streamGeometry(object, listener); - } - }; - function d3_geo_streamGeometry(geometry, listener) { - if (d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { - d3_geo_streamGeometryType[geometry.type](geometry, listener); - } - } - var d3_geo_streamObjectType = { - Feature: function(feature, listener) { - d3_geo_streamGeometry(feature.geometry, listener); - }, - FeatureCollection: function(object, listener) { - var features = object.features, i = -1, n = features.length; - while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); - } - }; - var d3_geo_streamGeometryType = { - Sphere: function(object, listener) { - listener.sphere(); - }, - Point: function(object, listener) { - var coordinate = object.coordinates; - listener.point(coordinate[0], coordinate[1]); - }, - MultiPoint: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate; - while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); - }, - LineString: function(object, listener) { - d3_geo_streamLine(object.coordinates, listener, 0); - }, - MultiLineString: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length; - while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); - }, - Polygon: function(object, listener) { - d3_geo_streamPolygon(object.coordinates, listener); - }, - MultiPolygon: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length; - while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); - }, - GeometryCollection: function(object, listener) { - var geometries = object.geometries, i = -1, n = geometries.length; - while (++i < n) d3_geo_streamGeometry(geometries[i], listener); - } - }; - function d3_geo_streamLine(coordinates, listener, closed) { - var i = -1, n = coordinates.length - closed, coordinate; + + var start = subject[0], + current, + points, + point; + while (1) { + // Find first unvisited intersection. + current = start; + while (current.visited) if ((current = current.next) === start) return; + points = current.points; listener.lineStart(); - while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); + do { + current.visited = current.other.visited = true; + if (current.entry) { + if (current.subject) { + for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.point, current.next.point, 1, listener); + } + current = current.next; + } else { + if (current.subject) { + points = current.prev.points; + for (var i = points.length; --i >= 0;) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.point, current.prev.point, -1, listener); + } + current = current.prev; + } + current = current.other; + points = current.points; + } while (!current.visited); listener.lineEnd(); } - function d3_geo_streamPolygon(coordinates, listener) { - var i = -1, n = coordinates.length; - listener.polygonStart(); - while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); - listener.polygonEnd(); +} + +function d3_geo_clipPolygonLinkCircular(array) { + if (!(n = array.length)) return; + var n, + i = 0, + a = array[0], + b; + while (++i < n) { + a.next = b = array[i]; + b.prev = a; + a = b; } - function d3_geo_spherical(cartesian) { - return [ Math.atan2(cartesian[1], cartesian[0]), Math.asin(Math.max(-1, Math.min(1, cartesian[2]))) ]; - } - function d3_geo_sphericalEqual(a, b) { - return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε; - } - function d3_geo_cartesian(spherical) { - var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); - return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; - } - function d3_geo_cartesianDot(a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; - } - function d3_geo_cartesianCross(a, b) { - return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ]; - } - function d3_geo_cartesianAdd(a, b) { - a[0] += b[0]; - a[1] += b[1]; - a[2] += b[2]; - } - function d3_geo_cartesianScale(vector, k) { - return [ vector[0] * k, vector[1] * k, vector[2] * k ]; - } - function d3_geo_cartesianNormalize(d) { - var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); - d[0] /= l; - d[1] /= l; - d[2] /= l; - } - d3.geo.distance = function(a, b) { - var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t; - return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ); - }; - function d3_geo_resample(project) { - var δ2 = .5, maxDepth = 16; - function resample(stream) { - var λ0, x0, y0, a0, b0, c0; - var resample = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - stream.polygonStart(); - resample.lineStart = polygonLineStart; - }, - polygonEnd: function() { - stream.polygonEnd(); - resample.lineStart = lineStart; - } - }; - function point(x, y) { - x = project(x, y); - stream.point(x[0], x[1]); - } - function lineStart() { - x0 = NaN; - resample.point = linePoint; - stream.lineStart(); - } - function linePoint(λ, φ) { - var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); - 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); - stream.point(x0, y0); - } - function lineEnd() { - resample.point = point; - stream.lineEnd(); - } - function polygonLineStart() { - var λ00, φ00, x00, y00, a00, b00, c00; - lineStart(); - resample.point = function(λ, φ) { - linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; - resample.point = linePoint; - }; - resample.lineEnd = function() { - resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); - resample.lineEnd = lineEnd; - lineEnd(); - }; - } - return resample; - } - function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { - var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; - if (d2 > 4 * δ2 && depth--) { - var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2; - if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3) { - resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); - stream.point(x2, y2); - resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); - } - } - } - resample.precision = function(_) { - if (!arguments.length) return Math.sqrt(δ2); - maxDepth = (δ2 = _ * _) > 0 && 16; - return resample; - }; - return resample; - } - d3.geo.albersUsa = function() { - var lower48 = d3.geo.albers(); - var alaska = d3.geo.albers().rotate([ 160, 0 ]).center([ 0, 60 ]).parallels([ 55, 65 ]); - var hawaii = d3.geo.albers().rotate([ 160, 0 ]).center([ 0, 20 ]).parallels([ 8, 18 ]); - var puertoRico = d3.geo.albers().rotate([ 60, 0 ]).center([ 0, 10 ]).parallels([ 8, 18 ]); - var alaskaInvert, hawaiiInvert, puertoRicoInvert; - function albersUsa(coordinates) { - return projection(coordinates)(coordinates); - } - function projection(point) { - var lon = point[0], lat = point[1]; - return lat > 50 ? alaska : lon < -140 ? hawaii : lat < 21 ? puertoRico : lower48; - } - albersUsa.invert = function(coordinates) { - return alaskaInvert(coordinates) || hawaiiInvert(coordinates) || puertoRicoInvert(coordinates) || lower48.invert(coordinates); - }; - albersUsa.scale = function(x) { - if (!arguments.length) return lower48.scale(); - lower48.scale(x); - alaska.scale(x * .6); - hawaii.scale(x); - puertoRico.scale(x * 1.5); - return albersUsa.translate(lower48.translate()); - }; - albersUsa.translate = function(x) { - if (!arguments.length) return lower48.translate(); - var dz = lower48.scale(), dx = x[0], dy = x[1]; - lower48.translate(x); - alaska.translate([ dx - .4 * dz, dy + .17 * dz ]); - hawaii.translate([ dx - .19 * dz, dy + .2 * dz ]); - puertoRico.translate([ dx + .58 * dz, dy + .43 * dz ]); - alaskaInvert = d3_geo_albersUsaInvert(alaska, [ [ -180, 50 ], [ -130, 72 ] ]); - hawaiiInvert = d3_geo_albersUsaInvert(hawaii, [ [ -164, 18 ], [ -154, 24 ] ]); - puertoRicoInvert = d3_geo_albersUsaInvert(puertoRico, [ [ -67.5, 17.5 ], [ -65, 19 ] ]); - return albersUsa; - }; - return albersUsa.scale(lower48.scale()); - }; - function d3_geo_albersUsaInvert(projection, extent) { - var a = projection(extent[0]), b = projection([ .5 * (extent[0][0] + extent[1][0]), extent[0][1] ]), c = projection([ extent[1][0], extent[0][1] ]), d = projection(extent[1]); - var dya = b[1] - a[1], dxa = b[0] - a[0], dyb = c[1] - b[1], dxb = c[0] - b[0]; - var ma = dya / dxa, mb = dyb / dxb; - var cx = .5 * (ma * mb * (a[1] - c[1]) + mb * (a[0] + b[0]) - ma * (b[0] + c[0])) / (mb - ma), cy = (.5 * (a[0] + b[0]) - cx) / ma + .5 * (a[1] + b[1]); - var dx0 = d[0] - cx, dy0 = d[1] - cy, dx1 = a[0] - cx, dy1 = a[1] - cy, r0 = dx0 * dx0 + dy0 * dy0, r1 = dx1 * dx1 + dy1 * dy1; - var a0 = Math.atan2(dy0, dx0), a1 = Math.atan2(dy1, dx1); - return function(coordinates) { - var dx = coordinates[0] - cx, dy = coordinates[1] - cy, r = dx * dx + dy * dy, a = Math.atan2(dy, dx); - if (r0 < r && r < r1 && a0 < a && a < a1) return projection.invert(coordinates); - }; - } - function d3_geo_albers(φ0, φ1) { - var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n; - function albers(λ, φ) { - var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; - return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; - } - albers.invert = function(x, y) { - var ρ0_y = ρ0 - y; - return [ Math.atan2(x, ρ0_y) / n, Math.asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; - }; - return albers; - } - (d3.geo.albers = function() { - var φ0 = 29.5 * d3_radians, φ1 = 45.5 * d3_radians, m = d3_geo_projectionMutator(d3_geo_albers), p = m(φ0, φ1); - p.parallels = function(_) { - if (!arguments.length) return [ φ0 * d3_degrees, φ1 * d3_degrees ]; - return m(φ0 = _[0] * d3_radians, φ1 = _[1] * d3_radians); - }; - return p.rotate([ 98, 0 ]).center([ 0, 38 ]).scale(1e3); - }).raw = d3_geo_albers; - var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { - return Math.sqrt(2 / (1 + cosλcosφ)); - }, function(ρ) { - return 2 * Math.asin(ρ / 2); - }); - (d3.geo.azimuthalEqualArea = function() { - return d3_geo_projection(d3_geo_azimuthalEqualArea); - }).raw = d3_geo_azimuthalEqualArea; - var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { - var c = Math.acos(cosλcosφ); - return c && c / Math.sin(c); - }, d3_identity); - (d3.geo.azimuthalEquidistant = function() { - return d3_geo_projection(d3_geo_azimuthalEquidistant); - }).raw = d3_geo_azimuthalEquidistant; - d3.geo.bounds = d3_geo_bounds(d3_identity); - function d3_geo_bounds(projectStream) { - var x0, y0, x1, y1; - var bound = { - point: boundPoint, - lineStart: d3_noop, - lineEnd: d3_noop, + a.next = b = array[0]; + b.prev = a; +} + +function d3_geo_clip(pointVisible, clipLine, interpolate) { + return function(listener) { + var line = clipLine(listener); + + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, polygonStart: function() { - bound.lineEnd = boundPolygonLineEnd; + clip.point = pointRing; + clip.lineStart = ringStart; + clip.lineEnd = ringEnd; + invisible = false; + invisibleArea = visibleArea = 0; + segments = []; + listener.polygonStart(); }, polygonEnd: function() { - bound.point = boundPoint; - } - }; - function boundPoint(x, y) { - if (x < x0) x0 = x; - if (x > x1) x1 = x; - if (y < y0) y0 = y; - if (y > y1) y1 = y; - } - function boundPolygonLineEnd() { - bound.point = bound.lineEnd = d3_noop; - } - return function(feature) { - y1 = x1 = -(x0 = y0 = Infinity); - d3.geo.stream(feature, projectStream(bound)); - return [ [ x0, y0 ], [ x1, y1 ] ]; - }; - } - d3.geo.centroid = function(object) { - d3_geo_centroidDimension = d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; - d3.geo.stream(object, d3_geo_centroid); - var m; - if (d3_geo_centroidW && Math.abs(m = Math.sqrt(d3_geo_centroidX * d3_geo_centroidX + d3_geo_centroidY * d3_geo_centroidY + d3_geo_centroidZ * d3_geo_centroidZ)) > ε) { - return [ Math.atan2(d3_geo_centroidY, d3_geo_centroidX) * d3_degrees, Math.asin(Math.max(-1, Math.min(1, d3_geo_centroidZ / m))) * d3_degrees ]; - } - }; - var d3_geo_centroidDimension, d3_geo_centroidW, d3_geo_centroidX, d3_geo_centroidY, d3_geo_centroidZ; - var d3_geo_centroid = { - sphere: function() { - if (d3_geo_centroidDimension < 2) { - d3_geo_centroidDimension = 2; - d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; - } - }, - point: d3_geo_centroidPoint, - lineStart: d3_geo_centroidLineStart, - lineEnd: d3_geo_centroidLineEnd, - polygonStart: function() { - if (d3_geo_centroidDimension < 2) { - d3_geo_centroidDimension = 2; - d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; - } - d3_geo_centroid.lineStart = d3_geo_centroidRingStart; - }, - polygonEnd: function() { - d3_geo_centroid.lineStart = d3_geo_centroidLineStart; - } - }; - function d3_geo_centroidPoint(λ, φ) { - if (d3_geo_centroidDimension) return; - ++d3_geo_centroidW; - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - d3_geo_centroidX += (cosφ * Math.cos(λ) - d3_geo_centroidX) / d3_geo_centroidW; - d3_geo_centroidY += (cosφ * Math.sin(λ) - d3_geo_centroidY) / d3_geo_centroidW; - d3_geo_centroidZ += (Math.sin(φ) - d3_geo_centroidZ) / d3_geo_centroidW; - } - function d3_geo_centroidRingStart() { - var λ00, φ00; - d3_geo_centroidDimension = 1; - d3_geo_centroidLineStart(); - d3_geo_centroidDimension = 2; - var linePoint = d3_geo_centroid.point; - d3_geo_centroid.point = function(λ, φ) { - linePoint(λ00 = λ, φ00 = φ); - }; - d3_geo_centroid.lineEnd = function() { - d3_geo_centroid.point(λ00, φ00); - d3_geo_centroidLineEnd(); - d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; - }; - } - function d3_geo_centroidLineStart() { - var x0, y0, z0; - if (d3_geo_centroidDimension > 1) return; - if (d3_geo_centroidDimension < 1) { - d3_geo_centroidDimension = 1; - d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; - } - d3_geo_centroid.point = function(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - x0 = cosφ * Math.cos(λ); - y0 = cosφ * Math.sin(λ); - z0 = Math.sin(φ); - d3_geo_centroid.point = nextPoint; - }; - function nextPoint(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z); - d3_geo_centroidW += w; - d3_geo_centroidX += w * (x0 + (x0 = x)); - d3_geo_centroidY += w * (y0 + (y0 = y)); - d3_geo_centroidZ += w * (z0 + (z0 = z)); - } - } - function d3_geo_centroidLineEnd() { - d3_geo_centroid.point = d3_geo_centroidPoint; - } - d3.geo.circle = function() { - var origin = [ 0, 0 ], angle, precision = 6, interpolate; - function circle() { - var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = []; - interpolate(null, null, 1, { - point: function(x, y) { - ring.push(x = rotate(x, y)); - x[0] *= d3_degrees, x[1] *= d3_degrees; - } - }); - return { - type: "Polygon", - coordinates: [ ring ] - }; - } - circle.origin = function(x) { - if (!arguments.length) return origin; - origin = x; - return circle; - }; - circle.angle = function(x) { - if (!arguments.length) return angle; - interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); - return circle; - }; - circle.precision = function(_) { - if (!arguments.length) return precision; - interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); - return circle; - }; - return circle.angle(90); - }; - function d3_geo_circleInterpolate(radians, precision) { - var cr = Math.cos(radians), sr = Math.sin(radians); - return function(from, to, direction, listener) { - if (from != null) { - from = d3_geo_circleAngle(cr, from); - to = d3_geo_circleAngle(cr, to); - if (direction > 0 ? from < to : from > to) from += direction * 2 * π; - } else { - from = radians + direction * 2 * π; - to = radians; - } - var point; - for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) { - listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); - } - }; - } - function d3_geo_circleAngle(cr, point) { - var a = d3_geo_cartesian(point); - a[0] -= cr; - d3_geo_cartesianNormalize(a); - var angle = d3_acos(-a[1]); - return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); - } - function d3_geo_clip(pointVisible, clipLine, interpolate) { - return function(listener) { - var line = clipLine(listener); - var clip = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - clip.point = pointRing; - clip.lineStart = ringStart; - clip.lineEnd = ringEnd; - invisible = false; - invisibleArea = visibleArea = 0; - segments = []; - listener.polygonStart(); - }, - polygonEnd: function() { - clip.point = point; - clip.lineStart = lineStart; - clip.lineEnd = lineEnd; - segments = d3.merge(segments); - if (segments.length) { - d3_geo_clipPolygon(segments, d3_geo_clipSort, null, interpolate, listener); - } else if (visibleArea < -ε || invisible && invisibleArea < -ε) { - listener.lineStart(); - interpolate(null, null, 1, listener); - listener.lineEnd(); - } - listener.polygonEnd(); - segments = null; - }, - sphere: function() { - listener.polygonStart(); + clip.point = point; + clip.lineStart = lineStart; + clip.lineEnd = lineEnd; + + segments = d3.merge(segments); + if (segments.length) { + d3_geo_clipPolygon(segments, d3_geo_clipSort, null, interpolate, listener); + } else if (visibleArea < -ε || invisible && invisibleArea < -ε) { listener.lineStart(); interpolate(null, null, 1, listener); listener.lineEnd(); - listener.polygonEnd(); } - }; - function point(λ, φ) { - if (pointVisible(λ, φ)) listener.point(λ, φ); - } - function pointLine(λ, φ) { - line.point(λ, φ); - } - function lineStart() { - clip.point = pointLine; - line.lineStart(); - } - function lineEnd() { - clip.point = point; - line.lineEnd(); - } - var segments, visibleArea, invisibleArea, invisible; - var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), ring; - function pointRing(λ, φ) { - ringListener.point(λ, φ); - ring.push([ λ, φ ]); - } - function ringStart() { - ringListener.lineStart(); - ring = []; - } - function ringEnd() { - pointRing(ring[0][0], ring[0][1]); - ringListener.lineEnd(); - var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; - if (!n) { - invisible = true; - invisibleArea += d3_geo_clipAreaRing(ring, -1); - ring = null; - return; - } - ring = null; - if (clean & 1) { - segment = ringSegments[0]; - visibleArea += d3_geo_clipAreaRing(segment, 1); - var n = segment.length - 1, i = -1, point; - listener.lineStart(); - while (++i < n) listener.point((point = segment[i])[0], point[1]); - listener.lineEnd(); - return; - } - if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); - segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); - } - return clip; - }; - } - function d3_geo_clipSegmentLength1(segment) { - return segment.length > 1; - } - function d3_geo_clipBufferListener() { - var lines = [], line; - return { - lineStart: function() { - lines.push(line = []); + listener.polygonEnd(); + segments = null; }, - point: function(λ, φ) { - line.push([ λ, φ ]); - }, - lineEnd: d3_noop, - buffer: function() { - var buffer = lines; - lines = []; - line = null; - return buffer; - }, - rejoin: function() { - if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); - } - }; - } - function d3_geo_clipAreaRing(ring, invisible) { - if (!(n = ring.length)) return 0; - var n, i = 0, area = 0, p = ring[0], λ = p[0], φ = p[1], cosφ = Math.cos(φ), x0 = Math.atan2(invisible * Math.sin(λ) * cosφ, Math.sin(φ)), y0 = 1 - invisible * Math.cos(λ) * cosφ, x1 = x0, x, y; - while (++i < n) { - p = ring[i]; - cosφ = Math.cos(φ = p[1]); - x = Math.atan2(invisible * Math.sin(λ = p[0]) * cosφ, Math.sin(φ)); - y = 1 - invisible * Math.cos(λ) * cosφ; - if (Math.abs(y0 - 2) < ε && Math.abs(y - 2) < ε) continue; - if (Math.abs(y) < ε || Math.abs(y0) < ε) {} else if (Math.abs(Math.abs(x - x0) - π) < ε) { - if (y + y0 > 2) area += 4 * (x - x0); - } else if (Math.abs(y0 - 2) < ε) area += 4 * (x - x1); else area += ((3 * π + x - x0) % (2 * π) - π) * (y0 + y); - x1 = x0, x0 = x, y0 = y; - } - return area; - } - function d3_geo_clipSort(a, b) { - return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]); - } - var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate); - function d3_geo_clipAntimeridianLine(listener) { - var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; - return { - lineStart: function() { + sphere: function() { + listener.polygonStart(); listener.lineStart(); - clean = 1; - }, - point: function(λ1, φ1) { - var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0); - if (Math.abs(dλ - π) < ε) { - listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2); - listener.point(sλ0, φ0); - listener.lineEnd(); - listener.lineStart(); - listener.point(sλ1, φ0); - listener.point(λ1, φ0); - clean = 0; - } else if (sλ0 !== sλ1 && dλ >= π) { - if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; - if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; - φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); - listener.point(sλ0, φ0); - listener.lineEnd(); - listener.lineStart(); - listener.point(sλ1, φ0); - clean = 0; - } - listener.point(λ0 = λ1, φ0 = φ1); - sλ0 = sλ1; - }, - lineEnd: function() { + interpolate(null, null, 1, listener); listener.lineEnd(); - λ0 = φ0 = NaN; - }, - clean: function() { - return 2 - clean; + listener.polygonEnd(); } }; - } - function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { - var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); - return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2; - } - function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { - var φ; - if (from == null) { - φ = direction * π / 2; - listener.point(-π, φ); - listener.point(0, φ); - listener.point(π, φ); - listener.point(π, 0); - listener.point(π, -φ); - listener.point(0, -φ); - listener.point(-π, -φ); - listener.point(-π, 0); - listener.point(-π, φ); - } else if (Math.abs(from[0] - to[0]) > ε) { - var s = (from[0] < to[0] ? 1 : -1) * π; - φ = direction * s / 2; - listener.point(-s, φ); - listener.point(0, φ); - listener.point(s, φ); - } else { - listener.point(to[0], to[1]); + + function point(λ, φ) { if (pointVisible(λ, φ)) listener.point(λ, φ); } + function pointLine(λ, φ) { line.point(λ, φ); } + function lineStart() { clip.point = pointLine; line.lineStart(); } + function lineEnd() { clip.point = point; line.lineEnd(); } + + var segments, + visibleArea, + invisibleArea, + invisible; + + var buffer = d3_geo_clipBufferListener(), + ringListener = clipLine(buffer), + ring; + + function pointRing(λ, φ) { + ringListener.point(λ, φ); + ring.push([λ, φ]); } - } - function d3_geo_clipCircle(degrees) { - var radians = degrees * d3_radians, cr = Math.cos(radians), interpolate = d3_geo_circleInterpolate(radians, 6 * d3_radians); - return d3_geo_clip(visible, clipLine, interpolate); - function visible(λ, φ) { - return Math.cos(λ) * Math.cos(φ) > cr; + + function ringStart() { + ringListener.lineStart(); + ring = []; } - function clipLine(listener) { - var point0, v0, v00, clean; - return { - lineStart: function() { - v00 = v0 = false; - clean = 1; - }, - point: function(λ, φ) { - var point1 = [ λ, φ ], point2, v = visible(λ, φ); - if (!point0 && (v00 = v0 = v)) listener.lineStart(); - if (v !== v0) { - point2 = intersect(point0, point1); - if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { - point1[0] += ε; - point1[1] += ε; - v = visible(point1[0], point1[1]); - } - } - if (v !== v0) { - clean = 0; - if (v0 = v) { - listener.lineStart(); - point2 = intersect(point1, point0); - listener.point(point2[0], point2[1]); - } else { - point2 = intersect(point0, point1); - listener.point(point2[0], point2[1]); - listener.lineEnd(); - } - point0 = point2; - } - if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) listener.point(point1[0], point1[1]); - point0 = point1; - }, - lineEnd: function() { - if (v0) listener.lineEnd(); - point0 = null; - }, - clean: function() { - return clean | (v00 && v0) << 1; - } - }; - } - function intersect(a, b) { - var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); - var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; - if (!determinant) return a; - var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2); - d3_geo_cartesianAdd(A, B); - var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t = Math.sqrt(w * w - uu * (d3_geo_cartesianDot(A, A) - 1)), q = d3_geo_cartesianScale(u, (-w - t) / uu); - d3_geo_cartesianAdd(q, A); - return d3_geo_spherical(q); - } - } - function d3_geo_clipPolygon(segments, compare, inside, interpolate, listener) { - var subject = [], clip = []; - segments.forEach(function(segment) { - if ((n = segment.length) <= 1) return; - var n, p0 = segment[0], p1 = segment[n - 1]; - if (d3_geo_sphericalEqual(p0, p1)) { + + function ringEnd() { + pointRing(ring[0][0], ring[0][1]); + ringListener.lineEnd(); + + var clean = ringListener.clean(), + ringSegments = buffer.buffer(), + segment, + n = ringSegments.length; + + // TODO compute on-the-fly? + if (!n) { + invisible = true; + invisibleArea += d3_geo_clipAreaRing(ring, -1); + ring = null; + return; + } + ring = null; + + // No intersections. + // TODO compute on-the-fly? + if (clean & 1) { + segment = ringSegments[0]; + visibleArea += d3_geo_clipAreaRing(segment, 1); + var n = segment.length - 1, + i = -1, + point; listener.lineStart(); - for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); + while (++i < n) listener.point((point = segment[i])[0], point[1]); listener.lineEnd(); return; } - var a = { - point: p0, - points: segment, - other: null, - visited: false, - entry: true, - subject: true - }, b = { - point: p0, - points: [ p0 ], - other: a, - visited: false, - entry: false, - subject: false - }; - a.other = b; - subject.push(a); - clip.push(b); - a = { - point: p1, - points: [ p1 ], - other: null, - visited: false, - entry: false, - subject: true - }; - b = { - point: p1, - points: [ p1 ], - other: a, - visited: false, - entry: true, - subject: false - }; - a.other = b; - subject.push(a); - clip.push(b); - }); - clip.sort(compare); - d3_geo_clipPolygonLinkCircular(subject); - d3_geo_clipPolygonLinkCircular(clip); - if (!subject.length) return; - if (inside) for (var i = 1, e = inside(clip[0].point), n = clip.length; i < n; ++i) { - clip[i].entry = e = !e; + + // Rejoin connected segments. + // TODO reuse bufferListener.rejoin()? + if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); + + segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); } - var start = subject[0], current, points, point; - while (1) { - current = start; - while (current.visited) if ((current = current.next) === start) return; - points = current.points; + + return clip; + }; +} + +function d3_geo_clipSegmentLength1(segment) { + return segment.length > 1; +} + +function d3_geo_clipBufferListener() { + var lines = [], + line; + return { + lineStart: function() { lines.push(line = []); }, + point: function(λ, φ) { line.push([λ, φ]); }, + lineEnd: d3_noop, + buffer: function() { + var buffer = lines; + lines = []; + line = null; + return buffer; + }, + rejoin: function() { + if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); + } + }; +} + +// Approximate polygon ring area (×2, since we only need the sign). +// For an invisible polygon ring, we rotate longitudinally by 180°. +// The invisible parameter should be 1, or -1 to rotate longitudinally. +// Based on Robert. G. Chamberlain and William H. Duquette, +// “Some Algorithms for Polygons on a Sphere”, +// http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 +function d3_geo_clipAreaRing(ring, invisible) { + if (!(n = ring.length)) return 0; + var n, + i = 0, + area = 0, + p = ring[0], + λ = p[0], + φ = p[1], + cosφ = Math.cos(φ), + x0 = Math.atan2(invisible * Math.sin(λ) * cosφ, Math.sin(φ)), + y0 = 1 - invisible * Math.cos(λ) * cosφ, + x1 = x0, + x, // λ'; λ rotated to south pole. + y; // φ' = 1 + sin(φ); φ rotated to south pole. + while (++i < n) { + p = ring[i]; + cosφ = Math.cos(φ = p[1]); + x = Math.atan2(invisible * Math.sin(λ = p[0]) * cosφ, Math.sin(φ)); + y = 1 - invisible * Math.cos(λ) * cosφ; + + // If both the current point and the previous point are at the north pole, + // skip this point. + if (Math.abs(y0 - 2) < ε && Math.abs(y - 2) < ε) continue; + + // If this or the previous point is at the south pole, or if this segment + // goes through the south pole, the area is 0. + if (Math.abs(y) < ε || Math.abs(y0) < ε) {} + + // If this segment goes through either pole… + else if (Math.abs(Math.abs(x - x0) - π) < ε) { + // For the north pole, compute lune area. + if (y + y0 > 2) area += 4 * (x - x0); + // For the south pole, the area is zero. + } + + // If the previous point is at the north pole, then compute lune area. + else if (Math.abs(y0 - 2) < ε) area += 4 * (x - x1); + + // Otherwise, the spherical triangle area is approximately + // δλ * (1 + sinφ0 + 1 + sinφ) / 2. + else area += ((3 * π + x - x0) % (2 * π) - π) * (y0 + y); + + x1 = x0, x0 = x, y0 = y; + } + return area; +} + +// Intersection points are sorted along the clip edge. For both antimeridian +// cutting and circle clipping, the same comparison is used. +function d3_geo_clipSort(a, b) { + return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) + - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]); +} + +var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate); + +// Takes a line and cuts into visible segments. Return values: +// 0: there were intersections or the line was empty. +// 1: no intersections. +// 2: there were intersections, and the first and last segments should be +// rejoined. +function d3_geo_clipAntimeridianLine(listener) { + var λ0 = NaN, + φ0 = NaN, + sλ0 = NaN, + clean; // no intersections + + return { + lineStart: function() { listener.lineStart(); - do { - current.visited = current.other.visited = true; - if (current.entry) { - if (current.subject) { - for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]); - } else { - interpolate(current.point, current.next.point, 1, listener); - } - current = current.next; - } else { - if (current.subject) { - points = current.prev.points; - for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]); - } else { - interpolate(current.point, current.prev.point, -1, listener); - } - current = current.prev; - } - current = current.other; - points = current.points; - } while (!current.visited); + clean = 1; + }, + point: function(λ1, φ1) { + var sλ1 = λ1 > 0 ? π : -π, + dλ = Math.abs(λ1 - λ0); + if (Math.abs(dλ - π) < ε) { // line crosses a pole + listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + listener.point( λ1, φ0); + clean = 0; + } else if (sλ0 !== sλ1 && dλ >= π) { // line crosses antimeridian + // handle degeneracies + if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; + if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; + φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + clean = 0; + } + listener.point(λ0 = λ1, φ0 = φ1); + sλ0 = sλ1; + }, + lineEnd: function() { listener.lineEnd(); - } + λ0 = φ0 = NaN; + }, + // if there are intersections, we always rejoin the first and last segments. + clean: function() { return 2 - clean; } + }; +} + +function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { + var cosφ0, + cosφ1, + sinλ0_λ1 = Math.sin(λ0 - λ1); + return Math.abs(sinλ0_λ1) > ε + ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) + - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) + / (cosφ0 * cosφ1 * sinλ0_λ1)) + : (φ0 + φ1) / 2; +} + +function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { + var φ; + if (from == null) { + φ = direction * π / 2; + listener.point(-π, φ); + listener.point( 0, φ); + listener.point( π, φ); + listener.point( π, 0); + listener.point( π, -φ); + listener.point( 0, -φ); + listener.point(-π, -φ); + listener.point(-π, 0); + listener.point(-π, φ); + } else if (Math.abs(from[0] - to[0]) > ε) { + var s = (from[0] < to[0] ? 1 : -1) * π; + φ = direction * s / 2; + listener.point(-s, φ); + listener.point( 0, φ); + listener.point( s, φ); + } else { + listener.point(to[0], to[1]); } - function d3_geo_clipPolygonLinkCircular(array) { - if (!(n = array.length)) return; - var n, i = 0, a = array[0], b; - while (++i < n) { - a.next = b = array[i]; - b.prev = a; - a = b; - } - a.next = b = array[0]; - b.prev = a; +} +// TODO +// cross and scale return new vectors, +// whereas add and normalize operate in-place + +function d3_geo_cartesian(spherical) { + var λ = spherical[0], + φ = spherical[1], + cosφ = Math.cos(φ); + return [ + cosφ * Math.cos(λ), + cosφ * Math.sin(λ), + Math.sin(φ) + ]; +} + +function d3_geo_cartesianDot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +function d3_geo_cartesianCross(a, b) { + return [ + a[1] * b[2] - a[2] * b[1], + a[2] * b[0] - a[0] * b[2], + a[0] * b[1] - a[1] * b[0] + ]; +} + +function d3_geo_cartesianAdd(a, b) { + a[0] += b[0]; + a[1] += b[1]; + a[2] += b[2]; +} + +function d3_geo_cartesianScale(vector, k) { + return [ + vector[0] * k, + vector[1] * k, + vector[2] * k + ]; +} + +function d3_geo_cartesianNormalize(d) { + var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); + d[0] /= l; + d[1] /= l; + d[2] /= l; +} + +function d3_geo_equirectangular(λ, φ) { + return [λ, φ]; +} + +(d3.geo.equirectangular = function() { + return d3_geo_projection(d3_geo_equirectangular); +}).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; + +d3.geo.rotation = function(rotate) { + rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); + + function forward(coordinates) { + coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; } - function d3_geo_clipView(x0, y0, x1, y1) { - return function(listener) { - var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring; - var clip = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - listener = bufferListener; - segments = []; - polygon = []; - }, - polygonEnd: function() { - listener = listener_; - if (segments.length) { - listener.polygonStart(); - d3_geo_clipPolygon(d3.merge(segments), compare, inside, interpolate, listener); - listener.polygonEnd(); - } - segments = polygon = ring = null; - } - }; - function inside(point) { - var a = corner(point, -1), i = !insidePolygon([ a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0 ]); - return i; + + forward.invert = function(coordinates) { + coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + }; + + return forward; +}; + +// Note: |δλ| must be < 2π +function d3_geo_rotation(δλ, δφ, δγ) { + return δλ ? (δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) + : d3_geo_rotationλ(δλ)) + : (δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) + : d3_geo_equirectangular); +} + +function d3_geo_forwardRotationλ(δλ) { + return function(λ, φ) { + return λ += δλ, [λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ]; + }; +} + +function d3_geo_rotationλ(δλ) { + var rotation = d3_geo_forwardRotationλ(δλ); + rotation.invert = d3_geo_forwardRotationλ(-δλ); + return rotation; +} + +function d3_geo_rotationφγ(δφ, δγ) { + var cosδφ = Math.cos(δφ), + sinδφ = Math.sin(δφ), + cosδγ = Math.cos(δγ), + sinδγ = Math.sin(δγ); + + function rotation(λ, φ) { + var cosφ = Math.cos(φ), + x = Math.cos(λ) * cosφ, + y = Math.sin(λ) * cosφ, + z = Math.sin(φ), + k = z * cosδφ + x * sinδφ; + return [ + Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), + Math.asin(Math.max(-1, Math.min(1, k * cosδγ + y * sinδγ))) + ]; + } + + rotation.invert = function(λ, φ) { + var cosφ = Math.cos(φ), + x = Math.cos(λ) * cosφ, + y = Math.sin(λ) * cosφ, + z = Math.sin(φ), + k = z * cosδγ - y * sinδγ; + return [ + Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), + Math.asin(Math.max(-1, Math.min(1, k * cosδφ - x * sinδφ))) + ]; + }; + + return rotation; +} + +d3.geo.circle = function() { + var origin = [0, 0], + angle, + precision = 6, + interpolate; + + function circle() { + var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, + rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, + ring = []; + + interpolate(null, null, 1, { + point: function(x, y) { + ring.push(x = rotate(x, y)); + x[0] *= d3_degrees, x[1] *= d3_degrees; } - function insidePolygon(p) { - var wn = 0, n = polygon.length, y = p[1]; - for (var i = 0; i < n; ++i) { - for (var j = 1, v = polygon[i], m = v.length, a = v[0]; j < m; ++j) { - b = v[j]; - if (a[1] <= y) { - if (b[1] > y && isLeft(a, b, p) > 0) ++wn; - } else { - if (b[1] <= y && isLeft(a, b, p) < 0) --wn; - } - a = b; + }); + + return {type: "Polygon", coordinates: [ring]}; + } + + circle.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return circle; + }; + + circle.angle = function(x) { + if (!arguments.length) return angle; + interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); + return circle; + }; + + circle.precision = function(_) { + if (!arguments.length) return precision; + interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); + return circle; + }; + + return circle.angle(90); +}; + +// Interpolates along a circle centered at [0°, 0°], with a given radius and +// precision. +function d3_geo_circleInterpolate(radius, precision) { + var cr = Math.cos(radius), + sr = Math.sin(radius); + return function(from, to, direction, listener) { + if (from != null) { + from = d3_geo_circleAngle(cr, from); + to = d3_geo_circleAngle(cr, to); + if (direction > 0 ? from < to: from > to) from += direction * 2 * π; + } else { + from = radius + direction * 2 * π; + to = radius; + } + var point; + for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) { + listener.point((point = d3_geo_spherical([ + cr, + -sr * Math.cos(t), + -sr * Math.sin(t) + ]))[0], point[1]); + } + }; +} + +// Signed angle of a cartesian point relative to [cr, 0, 0]. +function d3_geo_circleAngle(cr, point) { + var a = d3_geo_cartesian(point); + a[0] -= cr; + d3_geo_cartesianNormalize(a); + var angle = d3_acos(-a[1]); + return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); +} + +// Clip features against a small circle centered at [0°, 0°]. +function d3_geo_clipCircle(radius) { + var cr = Math.cos(radius), + smallRadius = cr > 0, + notHemisphere = Math.abs(cr) > ε, // TODO optimise for this common case + interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); + + return d3_geo_clip(visible, clipLine, interpolate); + + function visible(λ, φ) { + return Math.cos(λ) * Math.cos(φ) > cr; + } + + // Takes a line and cuts into visible segments. Return values used for + // polygon clipping: + // 0: there were intersections or the line was empty. + // 1: no intersections. + // 2: there were intersections, and the first and last segments should be + // rejoined. + function clipLine(listener) { + var point0, // previous point + c0, // code for previous point + v0, // visibility of previous point + v00, // visibility of first point + clean; // no intersections + return { + lineStart: function() { + v00 = v0 = false; + clean = 1; + }, + point: function(λ, φ) { + var point1 = [λ, φ], + point2, + v = visible(λ, φ), + c = smallRadius + ? v ? 0 : code(λ, φ) + : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; + if (!point0 && (v00 = v0 = v)) listener.lineStart(); + // Handle degeneracies. + // TODO ignore if not clipping polygons. + if (v !== v0) { + point2 = intersect(point0, point1); + if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { + point1[0] += ε; + point1[1] += ε; + v = visible(point1[0], point1[1]); } } - return wn !== 0; - } - function isLeft(a, b, c) { - return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); - } - function interpolate(from, to, direction, listener) { - var a = corner(from, direction), a1 = corner(to, direction); - if (a !== a1) { - do { - listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); - } while ((a = (a + direction + 4) % 4) !== a1); - } else { - listener.point(to[0], to[1]); - } - } - function visible(x, y) { - return x0 <= x && x <= x1 && y0 <= y && y <= y1; - } - function point(x, y) { - if (visible(x, y)) listener.point(x, y); - } - var x__, y__, v__, x_, y_, v_, first; - function lineStart() { - clip.point = linePoint; - if (polygon) polygon.push(ring = []); - first = true; - v_ = false; - x_ = y_ = NaN; - } - function lineEnd() { - if (segments) { - linePoint(x__, y__); - if (v__ && v_) bufferListener.rejoin(); - segments.push(bufferListener.buffer()); - } - clip.point = point; - if (v_) listener.lineEnd(); - } - function linePoint(x, y) { - var v = visible(x, y); - if (polygon) ring.push([ x, y ]); - if (first) { - x__ = x, y__ = y, v__ = v; - first = false; + if (v !== v0) { + clean = 0; if (v) { + // outside going in + listener.lineStart(); + point2 = intersect(point1, point0); + listener.point(point2[0], point2[1]); + } else { + // inside going out + point2 = intersect(point0, point1); + listener.point(point2[0], point2[1]); + listener.lineEnd(); + } + point0 = point2; + } else if (notHemisphere && point0 && smallRadius ^ v) { + var t; + // If the codes for two points are different, or are both zero, + // and there this segment intersects with the small circle. + if (!(c & c0) && (t = intersect(point1, point0, true))) { + clean = 0; + if (smallRadius) { + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + } else { + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + } + } + } + if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { + listener.point(point1[0], point1[1]); + } + point0 = point1, v0 = v, c0 = c; + }, + lineEnd: function() { + if (v0) listener.lineEnd(); + point0 = null; + }, + // Rejoin first and last segments if there were intersections and the first + // and last points were visible. + clean: function() { return clean | ((v00 && v0) << 1); } + }; + } + + // Intersects the great circle between a and b with the clip circle. + function intersect(a, b, two) { + var pa = d3_geo_cartesian(a), + pb = d3_geo_cartesian(b); + + // We have two planes, n1.p = d1 and n2.p = d2. + // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2). + var n1 = [1, 0, 0], // normal + n2 = d3_geo_cartesianCross(pa, pb), + n2n2 = d3_geo_cartesianDot(n2, n2), + n1n2 = n2[0], // d3_geo_cartesianDot(n1, n2), + determinant = n2n2 - n1n2 * n1n2; + + // Two polar points. + if (!determinant) return !two && a; + + var c1 = cr * n2n2 / determinant, + c2 = -cr * n1n2 / determinant, + n1xn2 = d3_geo_cartesianCross(n1, n2), + A = d3_geo_cartesianScale(n1, c1), + B = d3_geo_cartesianScale(n2, c2); + d3_geo_cartesianAdd(A, B); + + // Solve |p(t)|^2 = 1. + var u = n1xn2, + w = d3_geo_cartesianDot(A, u), + uu = d3_geo_cartesianDot(u, u), + t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); + + if (t2 < 0) return; + + var t = Math.sqrt(t2), + q = d3_geo_cartesianScale(u, (-w - t) / uu); + d3_geo_cartesianAdd(q, A); + q = d3_geo_spherical(q); + if (!two) return q; + + // Two intersection points. + var λ0 = a[0], + λ1 = b[0], + φ0 = a[1], + φ1 = b[1], + z; + if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; + var δλ = λ1 - λ0, + polar = Math.abs(δλ - π) < ε, + meridian = polar || δλ < ε; + + if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; + + // Check that the first point is between a and b. + if (meridian + ? polar + ? φ0 + φ1 > 0 ^ q[1] < (Math.abs(q[0] - λ0) < ε ? φ0 : φ1) + : φ0 <= q[1] && q[1] <= φ1 + : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { + var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); + d3_geo_cartesianAdd(q1, A); + return [q, d3_geo_spherical(q1)]; + } + } + + // Generates a 4-bit vector representing the location of a point relative to + // the small circle's bounding box. + function code(λ, φ) { + var r = smallRadius ? radius : π - radius, + code = 0; + if (λ < -r) code |= 1; // left + else if (λ > r) code |= 2; // right + if (φ < -r) code |= 4; // below + else if (φ > r) code |= 8; // above + return code; + } +} + +var d3_geo_clipViewMAX = 1e9; + +function d3_geo_clipView(x0, y0, x1, y1) { + return function(listener) { + var listener_ = listener, + bufferListener = d3_geo_clipBufferListener(), + segments, + polygon, + ring; + + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + listener = bufferListener; + segments = []; + polygon = []; + }, + polygonEnd: function() { + listener = listener_; + if ((segments = d3.merge(segments)).length) { + listener.polygonStart(); + d3_geo_clipPolygon(segments, compare, inside, interpolate, listener); + listener.polygonEnd(); + } else if (insidePolygon([x0, y0])) { + listener.polygonStart(), listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(), listener.polygonEnd(); + } + segments = polygon = ring = null; + } + }; + + function inside(point) { + var a = corner(point, -1), + i = insidePolygon([a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0]); + return i; + } + + function insidePolygon(p) { + var wn = 0, // the winding number counter + n = polygon.length, + y = p[1]; + + for (var i = 0; i < n; ++i) { + for (var j = 1, v = polygon[i], m = v.length, a = v[0]; j < m; ++j) { + b = v[j]; + if (a[1] <= y) { + if (b[1] > y && isLeft(a, b, p) > 0) ++wn; + } else { + if (b[1] <= y && isLeft(a, b, p) < 0) --wn; + } + a = b; + } + } + return wn !== 0; + } + + function isLeft(a, b, c) { + return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); + } + + function interpolate(from, to, direction, listener) { + var a = 0, a1 = 0; + if (from == null || + (a = corner(from, direction)) !== (a1 = corner(to, direction)) || + comparePoints(from, to) < 0 ^ direction > 0) { + do { + listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); + } while ((a = (a + direction + 4) % 4) !== a1); + } else { + listener.point(to[0], to[1]); + } + } + + function visible(x, y) { + return x0 <= x && x <= x1 && y0 <= y && y <= y1; + } + + function point(x, y) { + if (visible(x, y)) listener.point(x, y); + } + + var x__, y__, v__, // first point + x_, y_, v_, // previous point + first; + + function lineStart() { + clip.point = linePoint; + if (polygon) polygon.push(ring = []); + first = true; + v_ = false; + x_ = y_ = NaN; + } + + function lineEnd() { + // TODO rather than special-case polygons, simply handle them separately. + // Ideally, coincident intersection points should be jittered to avoid + // clipping issues. + if (segments) { + linePoint(x__, y__); + if (v__ && v_) bufferListener.rejoin(); + segments.push(bufferListener.buffer()); + } + clip.point = point; + if (v_) listener.lineEnd(); + } + + function linePoint(x, y) { + x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x)); + y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y)); + var v = visible(x, y); + if (polygon) ring.push([x, y]); + if (first) { + x__ = x, y__ = y, v__ = v; + first = false; + if (v) { + listener.lineStart(); + listener.point(x, y); + } + } else { + if (v && v_) listener.point(x, y); + else { + var a = [x_, y_], + b = [x, y]; + if (clipLine(a, b)) { + if (!v_) { + listener.lineStart(); + listener.point(a[0], a[1]); + } + listener.point(b[0], b[1]); + if (!v) listener.lineEnd(); + } else { listener.lineStart(); listener.point(x, y); } - } else { - if (v && v_) listener.point(x, y); else { - var a = [ x_, y_ ], b = [ x, y ]; - if (clipLine(a, b)) { - if (!v_) { - listener.lineStart(); - listener.point(a[0], a[1]); - } - listener.point(b[0], b[1]); - if (!v) listener.lineEnd(); - } - } } - x_ = x, y_ = y, v_ = v; } - return clip; - }; - function corner(p, direction) { - return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; + x_ = x, y_ = y, v_ = v; } - function compare(a, b) { - a = a.point, b = b.point; - var ca = corner(a, 1), cb = corner(b, 1); - return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; - } - function clipLine(a, b) { - var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ]; - if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1; - if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx, t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1, -dy, t)) { - if (t[1] < 1) { - b[0] = a[0] + t[1] * dx; - b[1] = a[1] + t[1] * dy; - } - if (t[0] > 0) { - a[0] += t[0] * dx; - a[1] += t[0] * dy; - } - return true; + + return clip; + }; + + function corner(p, direction) { + return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 + : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 + : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 + : direction > 0 ? 3 : 2; // Math.abs(p[1] - y1) < ε + } + + function compare(a, b) { + return comparePoints(a.point, b.point); + } + + function comparePoints(a, b) { + var ca = corner(a, 1), + cb = corner(b, 1); + return ca !== cb ? ca - cb + : ca === 0 ? b[1] - a[1] + : ca === 1 ? a[0] - b[0] + : ca === 2 ? a[1] - b[1] + : b[0] - a[0]; + } + + // Liang–Barsky line clipping. + function clipLine(a, b) { + var dx = b[0] - a[0], + dy = b[1] - a[1], + t = [0, 1]; + + if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1; + + if (d3_geo_clipViewT(x0 - a[0], dx, t) && + d3_geo_clipViewT(a[0] - x1, -dx, t) && + d3_geo_clipViewT(y0 - a[1], dy, t) && + d3_geo_clipViewT(a[1] - y1, -dy, t)) { + if (t[1] < 1) { + b[0] = a[0] + t[1] * dx; + b[1] = a[1] + t[1] * dy; } - return false; + if (t[0] > 0) { + a[0] += t[0] * dx; + a[1] += t[0] * dy; + } + return true; } + + return false; } - function d3_geo_clipViewT(num, denominator, t) { - if (Math.abs(denominator) < ε) return num < 0; - var u = num / denominator; - if (denominator > 0) { - if (u > t[1]) return false; - if (u > t[0]) t[0] = u; - } else { - if (u < t[0]) return false; - if (u < t[1]) t[1] = u; - } - return true; +} + +function d3_geo_clipViewT(num, denominator, t) { + if (Math.abs(denominator) < ε) return num <= 0; + + var u = num / denominator; + + if (denominator > 0) { + if (u > t[1]) return false; + if (u > t[0]) t[0] = u; + } else { + if (u < t[0]) return false; + if (u < t[1]) t[1] = u; } - function d3_geo_compose(a, b) { - function compose(x, y) { - return x = a(x, y), b(x[0], x[1]); - } - if (a.invert && b.invert) compose.invert = function(x, y) { - return x = b.invert(x, y), x && a.invert(x[0], x[1]); - }; - return compose; + return true; +} +function d3_geo_compose(a, b) { + + function compose(x, y) { + return x = a(x, y), b(x[0], x[1]); } - function d3_geo_equirectangular(λ, φ) { - return [ λ, φ ]; - } - (d3.geo.equirectangular = function() { - return d3_geo_projection(d3_geo_equirectangular).scale(250 / π); - }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; - var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { - return 1 / cosλcosφ; - }, Math.atan); - (d3.geo.gnomonic = function() { - return d3_geo_projection(d3_geo_gnomonic); - }).raw = d3_geo_gnomonic; - d3.geo.graticule = function() { - var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; - function graticule() { - return { - type: "MultiLineString", - coordinates: lines() - }; - } - function lines() { - return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) { - return Math.abs(x % DX) > ε; - }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { - return Math.abs(y % DY) > ε; - }).map(y)); - } - graticule.lines = function() { - return lines().map(function(coordinates) { - return { - type: "LineString", - coordinates: coordinates - }; - }); - }; - graticule.outline = function() { - return { - type: "Polygon", - coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] - }; - }; - graticule.extent = function(_) { - if (!arguments.length) return graticule.minorExtent(); - return graticule.majorExtent(_).minorExtent(_); - }; - graticule.majorExtent = function(_) { - if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; - X0 = +_[0][0], X1 = +_[1][0]; - Y0 = +_[0][1], Y1 = +_[1][1]; - if (X0 > X1) _ = X0, X0 = X1, X1 = _; - if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; - return graticule.precision(precision); - }; - graticule.minorExtent = function(_) { - if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; - x0 = +_[0][0], x1 = +_[1][0]; - y0 = +_[0][1], y1 = +_[1][1]; - if (x0 > x1) _ = x0, x0 = x1, x1 = _; - if (y0 > y1) _ = y0, y0 = y1, y1 = _; - return graticule.precision(precision); - }; - graticule.step = function(_) { - if (!arguments.length) return graticule.minorStep(); - return graticule.majorStep(_).minorStep(_); - }; - graticule.majorStep = function(_) { - if (!arguments.length) return [ DX, DY ]; - DX = +_[0], DY = +_[1]; - return graticule; - }; - graticule.minorStep = function(_) { - if (!arguments.length) return [ dx, dy ]; - dx = +_[0], dy = +_[1]; - return graticule; - }; - graticule.precision = function(_) { - if (!arguments.length) return precision; - precision = +_; - x = d3_geo_graticuleX(y0, y1, 90); - y = d3_geo_graticuleY(x0, x1, precision); - X = d3_geo_graticuleX(Y0, Y1, 90); - Y = d3_geo_graticuleY(X0, X1, precision); - return graticule; - }; - return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); + + if (a.invert && b.invert) compose.invert = function(x, y) { + return x = b.invert(x, y), x && a.invert(x[0], x[1]); }; - function d3_geo_graticuleX(y0, y1, dy) { - var y = d3.range(y0, y1 - ε, dy).concat(y1); - return function(x) { - return y.map(function(y) { - return [ x, y ]; - }); - }; + + return compose; +} + +d3.geo.stream = function(object, listener) { + if (d3_geo_streamObjectType.hasOwnProperty(object.type)) { + d3_geo_streamObjectType[object.type](object, listener); + } else { + d3_geo_streamGeometry(object, listener); } - function d3_geo_graticuleY(x0, x1, dx) { - var x = d3.range(x0, x1 - ε, dx).concat(x1); - return function(y) { - return x.map(function(x) { - return [ x, y ]; - }); - }; +}; + +function d3_geo_streamGeometry(geometry, listener) { + if (d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { + d3_geo_streamGeometryType[geometry.type](geometry, listener); } - function d3_geo_haversin(x) { - return (x = Math.sin(x / 2)) * x; +} + +var d3_geo_streamObjectType = { + Feature: function(feature, listener) { + d3_geo_streamGeometry(feature.geometry, listener); + }, + FeatureCollection: function(object, listener) { + var features = object.features, i = -1, n = features.length; + while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); } - d3.geo.interpolate = function(source, target) { - return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); - }; - function d3_geo_interpolate(x0, y0, x1, y1) { - var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_geo_haversin(y1 - y0) + cy0 * cy1 * d3_geo_haversin(x1 - x0))), k = 1 / Math.sin(d); - var interpolate = d ? function(t) { - var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; - return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; - } : function() { - return [ x0 * d3_degrees, y0 * d3_degrees ]; - }; - interpolate.distance = d; - return interpolate; +}; + +var d3_geo_streamGeometryType = { + Sphere: function(object, listener) { + listener.sphere(); + }, + Point: function(object, listener) { + var coordinate = object.coordinates; + listener.point(coordinate[0], coordinate[1]); + }, + MultiPoint: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate; + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); + }, + LineString: function(object, listener) { + d3_geo_streamLine(object.coordinates, listener, 0); + }, + MultiLineString: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); + }, + Polygon: function(object, listener) { + d3_geo_streamPolygon(object.coordinates, listener); + }, + MultiPolygon: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); + }, + GeometryCollection: function(object, listener) { + var geometries = object.geometries, i = -1, n = geometries.length; + while (++i < n) d3_geo_streamGeometry(geometries[i], listener); } - d3.geo.greatArc = function() { - var source = d3_source, source_, target = d3_target, target_; - function greatArc() { - return { - type: "LineString", - coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] - }; - } - greatArc.distance = function() { - return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); - }; - greatArc.source = function(_) { - if (!arguments.length) return source; - source = _, source_ = typeof _ === "function" ? null : _; - return greatArc; - }; - greatArc.target = function(_) { - if (!arguments.length) return target; - target = _, target_ = typeof _ === "function" ? null : _; - return greatArc; - }; - greatArc.precision = function() { - return arguments.length ? greatArc : 0; - }; - return greatArc; - }; - function d3_geo_mercator(λ, φ) { - return [ λ / (2 * π), Math.max(-.5, Math.min(+.5, Math.log(Math.tan(π / 4 + φ / 2)) / (2 * π))) ]; - } - d3_geo_mercator.invert = function(x, y) { - return [ 2 * π * x, 2 * Math.atan(Math.exp(2 * π * y)) - π / 2 ]; - }; - (d3.geo.mercator = function() { - return d3_geo_projection(d3_geo_mercator).scale(500); - }).raw = d3_geo_mercator; - var d3_geo_orthographic = d3_geo_azimuthal(function() { - return 1; - }, Math.asin); - (d3.geo.orthographic = function() { - return d3_geo_projection(d3_geo_orthographic); - }).raw = d3_geo_orthographic; - d3.geo.path = function() { - var pointRadius = 4.5, projection, context, projectStream, contextStream; - function path(object) { - if (object) d3.geo.stream(object, projectStream(contextStream.pointRadius(typeof pointRadius === "function" ? +pointRadius.apply(this, arguments) : pointRadius))); - return contextStream.result(); - } - path.area = function(object) { - d3_geo_pathAreaSum = 0; - d3.geo.stream(object, projectStream(d3_geo_pathArea)); - return d3_geo_pathAreaSum; - }; - path.centroid = function(object) { - d3_geo_centroidDimension = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; - d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); - return d3_geo_centroidZ ? [ d3_geo_centroidX / d3_geo_centroidZ, d3_geo_centroidY / d3_geo_centroidZ ] : undefined; - }; - path.bounds = function(object) { - return d3_geo_bounds(projectStream)(object); - }; - path.projection = function(_) { - if (!arguments.length) return projection; - projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; - return path; - }; - path.context = function(_) { - if (!arguments.length) return context; - contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); - return path; - }; - path.pointRadius = function(_) { - if (!arguments.length) return pointRadius; - pointRadius = typeof _ === "function" ? _ : +_; - return path; - }; - return path.projection(d3.geo.albersUsa()).context(null); - }; - function d3_geo_pathCircle(radius) { - return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + +2 * radius + "z"; - } - function d3_geo_pathProjectStream(project) { - var resample = d3_geo_resample(function(λ, φ) { - return project([ λ * d3_degrees, φ * d3_degrees ]); - }); - return function(stream) { - stream = resample(stream); - return { - point: function(λ, φ) { - stream.point(λ * d3_radians, φ * d3_radians); - }, - sphere: function() { - stream.sphere(); - }, - lineStart: function() { - stream.lineStart(); - }, - lineEnd: function() { - stream.lineEnd(); - }, - polygonStart: function() { - stream.polygonStart(); - }, - polygonEnd: function() { - stream.polygonEnd(); - } - }; - }; - } - function d3_geo_pathBuffer() { - var pointCircle = d3_geo_pathCircle(4.5), buffer = []; - var stream = { +}; + +function d3_geo_streamLine(coordinates, listener, closed) { + var i = -1, n = coordinates.length - closed, coordinate; + listener.lineStart(); + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); + listener.lineEnd(); +} + +function d3_geo_streamPolygon(coordinates, listener) { + var i = -1, n = coordinates.length; + listener.polygonStart(); + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); + listener.polygonEnd(); +} + +function d3_geo_resample(project) { + var δ2 = .5, // precision, px² + maxDepth = 16; + + function resample(stream) { + var λ0, x0, y0, a0, b0, c0; // previous point + + var resample = { point: point, - lineStart: function() { - stream.point = pointLineStart; - }, + lineStart: lineStart, lineEnd: lineEnd, - polygonStart: function() { - stream.lineEnd = lineEndPolygon; - }, - polygonEnd: function() { - stream.lineEnd = lineEnd; - stream.point = point; - }, - pointRadius: function(_) { - pointCircle = d3_geo_pathCircle(_); - return stream; - }, - result: function() { - if (buffer.length) { - var result = buffer.join(""); - buffer = []; - return result; - } + polygonStart: function() { stream.polygonStart(); resample.lineStart = polygonLineStart; }, + polygonEnd: function() { stream.polygonEnd(); resample.lineStart = lineStart; } + }; + + function point(x, y) { + x = project(x, y); + stream.point(x[0], x[1]); + } + + function lineStart() { + x0 = NaN; + resample.point = linePoint; + stream.lineStart(); + } + + function linePoint(λ, φ) { + var c = d3_geo_cartesian([λ, φ]), p = project(λ, φ); + 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); + stream.point(x0, y0); + } + + function lineEnd() { + resample.point = point; + stream.lineEnd(); + } + + function polygonLineStart() { + var λ00, φ00, x00, y00, a00, b00, c00; // first point + + lineStart(); + + resample.point = function(λ, φ) { + linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; + resample.point = linePoint; + }; + + resample.lineEnd = function() { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); + resample.lineEnd = lineEnd; + lineEnd(); + }; + } + + return resample; + } + + function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { + var dx = x1 - x0, + dy = y1 - y0, + d2 = dx * dx + dy * dy; + if (d2 > 4 * δ2 && depth--) { + var a = a0 + a1, + b = b0 + b1, + c = c0 + c1, + m = Math.sqrt(a * a + b * b + c * c), + φ2 = Math.asin(c /= m), + λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), + p = project(λ2, φ2), + x2 = p[0], + y2 = p[1], + dx2 = x2 - x0, + dy2 = y2 - y0, + dz = dy * dx2 - dx * dy2; + if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3) { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); + stream.point(x2, y2); + resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); } - }; - function point(x, y) { - buffer.push("M", x, ",", y, pointCircle); } - function pointLineStart(x, y) { - buffer.push("M", x, ",", y); - stream.point = pointLine; - } - function pointLine(x, y) { - buffer.push("L", x, ",", y); - } - function lineEnd() { - stream.point = point; - } - function lineEndPolygon() { - buffer.push("Z"); - } - return stream; } - function d3_geo_pathContext(context) { - var pointRadius = 4.5; - var stream = { - point: point, - lineStart: function() { - stream.point = pointLineStart; - }, - lineEnd: lineEnd, - polygonStart: function() { - stream.lineEnd = lineEndPolygon; - }, - polygonEnd: function() { - stream.lineEnd = lineEnd; - stream.point = point; - }, - pointRadius: function(_) { - pointRadius = _; - return stream; - }, - result: d3_noop - }; - function point(x, y) { - context.moveTo(x, y); - context.arc(x, y, pointRadius, 0, 2 * π); - } - function pointLineStart(x, y) { - context.moveTo(x, y); - stream.point = pointLine; - } - function pointLine(x, y) { - context.lineTo(x, y); - } - function lineEnd() { - stream.point = point; - } - function lineEndPolygon() { - context.closePath(); - } - return stream; + + resample.precision = function(_) { + if (!arguments.length) return Math.sqrt(δ2); + maxDepth = (δ2 = _ * _) > 0 && 16; + return resample; + }; + + return resample; +} + +d3.geo.projection = d3_geo_projection; +d3.geo.projectionMutator = d3_geo_projectionMutator; + +function d3_geo_projection(project) { + return d3_geo_projectionMutator(function() { return project; })(); +} + +function d3_geo_projectionMutator(projectAt) { + var project, + rotate, + projectRotate, + projectResample = d3_geo_resample(function(x, y) { x = project(x, y); return [x[0] * k + δx, δy - x[1] * k]; }), + k = 150, // scale + x = 480, y = 250, // translate + λ = 0, φ = 0, // center + δλ = 0, δφ = 0, δγ = 0, // rotate + δx, δy, // center + preclip = d3_geo_clipAntimeridian, + postclip = d3_identity, + clipAngle = null, + clipExtent = null; + + function projection(point) { + point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); + return [point[0] * k + δx, δy - point[1] * k]; } - var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { - point: d3_noop, + + function invert(point) { + point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); + return point && [point[0] * d3_degrees, point[1] * d3_degrees]; + } + + projection.stream = function(stream) { + return d3_geo_projectionRadiansRotate(rotate, preclip(projectResample(postclip(stream)))); + }; + + projection.clipAngle = function(_) { + if (!arguments.length) return clipAngle; + preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); + return projection; + }; + + projection.clipExtent = function(_) { + if (!arguments.length) return clipExtent; + clipExtent = _; + postclip = _ == null ? d3_identity : d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]); + return projection; + }; + + projection.scale = function(_) { + if (!arguments.length) return k; + k = +_; + return reset(); + }; + + projection.translate = function(_) { + if (!arguments.length) return [x, y]; + x = +_[0]; + y = +_[1]; + return reset(); + }; + + projection.center = function(_) { + if (!arguments.length) return [λ * d3_degrees, φ * d3_degrees]; + λ = _[0] % 360 * d3_radians; + φ = _[1] % 360 * d3_radians; + return reset(); + }; + + projection.rotate = function(_) { + if (!arguments.length) return [δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees]; + δλ = _[0] % 360 * d3_radians; + δφ = _[1] % 360 * d3_radians; + δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; + return reset(); + }; + + d3.rebind(projection, projectResample, "precision"); + + function reset() { + projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); + var center = project(λ, φ); + δx = x - center[0] * k; + δy = y + center[1] * k; + return projection; + } + + return function() { + project = projectAt.apply(this, arguments); + projection.invert = project.invert && invert; + return reset(); + }; +} + +function d3_geo_projectionRadiansRotate(rotate, stream) { + return { + point: function(x, y) { + y = rotate(x * d3_radians, y * d3_radians), x = y[0]; + stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]); + }, + sphere: function() { stream.sphere(); }, + lineStart: function() { stream.lineStart(); }, + lineEnd: function() { stream.lineEnd(); }, + polygonStart: function() { stream.polygonStart(); }, + polygonEnd: function() { stream.polygonEnd(); } + }; +} + +function d3_geo_mercator(λ, φ) { + return [λ, Math.log(Math.tan(π / 4 + φ / 2))]; +} + +d3_geo_mercator.invert = function(x, y) { + return [x, 2 * Math.atan(Math.exp(y)) - π / 2]; +}; + +function d3_geo_mercatorProjection(project) { + var m = d3_geo_projection(project), + scale = m.scale, + translate = m.translate, + clipExtent = m.clipExtent, + clipAuto; + + m.scale = function() { + var v = scale.apply(m, arguments); + return v === m ? (clipAuto ? m.clipExtent(null) : m) : v; + }; + + m.translate = function() { + var v = translate.apply(m, arguments); + return v === m ? (clipAuto ? m.clipExtent(null) : m) : v; + }; + + m.clipExtent = function(_) { + var v = clipExtent.apply(m, arguments); + if (v === m) { + if (clipAuto = _ == null) { + var k = π * scale(), t = translate(); + clipExtent([[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]]); + } + } else if (clipAuto) { + v = null; + } + return v; + }; + + return m.clipExtent(null); +} + +(d3.geo.mercator = function() { + return d3_geo_mercatorProjection(d3_geo_mercator); +}).raw = d3_geo_mercator; + +function d3_geo_conic(projectAt) { + var φ0 = 0, + φ1 = π / 3, + m = d3_geo_projectionMutator(projectAt), + p = m(φ0, φ1); + + p.parallels = function(_) { + if (!arguments.length) return [φ0 / π * 180, φ1 / π * 180]; + return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); + }; + + return p; +} + +function d3_geo_conicEqualArea(φ0, φ1) { + var sinφ0 = Math.sin(φ0), + n = (sinφ0 + Math.sin(φ1)) / 2, + C = 1 + sinφ0 * (2 * n - sinφ0), + ρ0 = Math.sqrt(C) / n; + + function forward(λ, φ) { + var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; + return [ + ρ * Math.sin(λ *= n), + ρ0 - ρ * Math.cos(λ) + ]; + } + + forward.invert = function(x, y) { + var ρ0_y = ρ0 - y; + return [ + Math.atan2(x, ρ0_y) / n, + Math.asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) + ]; + }; + + return forward; +} + +(d3.geo.conicEqualArea = function() { + return d3_geo_conic(d3_geo_conicEqualArea); +}).raw = d3_geo_conicEqualArea; + +// A composite projection for the United States, 960×500. The set of standard +// parallels for each region comes from USGS, which is published here: +// http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers +d3.geo.albersUsa = function() { + var lower48 = d3.geo.conicEqualArea() + .rotate([98, 0]) + .center([0, 38]) + .parallels([29.5, 45.5]); + + var alaska = d3.geo.conicEqualArea() + .rotate([160, 0]) + .center([0, 60]) + .parallels([55, 65]); + + var hawaii = d3.geo.conicEqualArea() + .rotate([160, 0]) + .center([0, 20]) + .parallels([8, 18]); + + var puertoRico = d3.geo.conicEqualArea() + .rotate([60, 0]) + .center([0, 10]) + .parallels([8, 18]); + + var alaskaInvert, + hawaiiInvert, + puertoRicoInvert; + + function albersUsa(coordinates) { + return projection(coordinates)(coordinates); + } + + function projection(point) { + var lon = point[0], + lat = point[1]; + return lat > 50 ? alaska + : lon < -140 ? hawaii + : lat < 21 ? puertoRico + : lower48; + } + + albersUsa.invert = function(coordinates) { + return alaskaInvert(coordinates) || hawaiiInvert(coordinates) || puertoRicoInvert(coordinates) || lower48.invert(coordinates); + }; + + albersUsa.scale = function(x) { + if (!arguments.length) return lower48.scale(); + lower48.scale(x); + alaska.scale(x * .6); + hawaii.scale(x); + puertoRico.scale(x * 1.5); + return albersUsa.translate(lower48.translate()); + }; + + albersUsa.translate = function(x) { + if (!arguments.length) return lower48.translate(); + var dz = lower48.scale(), + dx = x[0], + dy = x[1]; + lower48.translate(x); + alaska.translate([dx - .40 * dz, dy + .17 * dz]); + hawaii.translate([dx - .19 * dz, dy + .20 * dz]); + puertoRico.translate([dx + .58 * dz, dy + .43 * dz]); + + alaskaInvert = d3_geo_albersUsaInvert(alaska, [[-180, 50], [-130, 72]]); + hawaiiInvert = d3_geo_albersUsaInvert(hawaii, [[-164, 18], [-154, 24]]); + puertoRicoInvert = d3_geo_albersUsaInvert(puertoRico, [[-67.5, 17.5], [-65, 19]]); + + return albersUsa; + }; + + return albersUsa.scale(1000); +}; + +function d3_geo_albersUsaInvert(projection, extent) { + var a = projection(extent[0]), + b = projection([.5 * (extent[0][0] + extent[1][0]), extent[0][1]]), + c = projection([extent[1][0], extent[0][1]]), + d = projection(extent[1]); + + var dya = b[1]- a[1], + dxa = b[0]- a[0], + dyb = c[1]- b[1], + dxb = c[0]- b[0]; + + var ma = dya / dxa, + mb = dyb / dxb; + + // Find center of circle going through points [a, b, c]. + var cx = .5 * (ma * mb * (a[1] - c[1]) + mb * (a[0] + b[0]) - ma * (b[0] + c[0])) / (mb - ma), + cy = (.5 * (a[0] + b[0]) - cx) / ma + .5 * (a[1] + b[1]); + + // Radial distance² from center. + var dx0 = d[0] - cx, + dy0 = d[1] - cy, + dx1 = a[0] - cx, + dy1 = a[1] - cy, + r0 = dx0 * dx0 + dy0 * dy0, + r1 = dx1 * dx1 + dy1 * dy1; + + // Angular extent. + var a0 = Math.atan2(dy0, dx0), + a1 = Math.atan2(dy1, dx1); + + return function(coordinates) { + var dx = coordinates[0] - cx, + dy = coordinates[1] - cy, + r = dx * dx + dy * dy, + a = Math.atan2(dy, dx); + if (r0 < r && r < r1 && a0 < a && a < a1) return projection.invert(coordinates); + }; +} + +d3.geo.area = function(object) { + d3_geo_areaSum = 0; + d3.geo.stream(object, d3_geo_area); + return d3_geo_areaSum; +}; + +var d3_geo_areaSum, + d3_geo_areaRingU, + d3_geo_areaRingV; + +var d3_geo_area = { + sphere: function() { d3_geo_areaSum += 4 * π; }, + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + + // Only count area for polygon rings. + polygonStart: function() { + d3_geo_areaRingU = 1, d3_geo_areaRingV = 0; + d3_geo_area.lineStart = d3_geo_areaRingStart; + }, + polygonEnd: function() { + var area = 2 * Math.atan2(d3_geo_areaRingV, d3_geo_areaRingU); + d3_geo_areaSum += area < 0 ? 4 * π + area : area; + d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; + } +}; + +function d3_geo_areaRingStart() { + var λ00, φ00, λ0, cosφ0, sinφ0; // start point and two previous points + + // For the first point, … + d3_geo_area.point = function(λ, φ) { + d3_geo_area.point = nextPoint; + λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), sinφ0 = Math.sin(φ); + }; + + // For subsequent points, … + function nextPoint(λ, φ) { + λ *= d3_radians; + φ = φ * d3_radians / 2 + π / 4; // half the angular distance from south pole + + // Spherical excess E for a spherical triangle with vertices: south pole, + // previous point, current point. Uses a formula derived from Cagnoli’s + // theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2). + var dλ = λ - λ0, + cosφ = Math.cos(φ), + sinφ = Math.sin(φ), + k = sinφ0 * sinφ, + u0 = d3_geo_areaRingU, + v0 = d3_geo_areaRingV, + u = cosφ0 * cosφ + k * Math.cos(dλ), + v = k * Math.sin(dλ); + // ∑ arg(z) = arg(∏ z), where z = u + iv. + d3_geo_areaRingU = u0 * u - v0 * v; + d3_geo_areaRingV = v0 * u + u0 * v; + + // Advance the previous points. + λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; + } + + // For the last point, return to the start. + d3_geo_area.lineEnd = function() { + nextPoint(λ00, φ00); + }; +} + +d3.geo.bounds = d3_geo_bounds(d3_identity); + +function d3_geo_bounds(projectStream) { + var x0, y0, x1, y1; + + var bound = { + point: boundPoint, lineStart: d3_noop, lineEnd: d3_noop, - polygonStart: function() { - d3_geo_pathAreaPolygon = 0; - d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; - }, - polygonEnd: function() { - d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; - d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2); - } + + // While inside a polygon, ignore points in holes. + polygonStart: function() { bound.lineEnd = boundPolygonLineEnd; }, + polygonEnd: function() { bound.point = boundPoint; } }; - function d3_geo_pathAreaRingStart() { - var x00, y00, x0, y0; - d3_geo_pathArea.point = function(x, y) { - d3_geo_pathArea.point = nextPoint; - x00 = x0 = x, y00 = y0 = y; - }; - function nextPoint(x, y) { - d3_geo_pathAreaPolygon += y0 * x - x0 * y; - x0 = x, y0 = y; - } - d3_geo_pathArea.lineEnd = function() { - nextPoint(x00, y00); - }; + + function boundPoint(x, y) { + if (x < x0) x0 = x; + if (x > x1) x1 = x; + if (y < y0) y0 = y; + if (y > y1) y1 = y; } - var d3_geo_pathCentroid = { - point: d3_geo_pathCentroidPoint, - lineStart: d3_geo_pathCentroidLineStart, - lineEnd: d3_geo_pathCentroidLineEnd, - polygonStart: function() { - d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; - }, - polygonEnd: function() { - d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; - d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; - d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; - } + + function boundPolygonLineEnd() { + bound.point = bound.lineEnd = d3_noop; + } + + return function(feature) { + y1 = x1 = -(x0 = y0 = Infinity); + d3.geo.stream(feature, projectStream(bound)); + return [[x0, y0], [x1, y1]]; }; - function d3_geo_pathCentroidPoint(x, y) { - if (d3_geo_centroidDimension) return; - d3_geo_centroidX += x; - d3_geo_centroidY += y; - ++d3_geo_centroidZ; +} + +d3.geo.centroid = function(object) { + d3_geo_centroidDimension = d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; + d3.geo.stream(object, d3_geo_centroid); + var m; + if (d3_geo_centroidW && + Math.abs(m = Math.sqrt(d3_geo_centroidX * d3_geo_centroidX + d3_geo_centroidY * d3_geo_centroidY + d3_geo_centroidZ * d3_geo_centroidZ)) > ε) { + return [ + Math.atan2(d3_geo_centroidY, d3_geo_centroidX) * d3_degrees, + Math.asin(Math.max(-1, Math.min(1, d3_geo_centroidZ / m))) * d3_degrees + ]; } - function d3_geo_pathCentroidLineStart() { - var x0, y0; - if (d3_geo_centroidDimension !== 1) { - if (d3_geo_centroidDimension < 1) { - d3_geo_centroidDimension = 1; - d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; - } else return; - } - d3_geo_pathCentroid.point = function(x, y) { - d3_geo_pathCentroid.point = nextPoint; - x0 = x, y0 = y; - }; - function nextPoint(x, y) { - var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); - d3_geo_centroidX += z * (x0 + x) / 2; - d3_geo_centroidY += z * (y0 + y) / 2; - d3_geo_centroidZ += z; - x0 = x, y0 = y; - } - } - function d3_geo_pathCentroidLineEnd() { - d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; - } - function d3_geo_pathCentroidRingStart() { - var x00, y00, x0, y0; +}; + +var d3_geo_centroidDimension, + d3_geo_centroidW, + d3_geo_centroidX, + d3_geo_centroidY, + d3_geo_centroidZ; + +var d3_geo_centroid = { + sphere: function() { if (d3_geo_centroidDimension < 2) { d3_geo_centroidDimension = 2; + d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; + } + }, + point: d3_geo_centroidPoint, + lineStart: d3_geo_centroidLineStart, + lineEnd: d3_geo_centroidLineEnd, + polygonStart: function() { + if (d3_geo_centroidDimension < 2) { + d3_geo_centroidDimension = 2; + d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; + } + d3_geo_centroid.lineStart = d3_geo_centroidRingStart; + }, + polygonEnd: function() { + d3_geo_centroid.lineStart = d3_geo_centroidLineStart; + } +}; + +// Arithmetic mean of Cartesian vectors. +function d3_geo_centroidPoint(λ, φ) { + if (d3_geo_centroidDimension) return; + ++d3_geo_centroidW; + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + d3_geo_centroidX += (cosφ * Math.cos(λ) - d3_geo_centroidX) / d3_geo_centroidW; + d3_geo_centroidY += (cosφ * Math.sin(λ) - d3_geo_centroidY) / d3_geo_centroidW; + d3_geo_centroidZ += (Math.sin(φ) - d3_geo_centroidZ) / d3_geo_centroidW; +} + +function d3_geo_centroidRingStart() { + var λ00, φ00; // first point + + d3_geo_centroidDimension = 1; + d3_geo_centroidLineStart(); + d3_geo_centroidDimension = 2; + + var linePoint = d3_geo_centroid.point; + d3_geo_centroid.point = function(λ, φ) { + linePoint(λ00 = λ, φ00 = φ); + }; + d3_geo_centroid.lineEnd = function() { + d3_geo_centroid.point(λ00, φ00); + d3_geo_centroidLineEnd(); + d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; + }; +} + +function d3_geo_centroidLineStart() { + var x0, y0, z0; // previous point + + if (d3_geo_centroidDimension > 1) return; + if (d3_geo_centroidDimension < 1) { + d3_geo_centroidDimension = 1; + d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; + } + + d3_geo_centroid.point = function(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroid.point = nextPoint; + }; + + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), + x = cosφ * Math.cos(λ), + y = cosφ * Math.sin(λ), + z = Math.sin(φ), + w = Math.atan2( + Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), + x0 * x + y0 * y + z0 * z); + d3_geo_centroidW += w; + d3_geo_centroidX += w * (x0 + (x0 = x)); + d3_geo_centroidY += w * (y0 + (y0 = y)); + d3_geo_centroidZ += w * (z0 + (z0 = z)); + } +} + +function d3_geo_centroidLineEnd() { + d3_geo_centroid.point = d3_geo_centroidPoint; +} + +// TODO Unify this code with d3.geom.polygon area? + +var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + + // Only count area for polygon rings. + polygonStart: function() { + d3_geo_pathAreaPolygon = 0; + d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; + }, + polygonEnd: function() { + d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; + d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2); + } +}; + +function d3_geo_pathAreaRingStart() { + var x00, y00, x0, y0; + + // For the first point, … + d3_geo_pathArea.point = function(x, y) { + d3_geo_pathArea.point = nextPoint; + x00 = x0 = x, y00 = y0 = y; + }; + + // For subsequent points, … + function nextPoint(x, y) { + d3_geo_pathAreaPolygon += y0 * x - x0 * y; + x0 = x, y0 = y; + } + + // For the last point, return to the start. + d3_geo_pathArea.lineEnd = function() { + nextPoint(x00, y00); + }; +} +function d3_geo_pathBuffer() { + var pointCircle = d3_geo_pathCircle(4.5), + buffer = []; + + var stream = { + point: point, + + // While inside a line, override point to moveTo then lineTo. + lineStart: function() { stream.point = pointLineStart; }, + lineEnd: lineEnd, + + // While inside a polygon, override lineEnd to closePath. + polygonStart: function() { stream.lineEnd = lineEndPolygon; }, + polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; }, + + pointRadius: function(_) { + pointCircle = d3_geo_pathCircle(_); + return stream; + }, + + result: function() { + if (buffer.length) { + var result = buffer.join(""); + buffer = []; + return result; + } + } + }; + + function point(x, y) { + buffer.push("M", x, ",", y, pointCircle); + } + + function pointLineStart(x, y) { + buffer.push("M", x, ",", y); + stream.point = pointLine; + } + + function pointLine(x, y) { + buffer.push("L", x, ",", y); + } + + function lineEnd() { + stream.point = point; + } + + function lineEndPolygon() { + buffer.push("Z"); + } + + return stream; +} + +// TODO Unify this code with d3.geom.polygon centroid? +// TODO Enforce positive area for exterior, negative area for interior? + +var d3_geo_pathCentroid = { + point: d3_geo_pathCentroidPoint, + + // For lines, weight by length. + lineStart: d3_geo_pathCentroidLineStart, + lineEnd: d3_geo_pathCentroidLineEnd, + + // For polygons, weight by area. + polygonStart: function() { + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; + }, + polygonEnd: function() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; + d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; + } +}; + +function d3_geo_pathCentroidPoint(x, y) { + if (d3_geo_centroidDimension) return; + d3_geo_centroidX += x; + d3_geo_centroidY += y; + ++d3_geo_centroidZ; +} + +function d3_geo_pathCentroidLineStart() { + var x0, y0; + + if (d3_geo_centroidDimension !== 1) { + if (d3_geo_centroidDimension < 1) { + d3_geo_centroidDimension = 1; d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; - } - d3_geo_pathCentroid.point = function(x, y) { - d3_geo_pathCentroid.point = nextPoint; - x00 = x0 = x, y00 = y0 = y; - }; - function nextPoint(x, y) { - var z = y0 * x - x0 * y; - d3_geo_centroidX += z * (x0 + x); - d3_geo_centroidY += z * (y0 + y); - d3_geo_centroidZ += z * 3; - x0 = x, y0 = y; - } - d3_geo_pathCentroid.lineEnd = function() { - nextPoint(x00, y00); - }; + } else return; } - d3.geo.area = function(object) { - d3_geo_areaSum = 0; - d3.geo.stream(object, d3_geo_area); - return d3_geo_areaSum; + + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + x0 = x, y0 = y; }; - var d3_geo_areaSum, d3_geo_areaRingU, d3_geo_areaRingV; - var d3_geo_area = { - sphere: function() { - d3_geo_areaSum += 4 * π; + + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX += z * (x0 + x) / 2; + d3_geo_centroidY += z * (y0 + y) / 2; + d3_geo_centroidZ += z; + x0 = x, y0 = y; + } +} + +function d3_geo_pathCentroidLineEnd() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; +} + +function d3_geo_pathCentroidRingStart() { + var x00, y00, x0, y0; + + if (d3_geo_centroidDimension < 2) { + d3_geo_centroidDimension = 2; + d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; + } + + // For the first point, … + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + x00 = x0 = x, y00 = y0 = y; + }; + + // For subsequent points, … + function nextPoint(x, y) { + var z = y0 * x - x0 * y; + d3_geo_centroidX += z * (x0 + x); + d3_geo_centroidY += z * (y0 + y); + d3_geo_centroidZ += z * 3; + x0 = x, y0 = y; + } + + // For the last point, return to the start. + d3_geo_pathCentroid.lineEnd = function() { + nextPoint(x00, y00); + }; +} + +function d3_geo_pathContext(context) { + var pointRadius = 4.5; + + var stream = { + point: point, + + // While inside a line, override point to moveTo then lineTo. + lineStart: function() { stream.point = pointLineStart; }, + lineEnd: lineEnd, + + // While inside a polygon, override lineEnd to closePath. + polygonStart: function() { stream.lineEnd = lineEndPolygon; }, + polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; }, + + pointRadius: function(_) { + pointRadius = _; + return stream; }, - point: d3_noop, - lineStart: d3_noop, - lineEnd: d3_noop, - polygonStart: function() { - d3_geo_areaRingU = 1, d3_geo_areaRingV = 0; - d3_geo_area.lineStart = d3_geo_areaRingStart; - }, - polygonEnd: function() { - var area = 2 * Math.atan2(d3_geo_areaRingV, d3_geo_areaRingU); - d3_geo_areaSum += area < 0 ? 4 * π + area : area; - d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; - } + + result: d3_noop }; - function d3_geo_areaRingStart() { - var λ00, φ00, λ0, cosφ0, sinφ0; - d3_geo_area.point = function(λ, φ) { - d3_geo_area.point = nextPoint; - λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), - sinφ0 = Math.sin(φ); - }; - function nextPoint(λ, φ) { - λ *= d3_radians; - φ = φ * d3_radians / 2 + π / 4; - var dλ = λ - λ0, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u0 = d3_geo_areaRingU, v0 = d3_geo_areaRingV, u = cosφ0 * cosφ + k * Math.cos(dλ), v = k * Math.sin(dλ); - d3_geo_areaRingU = u0 * u - v0 * v; - d3_geo_areaRingV = v0 * u + u0 * v; - λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; - } - d3_geo_area.lineEnd = function() { - nextPoint(λ00, φ00); - }; + + function point(x, y) { + context.moveTo(x, y); + context.arc(x, y, pointRadius, 0, 2 * π); } - d3.geo.length = function(object) { - d3_geo_lengthSum = 0; - d3.geo.stream(object, d3_geo_length); - return d3_geo_lengthSum; + + function pointLineStart(x, y) { + context.moveTo(x, y); + stream.point = pointLine; + } + + function pointLine(x, y) { + context.lineTo(x, y); + } + + function lineEnd() { + stream.point = point; + } + + function lineEndPolygon() { + context.closePath(); + } + + return stream; +} + +d3.geo.path = function() { + var pointRadius = 4.5, + projection, + context, + projectStream, + contextStream; + + function path(object) { + if (object) d3.geo.stream(object, projectStream( + contextStream.pointRadius(typeof pointRadius === "function" + ? +pointRadius.apply(this, arguments) + : pointRadius))); + return contextStream.result(); + } + + path.area = function(object) { + d3_geo_pathAreaSum = 0; + d3.geo.stream(object, projectStream(d3_geo_pathArea)); + return d3_geo_pathAreaSum; }; - var d3_geo_lengthSum; - var d3_geo_length = { - sphere: d3_noop, - point: d3_noop, - lineStart: d3_geo_lengthLineStart, - lineEnd: d3_noop, - polygonStart: d3_noop, - polygonEnd: d3_noop + + path.centroid = function(object) { + d3_geo_centroidDimension = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0; + d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); + return d3_geo_centroidZ ? [d3_geo_centroidX / d3_geo_centroidZ, d3_geo_centroidY / d3_geo_centroidZ] : undefined; }; - function d3_geo_lengthLineStart() { - var λ0, sinφ0, cosφ0; - d3_geo_length.point = function(λ, φ) { - λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); - d3_geo_length.point = nextPoint; - }; - d3_geo_length.lineEnd = function() { - d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; - }; - function nextPoint(λ, φ) { - var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = Math.abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); - 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Δλ); - λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; - } - } - d3.geo.projection = d3_geo_projection; - d3.geo.projectionMutator = d3_geo_projectionMutator; - function d3_geo_projection(project) { - return d3_geo_projectionMutator(function() { - return project; - })(); - } - function d3_geo_projectionMutator(projectAt) { - var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { - x = project(x, y); - return [ x[0] * k + δx, δy - x[1] * k ]; - }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null; - function projection(point) { - point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); - return [ point[0] * k + δx, δy - point[1] * k ]; - } - function invert(point) { - point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); - return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; - } - projection.stream = function(stream) { - return d3_geo_projectionRadiansRotate(rotate, preclip(projectResample(postclip(stream)))); - }; - projection.clipAngle = function(_) { - if (!arguments.length) return clipAngle; - preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle(clipAngle = +_); - return projection; - }; - projection.clipExtent = function(_) { - if (!arguments.length) return clipExtent; - clipExtent = _; - postclip = _ == null ? d3_identity : d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]); - return projection; - }; - projection.scale = function(_) { - if (!arguments.length) return k; - k = +_; - return reset(); - }; - projection.translate = function(_) { - if (!arguments.length) return [ x, y ]; - x = +_[0]; - y = +_[1]; - return reset(); - }; - projection.center = function(_) { - if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; - λ = _[0] % 360 * d3_radians; - φ = _[1] % 360 * d3_radians; - return reset(); - }; - projection.rotate = function(_) { - if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; - δλ = _[0] % 360 * d3_radians; - δφ = _[1] % 360 * d3_radians; - δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; - return reset(); - }; - d3.rebind(projection, projectResample, "precision"); - function reset() { - projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); - var center = project(λ, φ); - δx = x - center[0] * k; - δy = y + center[1] * k; - return projection; - } - return function() { - project = projectAt.apply(this, arguments); - projection.invert = project.invert && invert; - return reset(); - }; - } - function d3_geo_projectionRadiansRotate(rotate, stream) { + + path.bounds = function(object) { + return d3_geo_bounds(projectStream)(object); + }; + + path.projection = function(_) { + if (!arguments.length) return projection; + projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; + return path; + }; + + path.context = function(_) { + if (!arguments.length) return context; + contextStream = (context = _) == null ? new d3_geo_pathBuffer : new d3_geo_pathContext(_); + return path; + }; + + path.pointRadius = function(_) { + if (!arguments.length) return pointRadius; + pointRadius = typeof _ === "function" ? _ : +_; + return path; + }; + + return path.projection(d3.geo.albersUsa()).context(null); +}; + +function d3_geo_pathCircle(radius) { + return "m0," + radius + + "a" + radius + "," + radius + " 0 1,1 0," + (-2 * radius) + + "a" + radius + "," + radius + " 0 1,1 0," + (+2 * radius) + + "z"; +} + +function d3_geo_pathProjectStream(project) { + var resample = d3_geo_resample(function(λ, φ) { return project([λ * d3_degrees, φ * d3_degrees]); }); + return function(stream) { + stream = resample(stream); return { - point: function(x, y) { - y = rotate(x * d3_radians, y * d3_radians), x = y[0]; - stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]); - }, - sphere: function() { - stream.sphere(); - }, - lineStart: function() { - stream.lineStart(); - }, - lineEnd: function() { - stream.lineEnd(); - }, - polygonStart: function() { - stream.polygonStart(); - }, - polygonEnd: function() { - stream.polygonEnd(); - } - }; - } - d3.geo.rotation = function(rotate) { - rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); - return function(coordinates) { - coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); - return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + point: function(λ, φ) { stream.point(λ * d3_radians, φ * d3_radians); }, + sphere: function() { stream.sphere(); }, + lineStart: function() { stream.lineStart(); }, + lineEnd: function() { stream.lineEnd(); }, + polygonStart: function() { stream.polygonStart(); }, + polygonEnd: function() { stream.polygonEnd(); } }; }; - function d3_geo_rotation(δλ, δφ, δγ) { - return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular; - } - function d3_geo_forwardRotationλ(δλ) { - return function(λ, φ) { - return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ]; - }; - } - function d3_geo_rotationλ(δλ) { - var rotation = d3_geo_forwardRotationλ(δλ); - rotation.invert = d3_geo_forwardRotationλ(-δλ); - return rotation; - } - function d3_geo_rotationφγ(δφ, δγ) { - var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); - function rotation(λ, φ) { - var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; - return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), Math.asin(Math.max(-1, Math.min(1, k * cosδγ + y * sinδγ))) ]; +} +d3.geom = {}; + +d3.geom.polygon = function(coordinates) { + + coordinates.area = function() { + var i = 0, + n = coordinates.length, + area = coordinates[n - 1][1] * coordinates[0][0] - coordinates[n - 1][0] * coordinates[0][1]; + while (++i < n) { + area += coordinates[i - 1][1] * coordinates[i][0] - coordinates[i - 1][0] * coordinates[i][1]; } - rotation.invert = function(λ, φ) { - var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; - return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), Math.asin(Math.max(-1, Math.min(1, k * cosδφ - x * sinδφ))) ]; - }; - return rotation; - } - var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { - return 1 / (1 + cosλcosφ); - }, function(ρ) { - return 2 * Math.atan(ρ); - }); - (d3.geo.stereographic = function() { - return d3_geo_projection(d3_geo_stereographic); - }).raw = d3_geo_stereographic; - function d3_geo_azimuthal(scale, angle) { - function azimuthal(λ, φ) { - var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); - return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; - } - azimuthal.invert = function(x, y) { - var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); - return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; - }; - return azimuthal; - } - d3.geom = {}; - d3.geom.hull = function(vertices) { - if (vertices.length < 3) return []; - var len = vertices.length, plen = len - 1, points = [], stack = [], i, j, h = 0, x1, y1, x2, y2, u, v, a, sp; - for (i = 1; i < len; ++i) { - if (vertices[i][1] < vertices[h][1]) { - h = i; - } else if (vertices[i][1] == vertices[h][1]) { - h = vertices[i][0] < vertices[h][0] ? i : h; - } - } - for (i = 0; i < len; ++i) { - if (i === h) continue; - y1 = vertices[i][1] - vertices[h][1]; - x1 = vertices[i][0] - vertices[h][0]; - points.push({ - angle: Math.atan2(y1, x1), - index: i - }); - } - points.sort(function(a, b) { - return a.angle - b.angle; - }); - a = points[0].angle; - v = points[0].index; - u = 0; - for (i = 1; i < plen; ++i) { - j = points[i].index; - if (a == points[i].angle) { - x1 = vertices[v][0] - vertices[h][0]; - y1 = vertices[v][1] - vertices[h][1]; - x2 = vertices[j][0] - vertices[h][0]; - y2 = vertices[j][1] - vertices[h][1]; - if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) { - points[i].index = -1; - } else { - points[u].index = -1; - a = points[i].angle; - u = i; - v = j; - } - } else { - a = points[i].angle; - u = i; - v = j; - } - } - stack.push(h); - for (i = 0, j = 0; i < 2; ++j) { - if (points[j].index !== -1) { - stack.push(points[j].index); - i++; - } - } - sp = stack.length; - for (;j < plen; ++j) { - if (points[j].index === -1) continue; - while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) { - --sp; - } - stack[sp++] = points[j].index; - } - var poly = []; - for (i = 0; i < sp; ++i) { - poly.push(vertices[stack[i]]); - } - return poly; + return area * .5; }; - function d3_geom_hullCCW(i1, i2, i3, v) { - var t, a, b, c, d, e, f; - t = v[i1]; - a = t[0]; - b = t[1]; - t = v[i2]; - c = t[0]; - d = t[1]; - t = v[i3]; - e = t[0]; - f = t[1]; - return (f - b) * (c - a) - (d - b) * (e - a) > 0; - } - d3.geom.polygon = function(coordinates) { - coordinates.area = function() { - var i = 0, n = coordinates.length, area = coordinates[n - 1][1] * coordinates[0][0] - coordinates[n - 1][0] * coordinates[0][1]; - while (++i < n) { - area += coordinates[i - 1][1] * coordinates[i][0] - coordinates[i - 1][0] * coordinates[i][1]; - } - return area * .5; - }; - coordinates.centroid = function(k) { - var i = -1, n = coordinates.length, x = 0, y = 0, a, b = coordinates[n - 1], c; - if (!arguments.length) k = -1 / (6 * coordinates.area()); - while (++i < n) { - a = b; - b = coordinates[i]; - c = a[0] * b[1] - b[0] * a[1]; - x += (a[0] + b[0]) * c; - y += (a[1] + b[1]) * c; - } - return [ x * k, y * k ]; - }; - coordinates.clip = function(subject) { - var input, i = -1, n = coordinates.length, j, m, a = coordinates[n - 1], b, c, d; - while (++i < n) { - input = subject.slice(); - subject.length = 0; - b = coordinates[i]; - c = input[(m = input.length) - 1]; - j = -1; - while (++j < m) { - d = input[j]; - if (d3_geom_polygonInside(d, a, b)) { - if (!d3_geom_polygonInside(c, a, b)) { - subject.push(d3_geom_polygonIntersect(c, d, a, b)); - } - subject.push(d); - } else if (d3_geom_polygonInside(c, a, b)) { + + coordinates.centroid = function(k) { + var i = -1, + n = coordinates.length, + x = 0, + y = 0, + a, + b = coordinates[n - 1], + c; + if (!arguments.length) k = -1 / (6 * coordinates.area()); + while (++i < n) { + a = b; + b = coordinates[i]; + c = a[0] * b[1] - b[0] * a[1]; + x += (a[0] + b[0]) * c; + y += (a[1] + b[1]) * c; + } + return [x * k, y * k]; + }; + + // The Sutherland-Hodgman clipping algorithm. + // Note: requires the clip polygon to be counterclockwise and convex. + coordinates.clip = function(subject) { + var input, + i = -1, + n = coordinates.length, + j, + m, + a = coordinates[n - 1], + b, + c, + d; + while (++i < n) { + input = subject.slice(); + subject.length = 0; + b = coordinates[i]; + c = input[(m = input.length) - 1]; + j = -1; + while (++j < m) { + d = input[j]; + if (d3_geom_polygonInside(d, a, b)) { + if (!d3_geom_polygonInside(c, a, b)) { subject.push(d3_geom_polygonIntersect(c, d, a, b)); } - c = d; + subject.push(d); + } else if (d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); } - a = b; + c = d; } - return subject; - }; - return coordinates; + a = b; + } + return subject; }; - function d3_geom_polygonInside(p, a, b) { - return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); - } - function d3_geom_polygonIntersect(c, d, a, b) { - var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); - return [ x1 + ua * x21, y1 + ua * y21 ]; - } - d3.geom.voronoi = function(vertices) { - var polygons = vertices.map(function() { - return []; - }), Z = 1e6; - d3_voronoi_tessellate(vertices, function(e) { - var s1, s2, x1, x2, y1, y2; - if (e.a === 1 && e.b >= 0) { - s1 = e.ep.r; - s2 = e.ep.l; + + return coordinates; +}; + +function d3_geom_polygonInside(p, a, b) { + return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); +} + +// Intersect two infinite lines cd and ab. +function d3_geom_polygonIntersect(c, d, a, b) { + var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, + y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, + ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); + return [x1 + ua * x21, y1 + ua * y21]; +} + +var d3_ease_default = function() { return d3_identity; }; + +var d3_ease = d3.map({ + linear: d3_ease_default, + poly: d3_ease_poly, + quad: function() { return d3_ease_quad; }, + cubic: function() { return d3_ease_cubic; }, + sin: function() { return d3_ease_sin; }, + exp: function() { return d3_ease_exp; }, + circle: function() { return d3_ease_circle; }, + elastic: d3_ease_elastic, + back: d3_ease_back, + bounce: function() { return d3_ease_bounce; } +}); + +var d3_ease_mode = d3.map({ + "in": d3_identity, + "out": d3_ease_reverse, + "in-out": d3_ease_reflect, + "out-in": function(f) { return d3_ease_reflect(d3_ease_reverse(f)); } +}); + +d3.ease = function(name) { + var i = name.indexOf("-"), + t = i >= 0 ? name.substring(0, i) : name, + m = i >= 0 ? name.substring(i + 1) : "in"; + t = d3_ease.get(t) || d3_ease_default; + m = d3_ease_mode.get(m) || d3_identity; + return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); +}; + +function d3_ease_clamp(f) { + return function(t) { + return t <= 0 ? 0 : t >= 1 ? 1 : f(t); + }; +} + +function d3_ease_reverse(f) { + return function(t) { + return 1 - f(1 - t); + }; +} + +function d3_ease_reflect(f) { + return function(t) { + return .5 * (t < .5 ? f(2 * t) : (2 - f(2 - 2 * t))); + }; +} + +function d3_ease_quad(t) { + return t * t; +} + +function d3_ease_cubic(t) { + return t * t * t; +} + +// Optimized clamp(reflect(poly(3))). +function d3_ease_cubicInOut(t) { + if (t <= 0) return 0; + if (t >= 1) return 1; + var t2 = t * t, t3 = t2 * t; + return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); +} + +function d3_ease_poly(e) { + return function(t) { + return Math.pow(t, e); + }; +} + +function d3_ease_sin(t) { + return 1 - Math.cos(t * π / 2); +} + +function d3_ease_exp(t) { + return Math.pow(2, 10 * (t - 1)); +} + +function d3_ease_circle(t) { + return 1 - Math.sqrt(1 - t * t); +} + +function d3_ease_elastic(a, p) { + var s; + if (arguments.length < 2) p = 0.45; + if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); + else a = 1, s = p / 4; + return function(t) { + return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p); + }; +} + +function d3_ease_back(s) { + if (!s) s = 1.70158; + return function(t) { + return t * t * ((s + 1) * t - s); + }; +} + +function d3_ease_bounce(t) { + return t < 1 / 2.75 ? 7.5625 * t * t + : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 + : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 + : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; +} + +function d3_transition(groups, id) { + d3_arraySubclass(groups, d3_transitionPrototype); + + groups.id = id; // Note: read-only! + + return groups; +} + +var d3_transitionPrototype = [], + d3_transitionId = 0, + d3_transitionInheritId, + d3_transitionInherit = {ease: d3_ease_cubicInOut, delay: 0, duration: 250}; + +d3_transitionPrototype.call = d3_selectionPrototype.call; +d3_transitionPrototype.empty = d3_selectionPrototype.empty; +d3_transitionPrototype.node = d3_selectionPrototype.node; + +d3.transition = function(selection) { + return arguments.length + ? (d3_transitionInheritId ? selection.transition() : selection) + : d3_selectionRoot.transition(); +}; + +d3.transition.prototype = d3_transitionPrototype; + + +d3_transitionPrototype.select = function(selector) { + var id = this.id, + subgroups = [], + subgroup, + subnode, + node; + + if (typeof selector !== "function") selector = d3_selection_selector(selector); + + for (var j = -1, m = this.length; ++j < m;) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n;) { + if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + d3_transitionNode(subnode, i, id, node.__transition__[id]); + subgroup.push(subnode); } else { - s1 = e.ep.l; - s2 = e.ep.r; + subgroup.push(null); } - if (e.a === 1) { - y1 = s1 ? s1.y : -Z; - x1 = e.c - e.b * y1; - y2 = s2 ? s2.y : Z; - x2 = e.c - e.b * y2; - } else { - x1 = s1 ? s1.x : -Z; - y1 = e.c - e.a * x1; - x2 = s2 ? s2.x : Z; - y2 = e.c - e.a * x2; - } - var v1 = [ x1, y1 ], v2 = [ x2, y2 ]; - polygons[e.region.l.index].push(v1, v2); - polygons[e.region.r.index].push(v1, v2); - }); - polygons = polygons.map(function(polygon, i) { - var cx = vertices[i][0], cy = vertices[i][1], angle = polygon.map(function(v) { - return Math.atan2(v[0] - cx, v[1] - cy); - }), order = d3.range(polygon.length).sort(function(a, b) { - return angle[a] - angle[b]; - }); - return order.filter(function(d, i) { - return !i || angle[d] - angle[order[i - 1]] > ε; - }).map(function(d) { - return polygon[d]; - }); - }); - polygons.forEach(function(polygon, i) { - var n = polygon.length; - if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]); - if (n > 2) return; - var p0 = vertices[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1; - if (Math.abs(dy) < ε) { - var y = y0 < y1 ? -Z : Z; - polygon.push([ -Z, y ], [ Z, y ]); - } else if (dx < ε) { - var x = x0 < x1 ? -Z : Z; - polygon.push([ x, -Z ], [ x, Z ]); - } else { - var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx; - if (Math.abs(z) < ε) { - polygon.push([ dy < 0 ? y : -y, y ]); - } else { - if (z > 0) y *= -1; - polygon.push([ -Z, y ], [ Z, y ]); + } + } + + return d3_transition(subgroups, id); +}; + +d3_transitionPrototype.selectAll = function(selector) { + var id = this.id, + subgroups = [], + subgroup, + subnodes, + node, + subnode, + transition; + + if (typeof selector !== "function") selector = d3_selection_selectorAll(selector); + + for (var j = -1, m = this.length; ++j < m;) { + for (var group = this[j], i = -1, n = group.length; ++i < n;) { + if (node = group[i]) { + transition = node.__transition__[id]; + subnodes = selector.call(node, node.__data__, i); + subgroups.push(subgroup = []); + for (var k = -1, o = subnodes.length; ++k < o;) { + d3_transitionNode(subnode = subnodes[k], k, id, transition); + subgroup.push(subnode); } } - }); - return polygons; - }; - var d3_voronoi_opposite = { - l: "r", - r: "l" - }; - function d3_voronoi_tessellate(vertices, callback) { - var Sites = { - list: vertices.map(function(v, i) { - return { - index: i, - x: v[0], - y: v[1] - }; - }).sort(function(a, b) { - return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0; - }), - bottomSite: null - }; - var EdgeList = { - list: [], - leftEnd: null, - rightEnd: null, - init: function() { - EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l"); - EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l"); - EdgeList.leftEnd.r = EdgeList.rightEnd; - EdgeList.rightEnd.l = EdgeList.leftEnd; - EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd); - }, - createHalfEdge: function(edge, side) { - return { - edge: edge, - side: side, - vertex: null, - l: null, - r: null - }; - }, - insert: function(lb, he) { - he.l = lb; - he.r = lb.r; - lb.r.l = he; - lb.r = he; - }, - leftBound: function(p) { - var he = EdgeList.leftEnd; - do { - he = he.r; - } while (he != EdgeList.rightEnd && Geom.rightOf(he, p)); - he = he.l; - return he; - }, - del: function(he) { - he.l.r = he.r; - he.r.l = he.l; - he.edge = null; - }, - right: function(he) { - return he.r; - }, - left: function(he) { - return he.l; - }, - leftRegion: function(he) { - return he.edge == null ? Sites.bottomSite : he.edge.region[he.side]; - }, - rightRegion: function(he) { - return he.edge == null ? Sites.bottomSite : he.edge.region[d3_voronoi_opposite[he.side]]; + } + } + + return d3_transition(subgroups, id); +}; + +d3_transitionPrototype.filter = function(filter) { + var subgroups = [], + subgroup, + group, + node; + + if (typeof filter !== "function") filter = d3_selection_filter(filter); + + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); } + } + } + + return d3_transition(subgroups, this.id, this.time).ease(this.ease()); +}; +function d3_Color() {} + +d3_Color.prototype.toString = function() { + return this.rgb() + ""; +}; + +d3.hsl = function(h, s, l) { + return arguments.length === 1 + ? (h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) + : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl)) + : d3_hsl(+h, +s, +l); +}; + +function d3_hsl(h, s, l) { + return new d3_Hsl(h, s, l); +} + +function d3_Hsl(h, s, l) { + this.h = h; + this.s = s; + this.l = l; +} + +var d3_hslPrototype = d3_Hsl.prototype = new d3_Color; + +d3_hslPrototype.brighter = function(k) { + k = Math.pow(0.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, this.l / k); +}; + +d3_hslPrototype.darker = function(k) { + k = Math.pow(0.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, k * this.l); +}; + +d3_hslPrototype.rgb = function() { + return d3_hsl_rgb(this.h, this.s, this.l); +}; + +function d3_hsl_rgb(h, s, l) { + var m1, + m2; + + /* Some simple corrections for h, s and l. */ + h = h % 360; if (h < 0) h += 360; + s = s < 0 ? 0 : s > 1 ? 1 : s; + l = l < 0 ? 0 : l > 1 ? 1 : l; + + /* From FvD 13.37, CSS Color Module Level 3 */ + m2 = l <= .5 ? l * (1 + s) : l + s - l * s; + m1 = 2 * l - m2; + + function v(h) { + if (h > 360) h -= 360; + else if (h < 0) h += 360; + if (h < 60) return m1 + (m2 - m1) * h / 60; + if (h < 180) return m2; + if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; + return m1; + } + + function vv(h) { + return Math.round(v(h) * 255); + } + + return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); +} + +d3.hcl = function(h, c, l) { + return arguments.length === 1 + ? (h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) + : (h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) + : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b))) + : d3_hcl(+h, +c, +l); +}; + +function d3_hcl(h, c, l) { + return new d3_Hcl(h, c, l); +} + +function d3_Hcl(h, c, l) { + this.h = h; + this.c = c; + this.l = l; +} + +var d3_hclPrototype = d3_Hcl.prototype = new d3_Color; + +d3_hclPrototype.brighter = function(k) { + return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); +}; + +d3_hclPrototype.darker = function(k) { + return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); +}; + +d3_hclPrototype.rgb = function() { + return d3_hcl_lab(this.h, this.c, this.l).rgb(); +}; + +function d3_hcl_lab(h, c, l) { + return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); +} + +d3.lab = function(l, a, b) { + return arguments.length === 1 + ? (l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) + : (l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) + : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b))) + : d3_lab(+l, +a, +b); +}; + +function d3_lab(l, a, b) { + return new d3_Lab(l, a, b); +} + +function d3_Lab(l, a, b) { + this.l = l; + this.a = a; + this.b = b; +} + +// Corresponds roughly to RGB brighter/darker +var d3_lab_K = 18; + +// D65 standard referent +var d3_lab_X = 0.950470, + d3_lab_Y = 1, + d3_lab_Z = 1.088830; + +var d3_labPrototype = d3_Lab.prototype = new d3_Color; + +d3_labPrototype.brighter = function(k) { + return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); +}; + +d3_labPrototype.darker = function(k) { + return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); +}; + +d3_labPrototype.rgb = function() { + return d3_lab_rgb(this.l, this.a, this.b); +}; + +function d3_lab_rgb(l, a, b) { + var y = (l + 16) / 116, + x = y + a / 500, + z = y - b / 200; + x = d3_lab_xyz(x) * d3_lab_X; + y = d3_lab_xyz(y) * d3_lab_Y; + z = d3_lab_xyz(z) * d3_lab_Z; + return d3_rgb( + d3_xyz_rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), + d3_xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z), + d3_xyz_rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z) + ); +} + +function d3_lab_hcl(l, a, b) { + return d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l); +} + +function d3_lab_xyz(x) { + return x > 0.206893034 ? x * x * x : (x - 4 / 29) / 7.787037; +} +function d3_xyz_lab(x) { + return x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; +} + +function d3_xyz_rgb(r) { + return Math.round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - 0.055)); +} + +d3.rgb = function(r, g, b) { + return arguments.length === 1 + ? (r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) + : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb)) + : d3_rgb(~~r, ~~g, ~~b); +}; + +function d3_rgb(r, g, b) { + return new d3_Rgb(r, g, b); +} + +function d3_Rgb(r, g, b) { + this.r = r; + this.g = g; + this.b = b; +} + +var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color; + +d3_rgbPrototype.brighter = function(k) { + k = Math.pow(0.7, arguments.length ? k : 1); + var r = this.r, + g = this.g, + b = this.b, + i = 30; + if (!r && !g && !b) return d3_rgb(i, i, i); + if (r && r < i) r = i; + if (g && g < i) g = i; + if (b && b < i) b = i; + return d3_rgb( + Math.min(255, Math.floor(r / k)), + Math.min(255, Math.floor(g / k)), + Math.min(255, Math.floor(b / k))); +}; + +d3_rgbPrototype.darker = function(k) { + k = Math.pow(0.7, arguments.length ? k : 1); + return d3_rgb( + Math.floor(k * this.r), + Math.floor(k * this.g), + Math.floor(k * this.b)); +}; + +d3_rgbPrototype.hsl = function() { + return d3_rgb_hsl(this.r, this.g, this.b); +}; + +d3_rgbPrototype.toString = function() { + return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); +}; + +function d3_rgb_hex(v) { + return v < 0x10 + ? "0" + Math.max(0, v).toString(16) + : Math.min(255, v).toString(16); +} + +function d3_rgb_parse(format, rgb, hsl) { + var r = 0, // red channel; int in [0, 255] + g = 0, // green channel; int in [0, 255] + b = 0, // blue channel; int in [0, 255] + m1, // CSS color specification match + m2, // CSS color specification type (e.g., rgb) + name; + + /* Handle hsl, rgb. */ + m1 = /([a-z]+)\((.*)\)/i.exec(format); + if (m1) { + m2 = m1[2].split(","); + switch (m1[1]) { + case "hsl": { + return hsl( + parseFloat(m2[0]), // degrees + parseFloat(m2[1]) / 100, // percentage + parseFloat(m2[2]) / 100 // percentage + ); + } + case "rgb": { + return rgb( + d3_rgb_parseNumber(m2[0]), + d3_rgb_parseNumber(m2[1]), + d3_rgb_parseNumber(m2[2]) + ); + } + } + } + + /* Named colors. */ + if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); + + /* Hexadecimal colors: #rgb and #rrggbb. */ + if (format != null && format.charAt(0) === "#") { + if (format.length === 4) { + r = format.charAt(1); r += r; + g = format.charAt(2); g += g; + b = format.charAt(3); b += b; + } else if (format.length === 7) { + r = format.substring(1, 3); + g = format.substring(3, 5); + b = format.substring(5, 7); + } + r = parseInt(r, 16); + g = parseInt(g, 16); + b = parseInt(b, 16); + } + + return rgb(r, g, b); +} + +function d3_rgb_hsl(r, g, b) { + var min = Math.min(r /= 255, g /= 255, b /= 255), + max = Math.max(r, g, b), + d = max - min, + h, + s, + l = (max + min) / 2; + if (d) { + s = l < .5 ? d / (max + min) : d / (2 - max - min); + if (r == max) h = (g - b) / d + (g < b ? 6 : 0); + else if (g == max) h = (b - r) / d + 2; + else h = (r - g) / d + 4; + h *= 60; + } else { + s = h = 0; + } + return d3_hsl(h, s, l); +} + +function d3_rgb_lab(r, g, b) { + r = d3_rgb_xyz(r); + g = d3_rgb_xyz(g); + b = d3_rgb_xyz(b); + var x = d3_xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / d3_lab_X), + y = d3_xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / d3_lab_Y), + z = d3_xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / d3_lab_Z); + return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); +} + +function d3_rgb_xyz(r) { + return (r /= 255) <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4); +} + +function d3_rgb_parseNumber(c) { // either integer or percentage + var f = parseFloat(c); + return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; +} + +var d3_rgb_names = d3.map({ + aliceblue: "#f0f8ff", + antiquewhite: "#faebd7", + aqua: "#00ffff", + aquamarine: "#7fffd4", + azure: "#f0ffff", + beige: "#f5f5dc", + bisque: "#ffe4c4", + black: "#000000", + blanchedalmond: "#ffebcd", + blue: "#0000ff", + blueviolet: "#8a2be2", + brown: "#a52a2a", + burlywood: "#deb887", + cadetblue: "#5f9ea0", + chartreuse: "#7fff00", + chocolate: "#d2691e", + coral: "#ff7f50", + cornflowerblue: "#6495ed", + cornsilk: "#fff8dc", + crimson: "#dc143c", + cyan: "#00ffff", + darkblue: "#00008b", + darkcyan: "#008b8b", + darkgoldenrod: "#b8860b", + darkgray: "#a9a9a9", + darkgreen: "#006400", + darkgrey: "#a9a9a9", + darkkhaki: "#bdb76b", + darkmagenta: "#8b008b", + darkolivegreen: "#556b2f", + darkorange: "#ff8c00", + darkorchid: "#9932cc", + darkred: "#8b0000", + darksalmon: "#e9967a", + darkseagreen: "#8fbc8f", + darkslateblue: "#483d8b", + darkslategray: "#2f4f4f", + darkslategrey: "#2f4f4f", + darkturquoise: "#00ced1", + darkviolet: "#9400d3", + deeppink: "#ff1493", + deepskyblue: "#00bfff", + dimgray: "#696969", + dimgrey: "#696969", + dodgerblue: "#1e90ff", + firebrick: "#b22222", + floralwhite: "#fffaf0", + forestgreen: "#228b22", + fuchsia: "#ff00ff", + gainsboro: "#dcdcdc", + ghostwhite: "#f8f8ff", + gold: "#ffd700", + goldenrod: "#daa520", + gray: "#808080", + green: "#008000", + greenyellow: "#adff2f", + grey: "#808080", + honeydew: "#f0fff0", + hotpink: "#ff69b4", + indianred: "#cd5c5c", + indigo: "#4b0082", + ivory: "#fffff0", + khaki: "#f0e68c", + lavender: "#e6e6fa", + lavenderblush: "#fff0f5", + lawngreen: "#7cfc00", + lemonchiffon: "#fffacd", + lightblue: "#add8e6", + lightcoral: "#f08080", + lightcyan: "#e0ffff", + lightgoldenrodyellow: "#fafad2", + lightgray: "#d3d3d3", + lightgreen: "#90ee90", + lightgrey: "#d3d3d3", + lightpink: "#ffb6c1", + lightsalmon: "#ffa07a", + lightseagreen: "#20b2aa", + lightskyblue: "#87cefa", + lightslategray: "#778899", + lightslategrey: "#778899", + lightsteelblue: "#b0c4de", + lightyellow: "#ffffe0", + lime: "#00ff00", + limegreen: "#32cd32", + linen: "#faf0e6", + magenta: "#ff00ff", + maroon: "#800000", + mediumaquamarine: "#66cdaa", + mediumblue: "#0000cd", + mediumorchid: "#ba55d3", + mediumpurple: "#9370db", + mediumseagreen: "#3cb371", + mediumslateblue: "#7b68ee", + mediumspringgreen: "#00fa9a", + mediumturquoise: "#48d1cc", + mediumvioletred: "#c71585", + midnightblue: "#191970", + mintcream: "#f5fffa", + mistyrose: "#ffe4e1", + moccasin: "#ffe4b5", + navajowhite: "#ffdead", + navy: "#000080", + oldlace: "#fdf5e6", + olive: "#808000", + olivedrab: "#6b8e23", + orange: "#ffa500", + orangered: "#ff4500", + orchid: "#da70d6", + palegoldenrod: "#eee8aa", + palegreen: "#98fb98", + paleturquoise: "#afeeee", + palevioletred: "#db7093", + papayawhip: "#ffefd5", + peachpuff: "#ffdab9", + peru: "#cd853f", + pink: "#ffc0cb", + plum: "#dda0dd", + powderblue: "#b0e0e6", + purple: "#800080", + red: "#ff0000", + rosybrown: "#bc8f8f", + royalblue: "#4169e1", + saddlebrown: "#8b4513", + salmon: "#fa8072", + sandybrown: "#f4a460", + seagreen: "#2e8b57", + seashell: "#fff5ee", + sienna: "#a0522d", + silver: "#c0c0c0", + skyblue: "#87ceeb", + slateblue: "#6a5acd", + slategray: "#708090", + slategrey: "#708090", + snow: "#fffafa", + springgreen: "#00ff7f", + steelblue: "#4682b4", + tan: "#d2b48c", + teal: "#008080", + thistle: "#d8bfd8", + tomato: "#ff6347", + turquoise: "#40e0d0", + violet: "#ee82ee", + wheat: "#f5deb3", + white: "#ffffff", + whitesmoke: "#f5f5f5", + yellow: "#ffff00", + yellowgreen: "#9acd32" +}); + +d3_rgb_names.forEach(function(key, value) { + d3_rgb_names.set(key, d3_rgb_parse(value, d3_rgb, d3_hsl_rgb)); +}); + +d3.interpolateRgb = d3_interpolateRgb; + +function d3_interpolateRgb(a, b) { + a = d3.rgb(a); + b = d3.rgb(b); + var ar = a.r, + ag = a.g, + ab = a.b, + br = b.r - ar, + bg = b.g - ag, + bb = b.b - ab; + return function(t) { + return "#" + + d3_rgb_hex(Math.round(ar + br * t)) + + d3_rgb_hex(Math.round(ag + bg * t)) + + d3_rgb_hex(Math.round(ab + bb * t)); + }; +} + +d3.transform = function(string) { + var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); + return (d3.transform = function(string) { + g.setAttribute("transform", string); + var t = g.transform.baseVal.consolidate(); + return new d3_transform(t ? t.matrix : d3_transformIdentity); + })(string); +}; + +// Compute x-scale and normalize the first row. +// Compute shear and make second row orthogonal to first. +// Compute y-scale and normalize the second row. +// Finally, compute the rotation. +function d3_transform(m) { + var r0 = [m.a, m.b], + r1 = [m.c, m.d], + kx = d3_transformNormalize(r0), + kz = d3_transformDot(r0, r1), + ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; + if (r0[0] * r1[1] < r1[0] * r0[1]) { + r0[0] *= -1; + r0[1] *= -1; + kx *= -1; + kz *= -1; + } + this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; + this.translate = [m.e, m.f]; + this.scale = [kx, ky]; + this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; +}; + +d3_transform.prototype.toString = function() { + return "translate(" + this.translate + + ")rotate(" + this.rotate + + ")skewX(" + this.skew + + ")scale(" + this.scale + + ")"; +}; + +function d3_transformDot(a, b) { + return a[0] * b[0] + a[1] * b[1]; +} + +function d3_transformNormalize(a) { + var k = Math.sqrt(d3_transformDot(a, a)); + if (k) { + a[0] /= k; + a[1] /= k; + } + return k; +} + +function d3_transformCombine(a, b, k) { + a[0] += k * b[0]; + a[1] += k * b[1]; + return a; +} + +var d3_transformIdentity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0}; +d3.interpolateNumber = d3_interpolateNumber; + +function d3_interpolateNumber(a, b) { + b -= a; + return function(t) { return a + b * t; }; +} + +d3.interpolateTransform = d3_interpolateTransform; + +function d3_interpolateTransform(a, b) { + var s = [], // string constants and placeholders + q = [], // number interpolators + n, + A = d3.transform(a), + B = d3.transform(b), + ta = A.translate, + tb = B.translate, + ra = A.rotate, + rb = B.rotate, + wa = A.skew, + wb = B.skew, + ka = A.scale, + kb = B.scale; + + if (ta[0] != tb[0] || ta[1] != tb[1]) { + s.push("translate(", null, ",", null, ")"); + q.push({i: 1, x: d3_interpolateNumber(ta[0], tb[0])}, {i: 3, x: d3_interpolateNumber(ta[1], tb[1])}); + } else if (tb[0] || tb[1]) { + s.push("translate(" + tb + ")"); + } else { + s.push(""); + } + + if (ra != rb) { + if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; // shortest path + q.push({i: s.push(s.pop() + "rotate(", null, ")") - 2, x: d3_interpolateNumber(ra, rb)}); + } else if (rb) { + s.push(s.pop() + "rotate(" + rb + ")"); + } + + if (wa != wb) { + q.push({i: s.push(s.pop() + "skewX(", null, ")") - 2, x: d3_interpolateNumber(wa, wb)}); + } else if (wb) { + s.push(s.pop() + "skewX(" + wb + ")"); + } + + if (ka[0] != kb[0] || ka[1] != kb[1]) { + n = s.push(s.pop() + "scale(", null, ",", null, ")"); + q.push({i: n - 4, x: d3_interpolateNumber(ka[0], kb[0])}, {i: n - 2, x: d3_interpolateNumber(ka[1], kb[1])}); + } else if (kb[0] != 1 || kb[1] != 1) { + s.push(s.pop() + "scale(" + kb + ")"); + } + + n = q.length; + return function(t) { + var i = -1, o; + while (++i < n) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; +} + +d3.interpolateObject = d3_interpolateObject; + +function d3_interpolateObject(a, b) { + var i = {}, + c = {}, + k; + for (k in a) { + if (k in b) { + i[k] = d3_interpolateByName(k)(a[k], b[k]); + } else { + c[k] = a[k]; + } + } + for (k in b) { + if (!(k in a)) { + c[k] = b[k]; + } + } + return function(t) { + for (k in i) c[k] = i[k](t); + return c; + }; +} + +d3.interpolateArray = d3_interpolateArray; + +function d3_interpolateArray(a, b) { + var x = [], + c = [], + na = a.length, + nb = b.length, + n0 = Math.min(a.length, b.length), + i; + for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); + for (; i < na; ++i) c[i] = a[i]; + for (; i < nb; ++i) c[i] = b[i]; + return function(t) { + for (i = 0; i < n0; ++i) c[i] = x[i](t); + return c; + }; +} + +d3.interpolateString = d3_interpolateString; + +function d3_interpolateString(a, b) { + var m, // current match + i, // current index + j, // current index (for coalescing) + s0 = 0, // start index of current string prefix + s1 = 0, // end index of current string prefix + s = [], // string constants and placeholders + q = [], // number interpolators + n, // q.length + o; + + // Reset our regular expression! + d3_interpolate_number.lastIndex = 0; + + // Find all numbers in b. + for (i = 0; m = d3_interpolate_number.exec(b); ++i) { + if (m.index) s.push(b.substring(s0, s1 = m.index)); + q.push({i: s.length, x: m[0]}); + s.push(null); + s0 = d3_interpolate_number.lastIndex; + } + if (s0 < b.length) s.push(b.substring(s0)); + + // Find all numbers in a. + for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { + o = q[i]; + if (o.x == m[0]) { // The numbers match, so coalesce. + if (o.i) { + if (s[o.i + 1] == null) { // This match is followed by another number. + s[o.i - 1] += o.x; + s.splice(o.i, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } else { // This match is followed by a string, so coalesce twice. + s[o.i - 1] += o.x + s[o.i + 1]; + s.splice(o.i, 2); + for (j = i + 1; j < n; ++j) q[j].i -= 2; + } + } else { + if (s[o.i + 1] == null) { // This match is followed by another number. + s[o.i] = o.x; + } else { // This match is followed by a string, so coalesce twice. + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } + } + q.splice(i, 1); + n--; + i--; + } else { + o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); + } + } + + // Remove any numbers in b not found in a. + while (i < n) { + o = q.pop(); + if (s[o.i + 1] == null) { // This match is followed by another number. + s[o.i] = o.x; + } else { // This match is followed by a string, so coalesce twice. + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + } + n--; + } + + // Special optimization for only a single match. + if (s.length === 1) { + return s[0] == null ? q[0].x : function() { return b; }; + } + + // Otherwise, interpolate each of the numbers and rejoin the string. + return function(t) { + for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; +} + +var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; + +d3.interpolate = d3_interpolate; + +function d3_interpolate(a, b) { + var i = d3.interpolators.length, f; + while (--i >= 0 && !(f = d3.interpolators[i](a, b))); + return f; +} + +function d3_interpolateByName(name) { + return name == "transform" + ? d3_interpolateTransform + : d3_interpolate; +} + +d3.interpolators = [ + d3_interpolateObject, + function(a, b) { return Array.isArray(b) && d3_interpolateArray(a, b); }, + function(a, b) { return (typeof a === "string" || typeof b === "string") && d3_interpolateString(a + "", b + ""); }, + function(a, b) { return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Color) && d3_interpolateRgb(a, b); }, + function(a, b) { return !isNaN(a = +a) && !isNaN(b = +b) && d3_interpolateNumber(a, b); } +]; + +d3_transitionPrototype.tween = function(name, tween) { + var id = this.id; + if (arguments.length < 2) return this.node().__transition__[id].tween.get(name); + return d3_selection_each(this, tween == null + ? function(node) { node.__transition__[id].tween.remove(name); } + : function(node) { node.__transition__[id].tween.set(name, tween); }); +}; + +function d3_transition_tween(groups, name, value, tween) { + var id = groups.id; + return d3_selection_each(groups, typeof value === "function" + ? function(node, i, j) { node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j))); } + : (value = tween(value), function(node) { node.__transition__[id].tween.set(name, value); })); +} + +d3_transitionPrototype.attr = function(nameNS, value) { + if (arguments.length < 2) { + + // For attr(object), the object specifies the names and values of the + // attributes to transition. The values may be functions that are + // evaluated for each element. + for (value in nameNS) this.attr(value, nameNS[value]); + return this; + } + + var interpolate = d3_interpolateByName(nameNS), + name = d3.ns.qualify(nameNS); + + // For attr(string, null), remove the attribute with the specified name. + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + + return d3_transition_tween(this, "attr." + nameNS, value, function(b) { + + // For attr(string, string), set the attribute with the specified name. + function attrString() { + var a = this.getAttribute(name), i; + return a !== b && (i = interpolate(a, b), function(t) { this.setAttribute(name, i(t)); }); + } + function attrStringNS() { + var a = this.getAttributeNS(name.space, name.local), i; + return a !== b && (i = interpolate(a, b), function(t) { this.setAttributeNS(name.space, name.local, i(t)); }); + } + + return b == null ? (name.local ? attrNullNS : attrNull) + : (b += "", name.local ? attrStringNS : attrString); + }); +}; + +d3_transitionPrototype.attrTween = function(nameNS, tween) { + var name = d3.ns.qualify(nameNS); + + function attrTween(d, i) { + var f = tween.call(this, d, i, this.getAttribute(name)); + return f && function(t) { this.setAttribute(name, f(t)); }; + } + + function attrTweenNS(d, i) { + var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); + return f && function(t) { this.setAttributeNS(name.space, name.local, f(t)); }; + } + + return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); +}; + +d3_transitionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + + // For style(object) or style(object, string), the object specifies the + // names and values of the attributes to set or remove. The values may be + // functions that are evaluated for each element. The optional string + // specifies the priority. + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.style(priority, name[priority], value); + return this; + } + + // For style(string, string) or style(string, function), use the default + // priority. The priority is ignored for style(string, null). + priority = ""; + } + + var interpolate = d3_interpolateByName(name); + + // For style(name, null) or style(name, null, priority), remove the style + // property with the specified name. The priority is ignored. + function styleNull() { + this.style.removeProperty(name); + } + + // Otherwise, a name, value and priority are specified, and handled as below. + return d3_transition_tween(this, "style." + name, value, function(b) { + + // For style(name, string) or style(name, string, priority), set the style + // property with the specified name, using the specified priority. + function styleString() { + var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i; + return a !== b && (i = interpolate(a, b), function(t) { this.style.setProperty(name, i(t), priority); }); + } + + return b == null ? styleNull + : (b += "", styleString); + }); +}; + +d3_transitionPrototype.styleTween = function(name, tween, priority) { + if (arguments.length < 3) priority = ""; + return this.tween("style." + name, function(d, i) { + var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name)); + return f && function(t) { this.style.setProperty(name, f(t), priority); }; + }); +}; + +d3_transitionPrototype.text = function(value) { + return d3_transition_tween(this, "text", value, d3_transition_text); +}; + +function d3_transition_text(b) { + if (b == null) b = ""; + return function() { this.textContent = b; }; +} + +d3_transitionPrototype.remove = function() { + return this.each("end.transition", function() { + var p; + if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); + }); +}; + +d3_transitionPrototype.ease = function(value) { + var id = this.id; + if (arguments.length < 1) return this.node().__transition__[id].ease; + if (typeof value !== "function") value = d3.ease.apply(d3, arguments); + return d3_selection_each(this, function(node) { node.__transition__[id].ease = value; }); +}; + +d3_transitionPrototype.delay = function(value) { + var id = this.id; + return d3_selection_each(this, typeof value === "function" + ? function(node, i, j) { node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0; } + : (value |= 0, function(node) { node.__transition__[id].delay = value; })); +}; + +d3_transitionPrototype.duration = function(value) { + var id = this.id; + return d3_selection_each(this, typeof value === "function" + ? function(node, i, j) { node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0); } + : (value = Math.max(1, value | 0), function(node) { node.__transition__[id].duration = value; })); +}; + +d3_transitionPrototype.each = function(type, listener) { + var id = this.id; + if (arguments.length < 2) { + var inherit = d3_transitionInherit, + inheritId = d3_transitionInheritId; + d3_transitionInheritId = id; + d3_selection_each(this, function(node, i, j) { + d3_transitionInherit = node.__transition__[id]; + type.call(node, node.__data__, i, j); + }); + d3_transitionInherit = inherit; + d3_transitionInheritId = inheritId; + } else { + d3_selection_each(this, function(node) { + node.__transition__[id].event.on(type, listener); + }); + } + return this; +}; + +d3_transitionPrototype.transition = function() { + var id0 = this.id, + id1 = ++d3_transitionId, + subgroups = [], + subgroup, + group, + node, + transition; + + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if (node = group[i]) { + transition = Object.create(node.__transition__[id0]); + transition.delay += transition.duration; + d3_transitionNode(node, i, id1, transition); + } + subgroup.push(node); + } + } + + return d3_transition(subgroups, id1); +}; + +function d3_transitionNode(node, i, id, inherit) { + var lock = node.__transition__ || (node.__transition__ = {active: 0, count: 0}), + transition = lock[id]; + + if (!transition) { + var time = inherit.time; + + transition = lock[id] = { + tween: new d3_Map, + event: d3.dispatch("start", "end"), // TODO construct lazily? + time: time, + ease: inherit.ease, + delay: inherit.delay, + duration: inherit.duration }; - var Geom = { - bisect: function(s1, s2) { - var newEdge = { - region: { - l: s1, - r: s2 - }, - ep: { - l: null, - r: null + + ++lock.count; + + d3.timer(function(elapsed) { + var d = node.__data__, + ease = transition.ease, + event = transition.event, + delay = transition.delay, + duration = transition.duration, + tweened = []; + + return delay <= elapsed + ? start(elapsed) + : d3.timer(start, delay, time), 1; + + function start(elapsed) { + if (lock.active > id) return stop(); + lock.active = id; + event.start.call(node, d, i); + + transition.tween.forEach(function(key, value) { + if (value = value.call(node, d, i)) { + tweened.push(value); } - }; - var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy; - newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5; - if (adx > ady) { - newEdge.a = 1; - newEdge.b = dy / dx; - newEdge.c /= dx; - } else { - newEdge.b = 1; - newEdge.a = dx / dy; - newEdge.c /= dy; + }); + + if (!tick(elapsed)) d3.timer(tick, 0, time); + return 1; + } + + function tick(elapsed) { + if (lock.active !== id) return stop(); + + var t = (elapsed - delay) / duration, + e = ease(t), + n = tweened.length; + + while (n > 0) { + tweened[--n].call(node, e); } - return newEdge; - }, - intersect: function(el1, el2) { - var e1 = el1.edge, e2 = el2.edge; - if (!e1 || !e2 || e1.region.r == e2.region.r) { - return null; - } - var d = e1.a * e2.b - e1.b * e2.a; - if (Math.abs(d) < 1e-10) { - return null; - } - var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e; - if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) { - el = el1; - e = e1; - } else { - el = el2; - e = e2; - } - var rightOfSite = xint >= e.region.r.x; - if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") { - return null; - } - return { - x: xint, - y: yint - }; - }, - rightOf: function(he, p) { - var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x; - if (rightOfSite && he.side === "l") { + + if (t >= 1) { + stop(); + event.end.call(node, d, i); return 1; } - if (!rightOfSite && he.side === "r") { - return 0; - } - if (e.a === 1) { - var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0; - if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) { - above = fast = dyp >= e.b * dxp; - } else { - above = p.x + p.y * e.b > e.c; - if (e.b < 0) { - above = !above; - } - if (!above) { - fast = 1; - } - } - if (!fast) { - var dxs = topsite.x - e.region.l.x; - above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b); - if (e.b < 0) { - above = !above; - } - } - } else { - var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y; - above = t1 * t1 > t2 * t2 + t3 * t3; - } - return he.side === "l" ? above : !above; - }, - endPoint: function(edge, side, site) { - edge.ep[side] = site; - if (!edge.ep[d3_voronoi_opposite[side]]) return; - callback(edge); - }, - distance: function(s, t) { - var dx = s.x - t.x, dy = s.y - t.y; - return Math.sqrt(dx * dx + dy * dy); } - }; - var EventQueue = { - list: [], - insert: function(he, site, offset) { - he.vertex = site; - he.ystar = site.y + offset; - for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) { - var next = list[i]; - if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) { - continue; - } else { - break; - } - } - list.splice(i, 0, he); - }, - del: function(he) { - for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {} - ls.splice(i, 1); - }, - empty: function() { - return EventQueue.list.length === 0; - }, - nextEvent: function(he) { - for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) { - if (ls[i] == he) return ls[i + 1]; - } - return null; - }, - min: function() { - var elem = EventQueue.list[0]; - return { - x: elem.vertex.x, - y: elem.ystar - }; - }, - extractMin: function() { - return EventQueue.list.shift(); + + function stop() { + if (--lock.count) delete lock[id]; + else delete node.__transition__; + return 1; } - }; - EdgeList.init(); - Sites.bottomSite = Sites.list.shift(); - var newSite = Sites.list.shift(), newIntStar; - var lbnd, rbnd, llbnd, rrbnd, bisector; - var bot, top, temp, p, v; - var e, pm; - while (true) { - if (!EventQueue.empty()) { - newIntStar = EventQueue.min(); - } - if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) { - lbnd = EdgeList.leftBound(newSite); - rbnd = EdgeList.right(lbnd); - bot = EdgeList.rightRegion(lbnd); - e = Geom.bisect(bot, newSite); - bisector = EdgeList.createHalfEdge(e, "l"); - EdgeList.insert(lbnd, bisector); - p = Geom.intersect(lbnd, bisector); - if (p) { - EventQueue.del(lbnd); - EventQueue.insert(lbnd, p, Geom.distance(p, newSite)); - } - lbnd = bisector; - bisector = EdgeList.createHalfEdge(e, "r"); - EdgeList.insert(lbnd, bisector); - p = Geom.intersect(bisector, rbnd); - if (p) { - EventQueue.insert(bisector, p, Geom.distance(p, newSite)); - } - newSite = Sites.list.shift(); - } else if (!EventQueue.empty()) { - lbnd = EventQueue.extractMin(); - llbnd = EdgeList.left(lbnd); - rbnd = EdgeList.right(lbnd); - rrbnd = EdgeList.right(rbnd); - bot = EdgeList.leftRegion(lbnd); - top = EdgeList.rightRegion(rbnd); - v = lbnd.vertex; - Geom.endPoint(lbnd.edge, lbnd.side, v); - Geom.endPoint(rbnd.edge, rbnd.side, v); - EdgeList.del(lbnd); - EventQueue.del(rbnd); - EdgeList.del(rbnd); - pm = "l"; - if (bot.y > top.y) { - temp = bot; - bot = top; - top = temp; - pm = "r"; - } - e = Geom.bisect(bot, top); - bisector = EdgeList.createHalfEdge(e, pm); - EdgeList.insert(llbnd, bisector); - Geom.endPoint(e, d3_voronoi_opposite[pm], v); - p = Geom.intersect(llbnd, bisector); - if (p) { - EventQueue.del(llbnd); - EventQueue.insert(llbnd, p, Geom.distance(p, bot)); - } - p = Geom.intersect(bisector, rrbnd); - if (p) { - EventQueue.insert(bisector, p, Geom.distance(p, bot)); - } - } else { - break; - } - } - for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) { - callback(lbnd.edge); - } + }, 0, time); + + return transition; } - d3.geom.delaunay = function(vertices) { - var edges = vertices.map(function() { - return []; - }), triangles = []; - d3_voronoi_tessellate(vertices, function(e) { - edges[e.region.l.index].push(vertices[e.region.r.index]); - }); - edges.forEach(function(edge, i) { - var v = vertices[i], cx = v[0], cy = v[1]; - edge.forEach(function(v) { - v.angle = Math.atan2(v[0] - cx, v[1] - cy); - }); - edge.sort(function(a, b) { - return a.angle - b.angle; - }); - for (var j = 0, m = edge.length - 1; j < m; j++) { - triangles.push([ v, edge[j], edge[j + 1] ]); - } - }); - return triangles; +} + +d3.xhr = function(url, mimeType, callback) { + var xhr = {}, + dispatch = d3.dispatch("progress", "load", "error"), + headers = {}, + response = d3_identity, + request = new (d3_window.XDomainRequest && /^(http(s)?:)?\/\//.test(url) ? XDomainRequest : XMLHttpRequest); + + "onload" in request + ? request.onload = request.onerror = respond + : request.onreadystatechange = function() { request.readyState > 3 && respond(); }; + + function respond() { + var s = request.status; + !s && request.responseText || s >= 200 && s < 300 || s === 304 + ? dispatch.load.call(xhr, response.call(xhr, request)) + : dispatch.error.call(xhr, request); + } + + request.onprogress = function(event) { + var o = d3.event; + d3.event = event; + try { dispatch.progress.call(xhr, request); } + finally { d3.event = o; } }; - d3.geom.quadtree = function(points, x1, y1, x2, y2) { - var p, i = -1, n = points.length; - if (arguments.length < 5) { - if (arguments.length === 3) { - y2 = y1; - x2 = x1; - y1 = x1 = 0; - } else { - x1 = y1 = Infinity; - x2 = y2 = -Infinity; - while (++i < n) { - p = points[i]; - if (p.x < x1) x1 = p.x; - if (p.y < y1) y1 = p.y; - if (p.x > x2) x2 = p.x; - if (p.y > y2) y2 = p.y; - } - } - } - var dx = x2 - x1, dy = y2 - y1; - if (dx > dy) y2 = y1 + dx; else x2 = x1 + dy; - function insert(n, p, x1, y1, x2, y2) { - if (isNaN(p.x) || isNaN(p.y)) return; - if (n.leaf) { - var v = n.point; - if (v) { - if (Math.abs(v.x - p.x) + Math.abs(v.y - p.y) < .01) { - insertChild(n, p, x1, y1, x2, y2); - } else { - n.point = null; - insertChild(n, v, x1, y1, x2, y2); - insertChild(n, p, x1, y1, x2, y2); - } - } else { - n.point = p; - } - } else { - insertChild(n, p, x1, y1, x2, y2); - } - } - function insertChild(n, p, x1, y1, x2, y2) { - var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = p.x >= sx, bottom = p.y >= sy, i = (bottom << 1) + right; - n.leaf = false; - n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); - if (right) x1 = sx; else x2 = sx; - if (bottom) y1 = sy; else y2 = sy; - insert(n, p, x1, y1, x2, y2); - } - var root = d3_geom_quadtreeNode(); - root.add = function(p) { - insert(root, p, x1, y1, x2, y2); - }; - root.visit = function(f) { - d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2); - }; - points.forEach(root.add); - return root; + + xhr.header = function(name, value) { + name = (name + "").toLowerCase(); + if (arguments.length < 2) return headers[name]; + if (value == null) delete headers[name]; + else headers[name] = value + ""; + return xhr; }; - function d3_geom_quadtreeNode() { - return { - leaf: true, - nodes: [], - point: null - }; - } - function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { - if (!f(node, x1, y1, x2, y2)) { - var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; - if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); - if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); - if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); - if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); - } - } - d3.time = {}; - var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; - function d3_time_utc() { - this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); - } - d3_time_utc.prototype = { - getDate: function() { - return this._.getUTCDate(); - }, - getDay: function() { - return this._.getUTCDay(); - }, - getFullYear: function() { - return this._.getUTCFullYear(); - }, - getHours: function() { - return this._.getUTCHours(); - }, - getMilliseconds: function() { - return this._.getUTCMilliseconds(); - }, - getMinutes: function() { - return this._.getUTCMinutes(); - }, - getMonth: function() { - return this._.getUTCMonth(); - }, - getSeconds: function() { - return this._.getUTCSeconds(); - }, - getTime: function() { - return this._.getTime(); - }, - getTimezoneOffset: function() { - return 0; - }, - valueOf: function() { - return this._.valueOf(); - }, - setDate: function() { - d3_time_prototype.setUTCDate.apply(this._, arguments); - }, - setDay: function() { - d3_time_prototype.setUTCDay.apply(this._, arguments); - }, - setFullYear: function() { - d3_time_prototype.setUTCFullYear.apply(this._, arguments); - }, - setHours: function() { - d3_time_prototype.setUTCHours.apply(this._, arguments); - }, - setMilliseconds: function() { - d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); - }, - setMinutes: function() { - d3_time_prototype.setUTCMinutes.apply(this._, arguments); - }, - setMonth: function() { - d3_time_prototype.setUTCMonth.apply(this._, arguments); - }, - setSeconds: function() { - d3_time_prototype.setUTCSeconds.apply(this._, arguments); - }, - setTime: function() { - d3_time_prototype.setTime.apply(this._, arguments); - } + + // If mimeType is non-null and no Accept header is set, a default is used. + xhr.mimeType = function(value) { + if (!arguments.length) return mimeType; + mimeType = value == null ? null : value + ""; + return xhr; }; - var d3_time_prototype = Date.prototype; - var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S"; - var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; - d3.time.format = function(template) { - var n = template.length; - function format(date) { - var string = [], i = -1, j = 0, c, p, f; - while (++i < n) { - if (template.charCodeAt(i) === 37) { - string.push(template.substring(j, i)); - if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); - if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); - string.push(c); - j = i + 1; - } - } - string.push(template.substring(j, i)); - return string.join(""); - } - format.parse = function(string) { - var d = { - y: 1900, - m: 0, - d: 1, - H: 0, - M: 0, - S: 0, - L: 0 - }, i = d3_time_parse(d, template, string, 0); - if (i != string.length) return null; - if ("p" in d) d.H = d.H % 12 + d.p * 12; - var date = new d3_time(); - date.setFullYear(d.y, d.m, d.d); - date.setHours(d.H, d.M, d.S, d.L); - return date; - }; - format.toString = function() { - return template; - }; - return format; + + // Specify how to convert the response content to a specific type; + // changes the callback value on "load" events. + xhr.response = function(value) { + response = value; + return xhr; }; - function d3_time_parse(date, template, string, j) { - var c, p, i = 0, n = template.length, m = string.length; - while (i < n) { - if (j >= m) return -1; - c = template.charCodeAt(i++); - if (c === 37) { - p = d3_time_parsers[template.charAt(i++)]; - if (!p || (j = p(date, string, j)) < 0) return -1; - } else if (c != string.charCodeAt(j++)) { - return -1; - } - } - return j; - } - function d3_time_formatRe(names) { - return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); - } - function d3_time_formatLookup(names) { - var map = new d3_Map(), i = -1, n = names.length; - while (++i < n) map.set(names[i].toLowerCase(), i); - return map; - } - function d3_time_formatPad(value, fill, width) { - value += ""; - var length = value.length; - return length < width ? new Array(width - length + 1).join(fill) + value : value; - } - var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations); - var d3_time_formatPads = { - "-": "", - _: " ", - "0": "0" - }; - var d3_time_formats = { - a: function(d) { - return d3_time_dayAbbreviations[d.getDay()]; - }, - A: function(d) { - return d3_time_days[d.getDay()]; - }, - b: function(d) { - return d3_time_monthAbbreviations[d.getMonth()]; - }, - B: function(d) { - return d3_time_months[d.getMonth()]; - }, - c: d3.time.format(d3_time_formatDateTime), - d: function(d, p) { - return d3_time_formatPad(d.getDate(), p, 2); - }, - e: function(d, p) { - return d3_time_formatPad(d.getDate(), p, 2); - }, - H: function(d, p) { - return d3_time_formatPad(d.getHours(), p, 2); - }, - I: function(d, p) { - return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); - }, - j: function(d, p) { - return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3); - }, - L: function(d, p) { - return d3_time_formatPad(d.getMilliseconds(), p, 3); - }, - m: function(d, p) { - return d3_time_formatPad(d.getMonth() + 1, p, 2); - }, - M: function(d, p) { - return d3_time_formatPad(d.getMinutes(), p, 2); - }, - p: function(d) { - return d.getHours() >= 12 ? "PM" : "AM"; - }, - S: function(d, p) { - return d3_time_formatPad(d.getSeconds(), p, 2); - }, - U: function(d, p) { - return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2); - }, - w: function(d) { - return d.getDay(); - }, - W: function(d, p) { - return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2); - }, - x: d3.time.format(d3_time_formatDate), - X: d3.time.format(d3_time_formatTime), - y: function(d, p) { - return d3_time_formatPad(d.getFullYear() % 100, p, 2); - }, - Y: function(d, p) { - return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); - }, - Z: d3_time_zone, - "%": function() { - return "%"; - } - }; - var d3_time_parsers = { - a: d3_time_parseWeekdayAbbrev, - A: d3_time_parseWeekday, - b: d3_time_parseMonthAbbrev, - B: d3_time_parseMonth, - c: d3_time_parseLocaleFull, - d: d3_time_parseDay, - e: d3_time_parseDay, - H: d3_time_parseHour24, - I: d3_time_parseHour24, - L: d3_time_parseMilliseconds, - m: d3_time_parseMonthNumber, - M: d3_time_parseMinutes, - p: d3_time_parseAmPm, - S: d3_time_parseSeconds, - x: d3_time_parseLocaleDate, - X: d3_time_parseLocaleTime, - y: d3_time_parseYear, - Y: d3_time_parseFullYear - }; - function d3_time_parseWeekdayAbbrev(date, string, i) { - d3_time_dayAbbrevRe.lastIndex = 0; - var n = d3_time_dayAbbrevRe.exec(string.substring(i)); - return n ? i += n[0].length : -1; - } - function d3_time_parseWeekday(date, string, i) { - d3_time_dayRe.lastIndex = 0; - var n = d3_time_dayRe.exec(string.substring(i)); - return n ? i += n[0].length : -1; - } - function d3_time_parseMonthAbbrev(date, string, i) { - d3_time_monthAbbrevRe.lastIndex = 0; - var n = d3_time_monthAbbrevRe.exec(string.substring(i)); - return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i += n[0].length) : -1; - } - function d3_time_parseMonth(date, string, i) { - d3_time_monthRe.lastIndex = 0; - var n = d3_time_monthRe.exec(string.substring(i)); - return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i += n[0].length) : -1; - } - function d3_time_parseLocaleFull(date, string, i) { - return d3_time_parse(date, d3_time_formats.c.toString(), string, i); - } - function d3_time_parseLocaleDate(date, string, i) { - return d3_time_parse(date, d3_time_formats.x.toString(), string, i); - } - function d3_time_parseLocaleTime(date, string, i) { - return d3_time_parse(date, d3_time_formats.X.toString(), string, i); - } - function d3_time_parseFullYear(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 4)); - return n ? (date.y = +n[0], i += n[0].length) : -1; - } - function d3_time_parseYear(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.y = d3_time_expandYear(+n[0]), i += n[0].length) : -1; - } - function d3_time_expandYear(d) { - return d + (d > 68 ? 1900 : 2e3); - } - function d3_time_parseMonthNumber(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.m = n[0] - 1, i += n[0].length) : -1; - } - function d3_time_parseDay(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.d = +n[0], i += n[0].length) : -1; - } - function d3_time_parseHour24(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.H = +n[0], i += n[0].length) : -1; - } - function d3_time_parseMinutes(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.M = +n[0], i += n[0].length) : -1; - } - function d3_time_parseSeconds(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.S = +n[0], i += n[0].length) : -1; - } - function d3_time_parseMilliseconds(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 3)); - return n ? (date.L = +n[0], i += n[0].length) : -1; - } - var d3_time_numberRe = /^\s*\d+/; - function d3_time_parseAmPm(date, string, i) { - var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase()); - return n == null ? -1 : (date.p = n, i); - } - var d3_time_amPmLookup = d3.map({ - am: 0, - pm: 1 - }); - function d3_time_zone(d) { - var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60; - return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); - } - d3.time.format.utc = function(template) { - var local = d3.time.format(template); - function format(date) { - try { - d3_time = d3_time_utc; - var utc = new d3_time(); - utc._ = date; - return local(utc); - } finally { - d3_time = Date; - } - } - format.parse = function(string) { - try { - d3_time = d3_time_utc; - var date = local.parse(string); - return date && date._; - } finally { - d3_time = Date; - } - }; - format.toString = local.toString; - return format; - }; - var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ"); - d3.time.format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; - function d3_time_formatIsoNative(date) { - return date.toISOString(); - } - d3_time_formatIsoNative.parse = function(string) { - var date = new Date(string); - return isNaN(date) ? null : date; - }; - d3_time_formatIsoNative.toString = d3_time_formatIso.toString; - function d3_time_interval(local, step, number) { - function round(date) { - var d0 = local(date), d1 = offset(d0, 1); - return date - d0 < d1 - date ? d0 : d1; - } - function ceil(date) { - step(date = local(new d3_time(date - 1)), 1); - return date; - } - function offset(date, k) { - step(date = new d3_time(+date), k); - return date; - } - function range(t0, t1, dt) { - var time = ceil(t0), times = []; - if (dt > 1) { - while (time < t1) { - if (!(number(time) % dt)) times.push(new Date(+time)); - step(time, 1); - } - } else { - while (time < t1) times.push(new Date(+time)), step(time, 1); - } - return times; - } - function range_utc(t0, t1, dt) { - try { - d3_time = d3_time_utc; - var utc = new d3_time_utc(); - utc._ = t0; - return range(utc, t1, dt); - } finally { - d3_time = Date; - } - } - local.floor = local; - local.round = round; - local.ceil = ceil; - local.offset = offset; - local.range = range; - var utc = local.utc = d3_time_interval_utc(local); - utc.floor = utc; - utc.round = d3_time_interval_utc(round); - utc.ceil = d3_time_interval_utc(ceil); - utc.offset = d3_time_interval_utc(offset); - utc.range = range_utc; - return local; - } - function d3_time_interval_utc(method) { - return function(date, k) { - try { - d3_time = d3_time_utc; - var utc = new d3_time_utc(); - utc._ = date; - return method(utc, k)._; - } finally { - d3_time = Date; - } - }; - } - d3.time.second = d3_time_interval(function(date) { - return new d3_time(Math.floor(date / 1e3) * 1e3); - }, function(date, offset) { - date.setTime(date.getTime() + Math.floor(offset) * 1e3); - }, function(date) { - return date.getSeconds(); - }); - d3.time.seconds = d3.time.second.range; - d3.time.seconds.utc = d3.time.second.utc.range; - d3.time.minute = d3_time_interval(function(date) { - return new d3_time(Math.floor(date / 6e4) * 6e4); - }, function(date, offset) { - date.setTime(date.getTime() + Math.floor(offset) * 6e4); - }, function(date) { - return date.getMinutes(); - }); - d3.time.minutes = d3.time.minute.range; - d3.time.minutes.utc = d3.time.minute.utc.range; - d3.time.hour = d3_time_interval(function(date) { - var timezone = date.getTimezoneOffset() / 60; - return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); - }, function(date, offset) { - date.setTime(date.getTime() + Math.floor(offset) * 36e5); - }, function(date) { - return date.getHours(); - }); - d3.time.hours = d3.time.hour.range; - d3.time.hours.utc = d3.time.hour.utc.range; - d3.time.day = d3_time_interval(function(date) { - var day = new d3_time(1970, 0); - day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); - return day; - }, function(date, offset) { - date.setDate(date.getDate() + offset); - }, function(date) { - return date.getDate() - 1; - }); - d3.time.days = d3.time.day.range; - d3.time.days.utc = d3.time.day.utc.range; - d3.time.dayOfYear = function(date) { - var year = d3.time.year(date); - return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); - }; - d3_time_daySymbols.forEach(function(day, i) { - day = day.toLowerCase(); - i = 7 - i; - var interval = d3.time[day] = d3_time_interval(function(date) { - (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); - return date; - }, function(date, offset) { - date.setDate(date.getDate() + Math.floor(offset) * 7); - }, function(date) { - var day = d3.time.year(date).getDay(); - return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); - }); - d3.time[day + "s"] = interval.range; - d3.time[day + "s"].utc = interval.utc.range; - d3.time[day + "OfYear"] = function(date) { - var day = d3.time.year(date).getDay(); - return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7); + + // Convenience methods. + ["get", "post"].forEach(function(method) { + xhr[method] = function() { + return xhr.send.apply(xhr, [method].concat(d3_array(arguments))); }; }); - d3.time.week = d3.time.sunday; - d3.time.weeks = d3.time.sunday.range; - d3.time.weeks.utc = d3.time.sunday.utc.range; - d3.time.weekOfYear = d3.time.sundayOfYear; - d3.time.month = d3_time_interval(function(date) { - date = d3.time.day(date); - date.setDate(1); - return date; - }, function(date, offset) { - date.setMonth(date.getMonth() + offset); - }, function(date) { - return date.getMonth(); - }); - d3.time.months = d3.time.month.range; - d3.time.months.utc = d3.time.month.utc.range; - d3.time.year = d3_time_interval(function(date) { - date = d3.time.day(date); - date.setMonth(0, 1); - return date; - }, function(date, offset) { - date.setFullYear(date.getFullYear() + offset); - }, function(date) { - return date.getFullYear(); - }); - d3.time.years = d3.time.year.range; - d3.time.years.utc = d3.time.year.utc.range; - function d3_time_scale(linear, methods, format) { - function scale(x) { - return linear(x); - } - scale.invert = function(x) { - return d3_time_scaleDate(linear.invert(x)); - }; - scale.domain = function(x) { - if (!arguments.length) return linear.domain().map(d3_time_scaleDate); - linear.domain(x); - return scale; - }; - scale.nice = function(m) { - return scale.domain(d3_scale_nice(scale.domain(), function() { - return m; - })); - }; - scale.ticks = function(m, k) { - var extent = d3_time_scaleExtent(scale.domain()); - if (typeof m !== "function") { - var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target); - if (i == d3_time_scaleSteps.length) return methods.year(extent, m); - if (!i) return linear.ticks(m).map(d3_time_scaleDate); - if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i; - m = methods[i]; - k = m[1]; - m = m[0].range; - } - return m(extent[0], new Date(+extent[1] + 1), k); - }; - scale.tickFormat = function() { - return format; - }; - scale.copy = function() { - return d3_time_scale(linear.copy(), methods, format); - }; - return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); - } - function d3_time_scaleExtent(domain) { - var start = domain[0], stop = domain[domain.length - 1]; - return start < stop ? [ start, stop ] : [ stop, start ]; - } - function d3_time_scaleDate(t) { - return new Date(t); - } - function d3_time_scaleFormat(formats) { - return function(date) { - var i = formats.length - 1, f = formats[i]; - while (!f[1](date)) f = formats[--i]; - return f[0](date); - }; - } - function d3_time_scaleSetYear(y) { - var d = new Date(y, 0, 1); - d.setFullYear(y); - return d; - } - function d3_time_scaleGetYear(d) { - var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1); - return y + (d - d0) / (d1 - d0); - } - var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; - var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ]; - var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [ d3.time.format("%B"), function(d) { - return d.getMonth(); - } ], [ d3.time.format("%b %d"), function(d) { - return d.getDate() != 1; - } ], [ d3.time.format("%a %d"), function(d) { - return d.getDay() && d.getDate() != 1; - } ], [ d3.time.format("%I %p"), function(d) { - return d.getHours(); - } ], [ d3.time.format("%I:%M"), function(d) { - return d.getMinutes(); - } ], [ d3.time.format(":%S"), function(d) { - return d.getSeconds(); - } ], [ d3.time.format(".%L"), function(d) { - return d.getMilliseconds(); - } ] ]; - var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats); - d3_time_scaleLocalMethods.year = function(extent, m) { - return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear); + + // If callback is non-null, it will be used for error and load events. + xhr.send = function(method, data, callback) { + if (arguments.length === 2 && typeof data === "function") callback = data, data = null; + request.open(method, url, true); + if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; + if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); + if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); + if (callback != null) xhr.on("error", callback).on("load", function(request) { callback(null, request); }); + request.send(data == null ? null : data); + return xhr; }; - d3.time.scale = function() { - return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); - }; - var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) { - return [ m[0].utc, m[1] ]; - }); - var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [ d3.time.format.utc("%B"), function(d) { - return d.getUTCMonth(); - } ], [ d3.time.format.utc("%b %d"), function(d) { - return d.getUTCDate() != 1; - } ], [ d3.time.format.utc("%a %d"), function(d) { - return d.getUTCDay() && d.getUTCDate() != 1; - } ], [ d3.time.format.utc("%I %p"), function(d) { - return d.getUTCHours(); - } ], [ d3.time.format.utc("%I:%M"), function(d) { - return d.getUTCMinutes(); - } ], [ d3.time.format.utc(":%S"), function(d) { - return d.getUTCSeconds(); - } ], [ d3.time.format.utc(".%L"), function(d) { - return d.getUTCMilliseconds(); - } ] ]; - var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats); - function d3_time_scaleUTCSetYear(y) { - var d = new Date(Date.UTC(y, 0, 1)); - d.setUTCFullYear(y); - return d; - } - function d3_time_scaleUTCGetYear(d) { - var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1); - return y + (d - d0) / (d1 - d0); - } - d3_time_scaleUTCMethods.year = function(extent, m) { - return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear); - }; - d3.time.scale.utc = function() { - return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat); + + xhr.abort = function() { + request.abort(); + return xhr; }; + + d3.rebind(xhr, dispatch, "on"); + + if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, mimeType = null; + return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); +}; + +function d3_xhr_fixCallback(callback) { + return callback.length === 1 + ? function(error, request) { callback(error == null ? request : null); } + : callback; +} + +d3.text = function() { + return d3.xhr.apply(d3, arguments).response(d3_text); +}; + +function d3_text(request) { + return request.responseText; +} + +d3.json = function(url, callback) { + return d3.xhr(url, "application/json", callback).response(d3_json); +}; + +function d3_json(request) { + return JSON.parse(request.responseText); +} + +d3.html = function(url, callback) { + return d3.xhr(url, "text/html", callback).response(d3_html); +}; + +function d3_html(request) { + var range = d3_document.createRange(); + range.selectNode(d3_document.body); + return range.createContextualFragment(request.responseText); +} + +d3.xml = function() { + return d3.xhr.apply(d3, arguments).response(d3_xml); +}; + +function d3_xml(request) { + return request.responseXML; +} return d3; -}(); +})(); diff --git a/package.json b/package.json index 4cd2317a8..d3cd8dcc9 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ ], "license": "WTFPL", "devDependencies": { + "d3": "3", + "smash": "0.0", "uglify-js": "~2.2.5", "mocha-phantomjs": "~1.1.1", "glob": "~3.1.21", diff --git a/test/spec/actions/move.js b/test/spec/actions/move.js index 665b906a9..c0b716849 100644 --- a/test/spec/actions/move.js +++ b/test/spec/actions/move.js @@ -1,15 +1,17 @@ describe("iD.actions.Move", function() { + var projection = d3.geo.mercator().scale(250 / Math.PI); + describe("#disabled", function() { it("returns falsy by default", function() { var node = iD.Node({loc: [0, 0]}), - action = iD.actions.Move([node.id], [0, 0], d3.geo.mercator()), + action = iD.actions.Move([node.id], [0, 0], projection), graph = iD.Graph([node]); expect(action.disabled(graph)).not.to.be.ok; }); it("returns 'incomplete_relation' for an incomplete relation", function() { var relation = iD.Relation({members: [{id: 1}]}), - action = iD.actions.Move([relation.id], [0, 0], d3.geo.mercator()), + action = iD.actions.Move([relation.id], [0, 0], projection), graph = iD.Graph([relation]); expect(action.disabled(graph)).to.equal('incomplete_relation'); }); @@ -17,7 +19,7 @@ describe("iD.actions.Move", function() { it("returns falsy for a complete relation", function() { var node = iD.Node({loc: [0, 0]}), relation = iD.Relation({members: [{id: node.id}]}), - action = iD.actions.Move([relation.id], [0, 0], d3.geo.mercator()), + action = iD.actions.Move([relation.id], [0, 0], projection), graph = iD.Graph([node, relation]); expect(action.disabled(graph)).not.to.be.ok; }); @@ -28,7 +30,6 @@ describe("iD.actions.Move", function() { node2 = iD.Node({loc: [5, 10]}), way = iD.Way({nodes: [node1.id, node2.id]}), delta = [2, 3], - projection = d3.geo.mercator(), graph = iD.actions.Move([way.id], delta, projection)(iD.Graph([node1, node2, way])), loc1 = graph.entity(node1.id).loc, loc2 = graph.entity(node2.id).loc; @@ -42,7 +43,6 @@ describe("iD.actions.Move", function() { var node = iD.Node({loc: [0, 0]}), way = iD.Way({nodes: [node.id, node.id]}), delta = [2, 3], - projection = d3.geo.mercator(), graph = iD.actions.Move([way.id], delta, projection)(iD.Graph([node, way])), loc = graph.entity(node.id).loc; expect(loc[0]).to.be.closeTo( 1.440, 0.001); @@ -54,7 +54,6 @@ describe("iD.actions.Move", function() { way1 = iD.Way({nodes: [node.id]}), way2 = iD.Way({nodes: [node.id]}), delta = [2, 3], - projection = d3.geo.mercator(), graph = iD.actions.Move([way1.id, way2.id], delta, projection)(iD.Graph([node, way1, way2])), loc = graph.entity(node.id).loc; expect(loc[0]).to.be.closeTo( 1.440, 0.001); @@ -66,7 +65,6 @@ describe("iD.actions.Move", function() { way = iD.Way({nodes: [node.id]}), relation = iD.Relation({members: [{id: way.id}]}), delta = [2, 3], - projection = d3.geo.mercator(), graph = iD.actions.Move([relation.id], delta, projection)(iD.Graph([node, way, relation])), loc = graph.entity(node.id).loc; expect(loc[0]).to.be.closeTo( 1.440, 0.001); diff --git a/test/spec/svg.js b/test/spec/svg.js index cc2b868d9..72efc293d 100644 --- a/test/spec/svg.js +++ b/test/spec/svg.js @@ -1,5 +1,5 @@ describe("iD.svg.LineString", function () { - var projection = d3.geo.mercator(); + var projection = d3.geo.mercator().scale(250 / Math.PI); it("returns an SVG path description for the entity's nodes", function () { var a = iD.Node({loc: [0, 0]}), From ccbb883d8f2c5c08e6d9fa372b9bd03ae445e005 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 2 Apr 2013 15:12:09 -0700 Subject: [PATCH 03/14] Fix test include --- test/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/test/index.html b/test/index.html index 569ebe82b..f732d4dd0 100644 --- a/test/index.html +++ b/test/index.html @@ -231,7 +231,6 @@ - From 4bc98c32d12e8fab03cd2d5f94a05adaba4dd589 Mon Sep 17 00:00:00 2001 From: Saman Bemel-Benrud Date: Wed, 3 Apr 2013 14:20:38 -0400 Subject: [PATCH 04/14] reworked out links, closes #1242 --- css/app.css | 11 ++++++++++- data/core.yaml | 4 ++-- data/locales.js | 4 ++-- img/sprite.png | Bin 14486 -> 38165 bytes img/sprite2x.png | Bin 31439 -> 83777 bytes js/id/ui/tag_editor.js | 10 +++++++--- js/id/ui/tag_reference.js | 9 +++++++-- svg/sprite.svg | 35 +++++++++++++++++++++++------------ 8 files changed, 51 insertions(+), 22 deletions(-) diff --git a/css/app.css b/css/app.css index 13df2863f..bcba11599 100644 --- a/css/app.css +++ b/css/app.css @@ -487,7 +487,6 @@ button.save.has-count .count::before { .icon.back { background-position: -420px 0;} .icon.forward { background-position: -440px 0;} .icon.help { background-position: -460px 0;} -.icon.out-link { background-position: -480px 0;} .icon.inspect.light { background-position: -220px -20px;} .icon.geocode.light { background-position: -280px -20px;} @@ -540,6 +539,11 @@ button[disabled] .icon.nearby { background-position: -340px -40px;} .icon-operation-disabled-rotate { background-position: -180px -160px;} .icon-operation-disabled-simplify { background-position: -200px -160px;} +/* Out link is special */ + +.icon.out-link { height: 14px; width: 14px; background-position: -500px 0;} +a:hover .icon.out-link { background-position: -500px -14px;} + /* Universal preset icons */ .icon.source { background-position: 0 -200px;} @@ -1370,6 +1374,11 @@ div.combobox { overflow: hidden; } +.tag-help a { + margin-top: 5px; + display: block; +} + .grid-pane .tag-reference-wrap { padding: 10px 0 20px 0; } diff --git a/data/core.yaml b/data/core.yaml index d5fdb8ea8..dd7215070 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -154,12 +154,12 @@ en: no_documentation_key: There is no documentation available for this key show_more: Show More new_tag: New tag - view_on_osm: View on OSM → + view_on_osm: View on openstreetmap.org editing_feature: "Editing {feature}" additional: Additional tags choose: Select feature type results: "{n} results for {search}" - reference: View on OpenStreetMap Wiki → + reference: View on OpenStreetMap Wiki back_tooltip: Change feature type background: title: Background diff --git a/data/locales.js b/data/locales.js index cb299b379..7bd71aa90 100644 --- a/data/locales.js +++ b/data/locales.js @@ -192,12 +192,12 @@ locale.en = { "no_documentation_key": "There is no documentation available for this key", "show_more": "Show More", "new_tag": "New tag", - "view_on_osm": "View on OSM →", + "view_on_osm": "View on openstreetmap.org", "editing_feature": "Editing {feature}", "additional": "Additional tags", "choose": "Select feature type", "results": "{n} results for {search}", - "reference": "View on OpenStreetMap Wiki →", + "reference": "View on OpenStreetMap Wiki", "back_tooltip": "Change feature type" }, "background": { diff --git a/img/sprite.png b/img/sprite.png index c60de32dcf75f3d67dcab6e907ad47778c8e2ee0..950e5f89dc50ed87f0c1a18634997560338fa413 100644 GIT binary patch literal 38165 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 literal 14486 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 diff --git a/img/sprite2x.png b/img/sprite2x.png index e08cb78e0e42867a2b2377554d3ce0b8018b1314..dfb1a18537a22cdd2207a254cb98a57055847c75 100644 GIT binary patch literal 83777 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

MtZ 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 literal 31439 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 S@>`E?R992hQYu$~!u|)|I-jHf diff --git a/js/id/ui/tag_editor.js b/js/id/ui/tag_editor.js index a49f19acb..82f01f561 100644 --- a/js/id/ui/tag_editor.js +++ b/js/id/ui/tag_editor.js @@ -73,12 +73,16 @@ iD.ui.TagEditor = function(context, entity) { .call(tagList, preset.id === 'other'); if (!entity.isNew()) { - tageditorpreset.append('div') + osmLink = tageditorpreset.append('div') .attr('class', 'col12 inspector-inner') .append('a') .attr('href', 'http://www.openstreetmap.org/browse/' + entity.type + '/' + entity.osmId()) - .attr('target', '_blank') - .text(t('inspector.view_on_osm')); + .attr('target', '_blank'); + + osmLink.append('span') + .attr('class','icon icon-pre-text out-link'); + + osmLink.append('span').text(t('inspector.view_on_osm')); } tageditor.tags(tags); diff --git a/js/id/ui/tag_reference.js b/js/id/ui/tag_reference.js index b18ba806b..47261451d 100644 --- a/js/id/ui/tag_reference.js +++ b/js/id/ui/tag_reference.js @@ -72,10 +72,15 @@ iD.ui.TagReference = function(entity, tag) { .append('p') .text(docs.description); - referenceBody + var wikiLink = referenceBody .append('a') .attr('target', '_blank') - .attr('href', 'http://wiki.openstreetmap.org/wiki/' + docs.title) + .attr('href', 'http://wiki.openstreetmap.org/wiki/' + docs.title); + + wikiLink.append('span') + .attr('class','icon icon-pre-text out-link'); + + wikiLink.append('span') .text(t('inspector.reference')); }); diff --git a/svg/sprite.svg b/svg/sprite.svg index 5395545c8..f38bfabc0 100644 --- a/svg/sprite.svg +++ b/svg/sprite.svg @@ -15,7 +15,7 @@ version="1.1" inkscape:version="0.48.2 r9819" sodipodi:docname="sprite.svg" - inkscape:export-filename="/Users/saman/work_repos/iD/img/sprite2x.png" + inkscape:export-filename="/Users/saman/work_repos/iD/img/sprite.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90"> + @@ -224,7 +228,7 @@ image/svg+xml - + @@ -2607,8 +2611,15 @@ + d="m 532.5,1.9999969 0,1 1,1 -4.5,4.5000001 0,0.5 0,1 1.5,0 4.5,-4.5000001 1,1 1,0 0,-3.5 0,-1 -1,0 z m -6.5,1 -1,1 0,9.0000001 1,1 9,0 1,-1 0,-5 -2,2 0,2 -1,0 -1,0 -4,0 -1,0 0,-5.0000001 0,-2 1,0 1,0 2,-2 z" + id="path3404-8" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccccccccccccccccccccccccccccccc" /> + From 67fcb1d7c2e289afa9d7c1757527e901838e2b23 Mon Sep 17 00:00:00 2001 From: Saman Bemel-Benrud Date: Wed, 3 Apr 2013 14:23:26 -0400 Subject: [PATCH 05/14] fixed sprite. --- img/sprite.png | Bin 38165 -> 14494 bytes img/sprite2x.png | Bin 83777 -> 31478 bytes svg/sprite.svg | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/img/sprite.png b/img/sprite.png index 950e5f89dc50ed87f0c1a18634997560338fa413..ccda51669a7fe0f960e60ee7b6973a7a84fb2114 100644 GIT binary patch literal 14494 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 Ds&v|# literal 38165 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 diff --git a/img/sprite2x.png b/img/sprite2x.png index dfb1a18537a22cdd2207a254cb98a57055847c75..78df59ab73bad436973ff8ebb917a99abf92ae74 100644 GIT binary patch literal 31478 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 Am;e9( literal 83777 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

MtZ z{iNH?z`DWjj$l6RKJ*BR3JmXC8wPtltd1uDtOFt|=LJ(Vzu+oYj@%uxV6$2_YlVzY zPXU$}*@uB6_JXpg%*s>|yCwTro^g7zmg&!>ttYMT|CW)_nTdnCqedlv(v=wZKLiiN zO~ap^N6#<6T+yxmTu(t+T`bm4r^UAPQ+x07@I^4r?$_sp!gjKTG^b6`=W1`}^AKJW zgxbZxF;TI%pQ(&az?#+a1%n3$=pj)DVcDxQ&!QP>Lf49#>6Q+ru_7p332;N+Pteq@@VN!;c#hj~ce=^T77dAgwP@azkxTI+Q z5jHC?gJR$2Ct5#q`{h8`MYE)IM$=jzD;K>zE91&6t@%Mxp6mEJw3Cfj_8sGw#A26c zp>1zT-^9QcyN0)b)YTVi9*9kSq32A53$&cFFzl|F24QC*q80^ z6<215blb(6oWcuRgKyS4h1o>Y6(y`})0bsG-yr>PsK4*bgW069E-)33UlsNVvrFG$ z-caf{0zYKBxy{X{8Y2iPy3GK>>cQ{~W?u6uROxe5G8SZyi7KD{@DJb#N**OJ>cf~j zcLudl>NKX}#z+`BEZl&bdyS%^`6;j_HRV$9*s8<47F)&*4mi*?bb61pjQuz!*n z=@5~(Kuho$*OD@JSDKavbF{vbRtvmYsOF^Lecui4_oRb}R2!c7F$4_d&12u*QFH9< zyGX`oesB6NSV86<@8DKl3g9UXlDREHG@Et>^`hzkkDND1GA5CawYPBSe&citQ@l}s zMd05U+vve@-+OfBTdi0IUOkFFNze$1i{9c=)eD4ePplMAZWzPR*k&Z0M#ivQVpf9} zf0%}D>cx+0q-~}PNj4}61xgr4q&#znUECxpbwlehwF!3Z_h*Fe<&C-*6MSW#9E%CU zT#hpF)dV*>vmC`F+VV3w81A&_sf--~Lv@c^%y^9_GQSlhwqMB3@jDF?aNx1>QRjwy z1i%mHWigp%Kl)MkQ{Vf^$REKNi$|YV@akM&KFXO<8Z}SBbfQLdZ{zVQI-{Kle>anV zX5M4g-dSS&yhos3YEi$aR;u_?T2-W_#<0IfWo_}?G@kiTndrd?5&XUFhrfjNdah@v zS?IwyBMEY_=_?B=-IOYTJqB})@_|39H2OB|G3UwrnL*oPV%*C zpZB`xCWtEOA3cB1L=L9kJkp|6Ce`ZAq_IkQ*>mA4{}O2cGh?RrBi*_;Qo?- zvy>y|t&*v@6RzIHd|bptGK9jHYN(d`V-kPWIW@@K?xL;KM{l+o$xk&g(!^ge-IPdR zV<`HBysPG7Z2R69>)1-YbF4vc#!hdxsO%Md2h;GIZAA=*i+bx}5s@d{0zy&6--X!* z7aPbu9yw*~=C&J`AK>EjTQzQ@i+vZ^q7tnhE-`2Aem8e80|MWEEt0xvNifxfjJx%Ga2>f=fVz({c@@DNJ!v07 z5B27<x3z?SK%t5X=7W1wKZ*S&Ns0006;xi*Yui;Cj>?RCqm2njUSetwsj&2{0p z-JP{i$fvpS#zvSO$*ht0i>@3>6jRjzLwVa5{gKVO1299``(&)h9RkDJuGtktjiwmG z1wgvnZy1{@+!_Mwn?#6B(!~z#rT593(jd?7C`#0XRl3!u__MkpO@Zn$v#yZ1abV~_ z%holo2B_YhmT5N^+TjYOH2c!g8S(^%GZ-FY-QdpkvJhJhC3tsG>TU@7Kv~l_-*Vq( zuW~!CEs5u<2@`Cki|siFY%O9kQ4L|t-<(piq)4hp95W{j`uiwC^+r0l`VZTote;a@ z4y`KS(lZ4Iw6!DBW-6GJxr1#juIL1p6af2V84iyHs4#q9RLqxMS{Q`$3y@<>#~gmq z4REatCU(;x78%XbqBp};qI(M;Z?hI@UX{~3FkZio%zwdxPx-vm9MJ@Ji+qo{`ZnUr z1FLTV%XsgEtSFbub+3D)cjL2SO;3%iBKY&57rS%ZzE6GWpox3C=)1>-q1uSeGszR7ddV(wPYy-S7Oy z4lO7q$7JMVy@do+(D8!BHnKA2UOqv#qijo~G+FErfQzEB`&;^|Ur0<#ntM`)&jnAj zcYLJ^)Ld|^m-j=ZIVF2m>viyFL)Frc`B(|IY(e2qoF9p=A9VPnp?H`a>?LKXg*Axf z#7w|i)Rw#^Ys;tQZWeMJZ@r87!ebpq7%4Xem^0^GO)2i&C!WV4-vq=mOM4u1nQ|UK z4}pX{gZHTe>2is6^uVt zskpd1Rnc9tb13*Er^PV8HdCdxTbJQKv6w%R+p9E+5oCG5vVtET+t7&WP4w=buEx`8 zI?9vKyvQX?n;?$f^idQ52=hM9ba=Ze#qUsOdYlhJJ!P-96Kd+Ps?gqA ztJbPC>IaywDAAU#o_&vqO6}>AKHp&B;+%=uTRpvlykyLQ7NFEcH9}{ocjUkXOrFg8 zb6(o$|K_^bml$+g66L%9iU`SUN*fC*^eg*{*gS1JeF#AaQE@B+CO^nip*Wd1dtxgI3_Ac9k^g^ycS5+ zJ^W2B&*ycu>~IaQ!NEIYe^~%=U@$9dyKx*9tM&A?lf2r#(rUcc$RqR? zU*kRjgmaKFxwh~ztk!8Y7}tT`KaBzCx2dSs#FhTGCn9d?LIPW%cH`-bhoiqAbA+T( zm*C97v61}nHWzKAgzc74|ufZDpypOCS2GRa57Lu2MEb7jagq@&U z>W{S>mpC~OR8{{RYqw@q9aKDXfF$+b!hmw0RfN%-(!^p9LL^L!G+J$-K=>X)mX4^6 zKEKgEqnXhsm!P0vUHP8grPv7mKFX{jAoG3BDAZxXGmQMW7IXiwk&fe!dbo7$*EQIE~@zA!x zl9(u8dSLRos9sHzkez!YKD8-JuDg!38GAySI9roTLJkw_Vew9!Ypv7tOX+vz{$-OK zm4z!S&n4SdA%Ck>xU=tSRJ!i6`TMW+&S30y_u8mcbwnjLbY7AH7bawR% zuJXX|3w1ss(3JerMRYqJtsLN&AeC0zZiZL;V8~O=)*(xl&7m^GVFuUW>RHlVN7%_G z)^_O`r1QEqm;p0tkkHP?(uD}G)`xt($_FH-~+ z4H+vStd=G-zb)*7b@)-JP($-hFft!1A^I`*c3@iu)IcU-CgFz?zx35O<|%tTuY$ft z`ro(upDZm_mW~cKb;#1x%~Bf!`m4Aa3r_QY%;H>qjP-w~{pJ6++oS&G%&`6+o-NQ_ zBeRzi##nOIO7Z$?C#|n;wExc6-ZyNpEk^5JMm6C0lY;)rweMiNqfyWz27keMsU%w_i!=5)G^(d9vaP*nHhZi5*4EXqjXF5a0JfVMXZtgWo zHg8JWe<)w=v|gBr?C-0~KtZ^wdwJiHx1w=jikUDr?{I+%b^XCj`i6x_-hTd+p3;Kw zVRvb&N~}WmYCrQPQ(5uI+$KH~B#xmB_{Z||lR2>>_Mm{;&Pm0;uY97B%uqdn6uFy9 z-}O*wtW#%{Zc=UpZuX$WivbH$pg>kD7L3ca2(-LktoJcKX&I*XTcx&BO`P^iKdX`0gEEQ^2BkDqrGxXlM9sif^G z)k9rLjm_DgEq9s!l2jJ1T~5&p_Hj0k_ZH(Iv3Orenoqtn6N(8YJ=CgwaK+qw7PX_I%4Xp)bf%<-;Y@GEM&=-r84>|1GH`=4YrVY_x3Iz|_4{-LM|+ zrF9cmSG{0pI*HeDi#nOIu@J05J(nvD&&iMqrZJabRAc8n*8Qj~dN#wrW}l;F0_W`x zj$slXlU!w{mFS9@s8wlBPL5R1^7E1=!}g$+`b@w;jrO>!vP|!*3vLZsNnTj?=oEXJ z911Nz_l@F;bSV#L0aCwpG-03J#G2tsH%Ho)Qhvtg-FskC4o-ns1rNLyE!}ax%Gb}$ z^7qv#x_+a~eer7`tI@i_78+avIven6VML~5n!J=VB@op9Y`+t>@Bf*!_zSOw2 zcP|uIWIa9TmcN&#fz;^a9qcWZ{~)|mqFuaVMSS^==!Ip6{6lad_OJEIJT6JkW1;p+ zx}a?B{_nzaQ52vab!>LF?e-lyxO7wRD9NjT6KQeiASsjZSSice6f@k)0{6T!i3N07 z4*7~A)p6!xx|}No4<(N0UefesNE}q{EuvkCot`ww625Tj&ybLFeC}%?6=^VnNt^k4 zu*|VF)KMncnagDiG3;0Pu$*96K3?$$5Xie__Y2Xzai7`1opO&h9U!T>AD@U#px!^( zv7s@C&*NKvjh?8}Ct*ClP57c6JC{q6cw8*+K!lI`i9_-G@V~F zluFqQwljLV&94~(c0WhGU=|O7$Le=p?~+hbe#@7cK7ad3kGgycpV8g3pa*~=+Qjq? zrj$w+9|FjfzTdvV`!&XmDPjCU%VGfGi@Dt^UKT(3RIc-l{GaS{N7_nOU3H(|!_q~V z1r9BBCGPBb4T0|+0cBO=n^qEC27O1ePG4SKBMQt^`J}D`PcsiRYl#)KXy3;EeI*9~ z)b2gjOC^3`Is3fnEJmmJ*N!n7JM3-Ga$>^eC60RY)8n&JfC>6Haod~Yk|iqAN7Bku z?9KnNWhkh})AEXHQdqnOW`{q{P7bun$QBX$F6vgYdR`;lT}?{YVXsI&TyRAuuNgw; z8%L7)jC71Y+NfPKEbp&o6FS{sz^GFy6(#j7^C!&j7ukAcDT_*)X#LY0zxKO$Wz2-X z>Agp`^7t5V7pA|2U{o55S6rT|^-gYNG(UZC^AX{T_cMIC$_rCOn+amEo<;c(NBGm< z?*Z-~^B=|%y_g$hCPa{WS`?P@M0h=JS(Kg>i_A4i%p~)87c2@`+S=rS`K_Q(bNClt>-&$3#!ima#l7f+b*01k-J|Smr4rlHX{CtimH!^ z9lk!LQYpb_9qX6dWi)J^E>G1vV{@M!Qd=P_p78MF2YFwdU@XRGXM-Qz#0|sl8Ecv> z)uzmp1rnCYty_qEvvM{RBx`Rf>iCw{U?q~b;&|JodF%JX%*7J^VLh)-DuXht8-fV0 z!_87);#_eb+<~l4TF1$lKdPuWY-S$Wx%N+z)}&eaZ=0_7Jp~sR_mPx|{9Ush5P}{| z@4FfS)LU*{^HgcyeIa$gKDo%;P^eG(^z7_qD>zAoNtfHa51_#G^QHjbQeRcqTRE)j z{9rr3d)GEtRH{h%6Mw{BvLD(jDl`-u5|FO#tw{B6)KD_XDq|sWaq-LoA4=TR_)X{- zwKnCJn21R2A`oEit7mlS7HI~0We0*QxT*#KDc2s{G@MiDnr~3lrql$TXUW~?_I+t} zXV-bl+(g_c51Z?CN*nyMC?~n5^}+@+rH;^(&JEL#mm`@8^`ZPU~pKLz%zwEe`G%jJjsvjOn1&k^rd0UYlRf0Of*c56~OAEIP} z!Wg=H+cThMcACfF?-bM$Ih?6*Kg&M2xhd>0lwV#FWdMqmo3FlRzOci3u#n^#Mkbjz z>i1`@$im{G)RiF!HO5P0VnbuSner)@#H?~~Vvpd}*&jUoCxeQS&hJQo;4>1;=z5J5 z-Y;kOVx_7qaZNX0{H>uP?&J92W*L#Gxj;(gEn&M}0|1)Gq#-)RwLhMJxdO>%&>+Z! z`=DwvJk;-Tkr!g5=Uxx3QJ&{h2D~%!@Pyb_FO}xto46YlRbQ^FU<-#6NvIG@b)0UN z=1R9+%^dGRRaaGMk^cGR;*V4>(X-R=+-K%DaS1elKV=+j6!}klwWCFRRxX}ejBTPG zI>0yQF`Dc~`tTjVxnJv=DZqg7%K_dxKYO-1!xi}inUGAp^CmL)*-Jn+TUOk*Q0W+1Q*VanQ`Tz3LaCS6csBV+vFcqGJ; zVw7z$jy^C3AjO#?19^Qkl;Aw1&Tqj+jW1I$k5=%!K`!Kp@9!Ie{OwGR_s*k6mKj zl8~YMGe61dan$;@@&sYriC>p}qvSz}`R2xkRN=nT{-t27x7)pe))HX#`qwLI_>F7V zo}ou6l(Y%?O8)q50G@Jl4^jLDk@y!zg%Bdkg^q|g(i=CxfF&s;F5*FF$HSmh&e!lz zy3EdQoz0_ClR&JbRW_0Z+)Je>D0S02Qrh0Kt{Sc<@Mov((*v=54n=X@U+MzAr6gI{^yXAMKL9{F6hHAR9-&wID>?b%%9|)0 z!z#**>41g+^;D7AIQ)DMMG4l3dlz zdmnD!1C{EekW)5`R_FOIuZOXz`HelLcb|;pz!bGb0^WW64-9@Fld8fh)Xeg9>2g8pwU!1@mZlW&3e zTf7}`rVnQCjT9O3KqMgzxS|n;Km_4AjVw*OZtv_|+9YQNG?qMD_W_m!19XA?E{TC`h2Tq!*!pnKem1UaJw z`ivWh|5_{XE*h-cZn>T-^0(cDk^g^`CiDeY$$3z{sX#DuWNxY9r*OSJO83wWlDYni ziwh|%;L(af#PGnM{n|7>FC+1bISMc%!E%n-LKhZ6g|*=TEQdYqnX?p4Vaq^!TtV1zf@8FocFN06c^fS5ctA_v??$ zP~GnzuW$L%-@0WeNBBYxyT`zc0oxu-dSblVddC!;l{N?>(R-^vE3i^=qKhTHxd>nM zT?GwT0Q6T)g3k|K@#|Gx+O7gJy3=oZ|KMm}uOS5Qu|SFeL?9yfnYtinObW-go(#>0 zNnZh|@2pxS1@N_A=5albmZjOKVRVm0`@2#P}$?;GcXfmFM74qd?zGGSii(|ALt?l*(9omRFl{0*{C~V{qZ) z=h&6v)b|T|N&kn4Qb}hwyZODTKp1dnz71s>*6{%hssb3)d}IHge-Mx3*chTG1Vm;8 zh)k;zGQ)luf9E%gTM)p+y_WjP_cnqj@5-{Gl1`AkdoW8&%k$RO)`Jo|s~A8jIS4xW zVFB;t+q8c(ro2ClR~A_cdW49tJTVfWvDeC&l)kS6TS@{#O`t{6Bvasxg3_{&-Ch(N zj|^9ZT;mI#tXN^!!e)|=MZsx47o6Dv&r?7U2pr}bu1GPwWZ++Z=89wla%l;)eQYVS z=-+U)7Cm@;|JFf97Vo{n@ZY!5P9@YC~@cn zN@CPaU5b3eCdb-$;ma&G3LV1Sw5DYF=GYy{UG(dJ|A-Z@tQaMsXE2=|5SS$@{m#rW zlhf0Qgr0B{5?$$WtZ=sD9>BLT^*=w*13#b&WCOrN8I<^6F zO6FtI()RjhROl?0JtW1X9mY8P&jOHFd~_ zIf@RYQnS$NEO|LdhSr(*#f0vo|L`F`cJvuG%w+B>zV(del!j-HsB|_agSGY_Kgckxs|HfM*%;BMpI#rFZJY!C1d{UdjK9NGWwQ7xZ378nWozA_n)|$)l4x z+Is@wjJKG#IX;c(_7=X5bw|yB8TeqmKt3q%R~Ug5Y->#VYLfRB(8d3n^AGo=X+t zRJwqNg@MC!>P7%lsx@)cL4Q&Dt5_kF;vB3?&o4vx@wvE3yS^`mwUbOz47U~U5$dw{ zhf+u0JWa@to?sI(d!Av5i==xd?^Es)&C$ae8%CIO^0MI* zi=n8B`)%33?jEtYkBuxF;gT}+Pz39UV~^9q4X822`?z~iRU4tRhV5;_vf1I3iX%kJ zz9`a=njd;^G(ReAV?ru%V5H4PaW$N*GX0~J-akTWwO0*^j>W2&$^*y8%6LQaeuch2 zev=!5$72QV=P~BCbS9k2)R4^k6w}BHs~44?{l*}Vz9jQ8-Xbkad+K5Yzn*GI9K25} z;`s}^8KN5=<;VLcdiE7zBiS+g<9fu2#PV$&gCXBfWP6(lq9G$HjYwKJq5$*mMw_$^ zab>;KCCjb(*ZV{$BNS=bQ*#n-ud=~vlD#n1Y>0lbM3RG!Hsm+!`oU<55-A`Hy6ur^j)trSYY*IeO<{^PjaR3u|DBaRwdm7U_(`{ znBQm2Z`tw=uGUM3wExi@M6kJ)$II%8eA(C%$WtZ%6YeaAdj?`aD--Yhw=>j|-uQNJ zEXG!>=8i&Y5K$i8PZhg%{#b_)mCaXBx~H8e3?Ce%ulF|WE5&(4#noIlY+-*_@CP!d z?u)q_85Me7KEI5li0_}T{wGXyb$=lbf?{i1`&D+gDq9qp%%QqU7$S(psT(Zz@O#UR z4E%sGsCl;(?V4|_bkcb zwGYxj4t$UNm1v9I4--b*`i}^VG4Y$tH{K#{^i>&^9oJWb7TA+XS2Dvr3vC>>ZY&hk z`BGg=t9}EY=vIr_Zv9ze1Br%&`-~VjtQQuA)RjGb+I`$=&gIj0Rv5kVcLMlSRelPq z;xCVVtT>zA9@izXw&SKf-&;L(5-O+ZA2&jFR*8_2Lv)$Jr>)IK_2WbrHp!x5QyurdzKMxVsGL*T`PO*s+@OagOK~$ zC}T1>z2Stq^7Iz^eGywmfSOprrPiCOe7rdfNu9ok*NuK;&x=}`Lm@QVbZmA0n^A_b^baZ?>YoI zY&|P+=uFxneKSIyWr|Z?)vu4rKDGCBxUK|e+mq*5bL^gIyU6xHNgVBETexT+UZ_aA zetpcFg&T`CqhMO~lU&XfDNv1Qk?HU?(*!PkFXo=taR9G{--^3FcB$0J3EfO_5R8~< zKP3r~0h^SR34R%%z283&H%nCsgx3t@$44p?-q%1XX8P zV`~vRV*W)o5goQD&aQpC+jZXsm!TA5GqKt3l#1Xh>j%&7gA=y#M45_dzuA(@0x89Di0Wc#kAE6i}HKM@f-fm*^Ri3uqlbu<6UefW0J zo#c+_j|>(SjcJ{+2=5WVlaXN5?NfLCM1Uw1&D>kL&Cx<~uU0yl#&5b#-jny@==?mmZ(6CP|2A;V+$xm6COo0D*kEgsweyrY%?jCF} zXqJRQPQw^opq68;G-v+-p7eFALkccthJ0B6Yg^1Zgxt;JIrsP5N=YPnXrssuADzK|9(B-kBpCd9$pTwUX!rKVeRN#ftuPtI#Jhyy+Sf;J#}3+2F3slAENz`WkXtVaiv} zgX6nf&f?3QMVq;Bry+7Ohq%FN?5Ya%o2Zb1LU5BJn@}N#(6BM%_=Ezz+HKFx>r(^) zvOA{N?@t@FXegE4urWmPP*&pc!QjN=v-Z6t-c~g)I~35$s~S04FsxZvyYCQCGH-$k zA_mvP_(y_-45io>15$A$-b_`AqS9mEK6eG=TFav?B8V)caO`c~y$@HVb6S^}Q5!u@ zx3DGlS#+%^+S$>AQcBKbYJhIeig;KOxU*UTRapu?bl1Wxat|m6usm* z{SR`<3({lL8DG!$1|bS%Pjf}3rG~I`tP2LKEmj+^!*3klt~#u0C;5nIv(G3ESCu;6 zL^MsKhd$3Iq&D~y7U1Xu^=J>ZfRqBq^+ByMGL0nT#+jsNz=)4df)rJ?&T8EPmCe|e zhnUUSp^n?-`!3tJIg6LrX#2!iEGa~69DqgIj-V(E+?8Mj5t|@tx+US=AWlUb;4*54 zDk`53?WW4Hrm|#Rm>r?xyfn-H8MhTz=HO7D9j;1tvWfcCZe12{RW!Y9f>$PXjbSmQ zCM58nzu^85WhIYmKN_njES40<;*s*0s!yue&R{X6ZA!D|_oz%CKDCtH z6Hui-zOftRNK?7Z#+V_whs=&ijgJL9NB{H4NkJlR^NLfdV`q+n-xt4EJL=E#Sq@|21IN%;@7UNH}CUxV22t;6U{@+v-75B;5X}a#Oj*}eo zKT}!bF`}yE8O3$E!O$$~PXh8*)sCy62E@h$^(pyS_tO0CVDIOvAn>tr)3=YK*sYrq zEAW9mWhwOiRdG&FnU;eY{SM(T`GMxx-Zcn<15HImHb|UbbkZ_DpRASK#Fua)2QU_G z};^is@LQ z%rRf|g zVMEmhP6Z%7ppy|d>h^wyIQjN%24{0kXy$;?T6AF=rIE9^YNKW*sEu9PLQ;+3-Pe>? zWK%fukJkG|!k0Z;ij`x{G{>?lo5d2N5`noHoDK(d=OIaDPjz9bj>JW_wY)w`%~1wa zJ&+W3b&1YI8-x2))z9@`E$GF2hxhIi?-qq52}fIqXz(+!&15P{eOYS9Fz+Iwk{M(0 zS|O%%l9f_iRQjvqA&qd(E%#TV8A(3mEG)FAF=)eddm%QNh_$?fpO~Yc2MM+>+uq;u zaI(1FZ%bgw4;!C^w%QWY7`49~t!mWpUD89A+#)a~ldM0ysZP#gwXEJ*YHMqRl4Ncl zSE|8ktnE78OjKeSdJ`8Gt0&Xx=tH1iw-xHIfFAR+w7>0TQHLg9=r0|iq1>TV$lSXnd-4JGXYc~pqQ>#OqC}BDR)MVf&gIdru-3)g-VQmq9Y<2;=!&ZexqwP~ z_erGiIRizKu_PQHfZBoB4FDQjCU@KKTl?dK)j5@xIo7Oal$|ahn33sN^Hsx~CM`8| zFKN%QS<1l1N1^>65i}m%1-V?ErIAUYr3yv;f!R+w90jQ=l~eQxMxQW$XP0n>4_BFvAMh3kEB?AUWr3dKK}&?a+nS^JHFAP)Z$|* z2A<^B`sBj=*|XLI54~Ts;us2t4a+H=T{t?!#QW2}ATRig_e!j!cS{G?&Xcuxtm*&> z>U;$)*lQj`crV}F@9yt;0fY0sC>wEv7aDx@u63tbvC zSBh%SS&Zt6s)z*|g00^z6(?}WRn;PDnhma1W|5Hm?12=-Zs1hMN>7-={ANRtaxRP0 z6sOaxocb8FLB@xmtv`A-G0sDddybqxPgl-_a~6r5r7g4`lkw8=n2T~m;f#jTcJO_q z3277cb6Yi}`}91*fb-{P-Hc}G&b_U2R9tAYJZ8(k@8ze;k9$&<6tG6ttA+2|5C`K{ z9MF3!%+(JHmB+i34GM{^J!&GB%QUzdC-KZX#fg@~(+Mx2CZ;Gu%M>;B@qKU}SS&UO zxkDpR;9Qd@lR!wR|IMWba36~CI*K0L-I5iJgK&`YKk?KMi}7WF57S!CQE`g66)>1@aHguKIwG|M$3%%Q3_OA9m|A;%sN#y^^H+{n_|7=p-N}z%87s_!<>XUC&(VxX;Q1Hs{grtPTf4ZE4Yw+skz5E7lvZZS$sRV z{4rfq_($k68iKMLbyJ%Gij<*#Pd0{y zS^7I?SJsOvLD)g4%>J>D1M#o|!H;0bRtsE|FK$vEUEd+s00YHP9X<-^$+HZGkO4wi?>y;-<9Yy(Zd z?T8~~DnG64=E z)+;2~E825@yui$^HEJ&Yct|?~VSS zL8ER#Gish62dlaFo`v&eU!I0X8N}JZV`D*<3CC2eUif8LNKE;BC2dw-QSp6YNg1)V zlRuqEsTL#Ti{r!!VsQevr~3=pPk zpqJLh1o`ROxIQqYM(x27QlKk*-r3@$V_|187kwwB#qo7h8(|oHWWI61*Aq#_muScN39+4$ersX+`HfIsj zMPF{prqr~9V?U4a(Yt?kD|6D3jOZBO^GVoO3KY$OW-igA+mkMT!a}Z%ipajmA2S4L znS-;mOyQ~MILG(?^-nsC(;^Kn@`I|$K_J5c|5iXDGr6<}vrl-PU!72SzY7_W7}&}C zAt@Ylu<~2-zqJ4fH^^yf1V|W8!vu!2w^W3qr`2_c?@?oG;%#>`Z=0z(6}v+B2(Gs> zC?bnh%t_d@e3mCKYL5}0q0}5l1J2h16Gq%EgE?j zG$jf2{c)j_i{4V>vFdz+-0wjbIiEtTr90LX`-1!y$_-g&j)OD>ur8J*?6hMbzj68@ z7gUm2gbXQ&*hLUU_*Z{v7BvcjCOH0&n4Gnnn( zr9_9t_T7z^%N^VcwmF?2Xh=X;IE=d8+tnC2v6(L#b+ZK$7CJz&GxIJ!V^M}Y<|mlE5U=-Pw=zp6a7O9wcF7OzHobadqqZg_Ywi6;FH|Ok zBHTVznnrS)l%Yl*og$Ae>_U)gsMSkmVI;=Pf9cFzQ$_m)((u6G)WJ$+5BJt5*nWFH z>40kA4c_%UkZok0}(=4ZiXf$lj)EG425IB;C2gHoas$%gmQXgO;JCy_TQF`ZhCB zk)wB{JU2-LzW8jCP+;w-3uJ3l_=`?_IlsM-sUBv*$YhIdm&;>sbSQ?X8&~&IgOrZb z>Nr^=^>|}vqdF*Jvl^QmYB30W?fJ5gu8wh6XP>^dUA?wQDv*BxT{Y6DPl7c=?6l6$ zDz}0SJfu1##Tw2j&Q34aZwAy;+RkmiQ8(|^apF@iX6(^6 zYA^42*?RC>1J=m4!}dv4f7(E}e11LJ>L_E$zBNM|?)9`zyMem;3DPl61dng)=l$X4 zGMOYb>I87$b%ZD%HV4^&KY3UBb;F_Pm{6Dub#)rQdBMBN5ohQG?QXBJQdZflMzgU6_Q@(A1Y>!t<9A2N>D~=*!aCN(cW3t|nLq|*r#^U8oHu-h zIdvAG^u>lCrT9X3%@8K$_g++5q1wBO?ASm`(~5ZPW^i}PNJSXS;jW(D^cVW!s9S{u=?6=>kawKZ_uo7%oSLpRpCy_d#(38 z%d#Js7U$_+jkuhbL{b)qz4I$ml>qjeCeu5bJNd~$u{`>F46+zfg?KQR_`dvY!4~!4 zyXH7G_gWo*INfo|UrC*QDkAM-`_gxIdN#PimSTRf&GBTrhc!`*Pe8rC+c8INm!^F4 zQ8um=k8&~}`#{9YnW=w;R&wQ(Rkgo^9Keo5eeD3+Ak;T!(Lcxf(2u~ReHrC~;^iLT z9g1!<8P=AHQxg)^yBaTDIa0u1gsk$N^})*N>Aq~#52!h7&~SQZMY|7#sR4lz4xb)Q zpkhC@x%nsBrt`JUHz+kuk=;#WyfS*Phh!k`4G`5sU1wMfZMoZBpes7*2extDrCl}F zMSp2w@shc=oem7TyR4>yjmTJU0$5`*+#l}Mq1t@Lzk{0(6EW>50bVddbbsgQ{b03O z%gY37Nr%VPJ3G9Iv#-0-*JMIBWDw`PRl2ONEgibP9@DK`>`Cv+3<%kJ3h%Yi4s(EV zodKbOYf69Bw9QVcN|soIn12Va&)d@BjlcWU%I&X-dY6~@3po`A*jk9#8U-{c@tN9{ zGHPcEjR~2Be|wP6NLAHQ^y7->Y0u3dXk64uU8GExGiKN*efRjUP@5#&Fqma%{I1YQ z5E56M$f;|zStvUU&FW#Uh-N;y=i`E(bJWjVD3bHx>M4;qZC#6`-`Jx1N1d=Yf);M) z=6SEGPEIY|{`yQoa#rzdXBo?q%k%6toN$95wS{UcpI;jk!WM^$XRTbyM2d8uexzOV zO=8hk@Te#OdIE|lggmE|&e1U9xle=c9B#DWz#muLg=H^-??xcBu$Ub)8-;TV#B@W= zNf?^RgT?FgqMkD1dslt+w~yfC2QeZ$ZO7Z6_#u`4u@YqB(;kl;hJM=jrpbb2;2Vq2 z&#nxHexw7BIhATVgJI4h2r_6_hKjR5e)!q1IUD^i=OC95)BIT>nsb9mUT%*rP7tdm z#6Ofq0nLk&3r|^gY=CwpNLH~CY4}_z_DAK}M|dbqXir2+v0U=mC1$M`RISAAl=8c( zCO+Mu2$w5!9F+s!=g(?Mg|4$wQh$W<>EXqay`M*^!WNb z13sKO8r{Rmeq_favPeGnl6HwT#y`tRstPJZV#wJPZli|B7vC>NCr-QWN}Vut4uYgw z`@HzUY8*F$KA)O<8}7ic@|Vq@3|0&8NSpJdoolvX>s*N{{^=ETE~3H0y2@oS6rSQC-s%+lKRBs!8A@VPrw3rpCl z9CplysIzGiJ#YKjA*k#HQe=1MWh$NBOLY7@dU4QYGIIF+-L-CMy*kbz|7AyP@Tt zD!MiMj6(wRls0Pt)@42BJ-TbLV5L?*VRD3RVzL-W`!?EzZeR})V&NalP5cqjyeqfi z!8)+VR=~&ys4p6+Ok_x4m!^b)UmNd)W`r58f9W3Rf&a?vbgpv8FX~wq6C| zSHpH~#0d)%1}2O4_Am zOREP}9MWqs7~=gMMus+?K1hdr3n)2hywfQ;^bM8n76(d-N9 zpJY0VuEJ`nYGZFgw;OOH{5CA{4k*d~P2ME7FooTk3^%epYtQg7!(yZMQdCh$w!T>) zZPo?9+M>J)7830-&MS>hTsbi(%Q5Q28-ZMny#6d7vLP&TZ?h%694p|9%KN3nw4Q*D zgu={4iLC2}IyS-Iq_EeZ#59%i=ybY?%*RS)D=A!nu?_oQCorY$BloUAF2& zUa_)@NVc6N7XEC_tOh}HQrruPJKxhD*#~!h8)chOM057Fb!YG3j2;hG*JDx_)M#j~ z?EQUKVDDucYqfl%3v6F)`NWCN%nn|XL>{mh<#+RbxWgPIqK9NL?{_bcG@PhLNQG$V zyc*|=duMRSCgGgS(!tSXt*bif7I0U^%YCNl*M~!CwEqxv`+#0I?Z{xaRr_T!8MPtJ zU)SPsACCU2A=TwZht#x7&cW}lKG#73@2%fvv)GBZ%b_a*N}lOO(_-wIoS~fink=vN zBMs;{X{f62zO|DGkn*8((odU`jw5`tePBMYSKH%?&DI<}vmvqhCu=dn9_+#B?3G*- zO~E&APs~}2>u_EtHz7;K>Q$rr21UrDk3w~I?Ac>d32xX>o;nT%TJa^|@iX=Ilh4^f zC;QenMt7q?DrxQ(iz;O$&r0%ZB`ox5?>ypZh4|-<4{@R zvWG~$qX?8-%|o%*wLl8JtRk*z(PTa8ADlH~NKs>xk32EPrw)o;_N!cn)istv(sbFHk@RVD15 zWj*Cj)#nyFAPxt=OyWRV*e=Sj&6&9{9P4i?Ak+dIRzO%s4N|s3GM>2R3B1&xm}4wp z091CZ-(k3t6rR`0l2us!T_REazq|(aNEFluKi;*}`0e_tY~J<0#Ku9mh-weP`3e8- zQ`qs?E?wC?wWHvreZ89_L(7`VCm%&KP(8-_^#a2VEh`=psjQS(9d&Ebvc0Zk?-L9ny z0g_rzBP;~5p3)5*Wr}5~=O@$cYra=M!yj*lnwPlu3OY{x&eqp-B#tVdKSdQDXK#G} z;E)FZ3B)5m_^jA5n?IhGvG}IqZ)QK3I$vuIjsl*U;4B`Wm!;PSoGW$Tf1iVsEUNf{ z2*#%38|#C!+lWbR*`^z<-4Uuo_zymR+%;Q@s=UfcOyNDMEp(yzL2CJ9In67DbkvIY zh-~1c@f!}!>phg!I-m$u`3kPthcax;M;h)*cQ$--;uwASkKH_$T^rZIviG_Zm8Ghf zT{K1mvJ19uNs8@J@x8nEThwCj)htA=dmb5<6GO^o(N-}m#CCX2Fg^`6FZQv#Tj@|s z^0PC?x@GYD>_hUd{Y)n8MdPM6&PtkU(9_J5%=4dt6>^66YMk6eK(tM>rTKxRY`Xv_ znXdp;uu)Y?gF1Fw;<((<64pJ*ymqJ^r067iA}8GB{gwI{sc(PL6x210G5dMC?dhD?(4x(TE}5;I6I&S-_l@pAw|pomQ%fXCC6UQ$+{ z^+GXH?}r3=8<6yv?7w2lbOu1qXb2V%pHup zl!Q;CZa*NK~wv*Kpf%vtEln6P7;m1cS zrnq$tL9R3~I8^-3j&wfe*@@*w7JlpFo%e%#Vsn1Rg66~xqHfl!$7-vF+*idyl!o7R z1IX57{l(lKb$shA9b<3M$f?#WQ|>qNTt}^&g9PIHH-7=uckm(a?!-*ZY5?}GHRuHE znyQxRay=^6^nmP5l`2op3)>SLV9yRnk*?8J<`k4V(5F&nsQ~`opNct?9l(%;N7*;9 z?~U!zTPS|&u_LDUuqy`^+}_ z23n@$$F;m%pyV6C|4m@G7|h8^$KP`EA$+0;42Rmr3{HlUblm#+$h}vwJ`nq*gpnZ^h*&jZ$FSWB1}8Z-?w2?Z zgAbEoB_LgD5qahFkPa!4nM@OJmg(Yf22AFh+Q1(05wdFgk38m2?Un8hh5qy526aHK zM%IJL+PD?r92opWMYn9;c!9z4B1`FvL>TuL?AY`{3b6oi5WB{mV6_wpoRe5SuVZx; zj{YzoW+&`a%@~B{g_M`iw?1v?<1p7uO|dX;Pk=Vaz5GO}7|`4nYAxo>V$O<|9aTi; z`VD$WpS$pq%nrQX$)@VMPXP8*!LEo-TFxSLMfM|BDv+X7B{vuxYn=Qzka|z5W4J>d zKRDHgrLTm?Dic?97F17f5P)3;+drX|kfYbJOgKzELMeZ<=TBgU(q~_nj=IUVw1~px z9vy3ET6+`dKT{B3X~~br8D#{?lBIDME=!rYE2pw^z8TVUG!O|N#rsQ%v^RwzhjgD7 zNsXvyh%=;q(kIoH&9|X6QDuA!G*f0*yFUsu5w+b=7MM86cs$&#R@L~Pal081$AVE7 z0ZEL5*8)kIHhUYz!L3zUG?cN}qj#y^hGobE3R2;ZSH~-69&`y2hyo`_Q_CX2XQYf; za&#ZKhi|0`O8rPmNy>0Ga{uz2806%V0=^#N7lqvxPkz%2fkkC7XAVH)_3rI&qqz8~*oP+rOzQ38d_pUW}&HOhm z7mLN&XP;+3`zfENoU=Qv8+vmv$@j=>qel^QM6(Ypc3BRj`~}bn;A7>Df5OnwE5J)J ziouJQc@3w`r#xNkf!^cZPfE$mVXgRtcTWEHqjC$E2X&{vVq}SZ9wPzAJaN!fzVqlf zOA|=O5#WpH(2zut-t7~frqpA^9b$inKXOTtw}c^CyKT|`;+@lxgrPlsArUw6=>6cF zEJ>mkFM6OwmONNw9%xvC(&v(?F*aodstqQe(pv*6%6sLra-{GYt5QI*KMZ_KUH4x9 zfXLc`z80_e!`{9=037R+1tKa zbgvZnR`zty0_e;)5Z1-}2&1We<;@D4%U^|^_~g~!F&_2Bcs;^%SD0vYW+-)5mC{0= z*O3O9zH^fB0lwbOyhN|PS@Kohn|PDbC7mVdcaX%v@BSf+MK;XdvIqW)c9=B%(Sx5H z8;S+juLQ5EFDoKmF921bkgasH!*R=PudgDcY)Aie(qtyvQZZ4f`E`M@QB4 z%(6jQ)o3i9K3FnQbpqaf@VyMRu%{n-L3@wAdOj=1=9Wrc_`|`uQ9s0-8gwivNIvaa zJ^_JAs zvf1oBp5Ul#=uW?lct_?zo<-jDrEj}-*36y~I;Qw~esCKxw}B@Ff3uOi&$MxB@?9Q3 z`1n3hwx+biUb(e_oC|=C(Ty1zPt;2LutTH?Eoh37z`kL zUFZ#Gn#rxs&=np(R^P=U=PQpqD2kO{ZBX&@6Vj5TwG9IEs5T3~moEh=N^@rshv75J z){gtW-7=9B^k|jf^9z4#OQZ?ZFj|1zgu;_6Tib!6k9a7vW`!&k8#%}FfgTpivrZe& z7cry}m+JSALG$2m>SXD}>G#?{@Ht5fai*$g@AnP?+faHhTO9dC_E{a#rUK!gt(oO+ zl39Jso0Q)z)Is8#us!`0RDNJ@MKtM_!F!{3;yv7NMPPxJ?Oz@Mm`O0wWIWxt`;?&x z)wfrn?qf@_n8TQgxEDYOH=b;GBi9?=^At?KG5+esmjOy1ZIu;?H40hU=ZoAU600>p z4=;xTFGu>-;mfmDnBwel?c{CDZhM2z*I8qYP6~{jYD_qZMJLzAkVJ98I}PE#HJd(v zEZmbvYrk+VdI0p^Y4#z__a*F+)IIGp6(0@!ulX)QtnS+$!0D!KV(Q*P>YMm2NG)8V z8tI6oFKjID*v&e8L*C~n<0DzG7CsXAeb&F7juGyH{3gev3o=N*-0J*{i6G4EN=$7) zfS#Zr(8fPpkhdiGE`0oS{j1~C(C2+ie1~xGvGab~yLnF-d4Y4#y1?n#x18>q+ss59 zgTKmCgump!TyJT$VFKE2H>jp>#gj9at#+a-Mxriu;;e zyClg3!f$DcsI;_Q99D(1#G;RN?p!UnAjhQObuFfezJ%MJ*sg;}w>Ow>UvKrY(l9E9 z2DLnWPe5&y%5=tpF}pn*@CkqQ5n8L-)TJglap8*$AP_m(Da+2Fcvf$ zQ_Q8q$T_PGLW24&}%2nr+;nWx9-in!um!ygdmjA|2E%2!u zw#eL~rFJ{R_K~io)8_2cA+GL}_$1<)9+Y+U&jgHtP*o)(`sz{!bs+u33m?X~vEjF# z(dI_sl>2*G{faq+M)yu+D_%fNTlQU`P^FwJA34QnN3OhYbV^!pBG zdZ)AJrgts(qt)stg1e?T{YZPMHxpKzO1ax6%lTNIkX#~lgYQ>*Ms;qlUW;Psw^CRJpM zn+bEH3`*n|d0Np>dns|W#lmNQ<~?8|k(g~ib>Gc(O50cXy8CC^IKhNPEE2Q-V6ye} z>ddx+$@OKs?4T}L$q;i82YFIron<^Vg(Qq;wby80AkO)C!Y^~ zjIK8n=A(%*8No1$<9Z=@*<457y}u6^6aSkv+1 zdN%V!71YYlDxCMWI8rs*d<3vRPr~qwVKusgmRbh-C8U0RHK#k9f$+W^Y5p3qJ9@)Wqc#Q&I!S1&SrQiSa(|td%y-J0<>UEK;HcpZ z4oXo^`!`2j!#4>qXw?}^k>(aO0wcaU1bAdekt)t8i2^6 znfCXmFCS9AV=N*A5?=H&AH{41h|MhLjj&4O*_UnyjjX;;)FPG_;j}9@bXeum#_?(6 zLgDeWkulU0qw6Vt*H|J)7sL9jN92jGIBK!^*C=Dyg%mj`n_>whdu^ckanO9bHZBJf z7diFb%p7q9^RD)L0&-HBTg3lVp)nrH8O6x<9`}uiw&vbE9Ub}9ERi|~*%{VSh$whF zv_XD+smogUJ!B_zj}+T1fxXYOV4LX0h@t?__$e)7w)nz1ME{uq)pC1986HmrywPC8 z7#4dx&L-S7Ce{_C58tc?Iq~^0I*7EGM0SzOoz%=Rz7R)lvRL0R=0=eAJ)GN}Ot=(f zmP@)$Ar)t3Fn6koEU!ru5#~%uiDx9)h8eP)a=hIFUuc+AITn!Q<+hq0WdmcbHkDLu zu(XV_%>`lmd8&W--5onL-KMe&WkZ-_&y=b|)R7%aY<{8OABcbX7mm3RWj}=}xhTw{ zjW({8ggqaOuQr;X!#=__!jvN$2f4)kiu`7eCrFN%@#RVk3aJWlY5cF9SF`aM-0#+0 zo1V&WeFU?7A8vcd%9&-})+)l;NHPNmg4$%8Hcl#PV^oAxgy}X)R7$I5L1eu7dQ(YF z6|Mm^uTFJMDE1|Yvo;^xC;s!;Mzl+T_6`m3p7nSzZ$9pqWe^xMMIC2k0fYR$=_5Ik z)c^?y+JS6QqbNev2u|2>DN!FU%lTqq=$n5y9!6l^GVY0R#!)%or!YAmmr+pP*Pff1t);?#|t zfE`4MPV_UiBzaToi5y#hl{I+Hg>}TPcivJYt7~f8<{h+E%m;+_Jp$|&G$PwV9!4@& z|8_eh1E|iwf5T#zSzXKgnQgSW~`6kf(K8X8a z(eZCmTN?wnG(u$+?rC}415?X+gIWJ5<_pV`2E3`)$MorWwi7|~`R%->>IKO*FH0|P zthj%-{edHt2!>}n9(A$K!a+_Nk)DsL4x8(v9DmO~Wa-dnXNxxP|B-2NAbJ&}REqJd zeP2Z=@v{0%i=yDB&7wZ$3A)m?9{~4#2=}z;1a$?G5;m!-JBEFs40+(k)LB$2oQ)UL zaK%sIIcso=#3fQG4zbnZi1jCj<=KCqk0q2`1LT-RPT$hb{+jfqRlNt#cO-T~w@9(7 zVxL21Rd-O;H1Q-9T)Au8Ul5HVQJBrhSS=UpdtZ$F7Z`C{r z7h>sAL@jW9kawHsFJMRKf|JHghN%$OiUHE%o-^5w&^OMTybvb#zJy30(VYX{{mg6LSov)w^Y>ierQ+-hWD`HS8?FnYm!axYl&hI5FRUu5 zg6`!JVh`UhZ@d_&k$Y%wIbSoTSykEs{hmZ+HBs6ab``04a?|XJmVNP?R86vv!W`0>ur>ZQYdbzQ_bg`h?t@W4qCe99r>Y&*$HNJC~LTVN{Zm zd{-=ssn^D_!{d{Ms?4diai2i*w3vF}JR2Lp#nL^^zykmZtVw3!Ek2vo%SDCyp;`7p z$Al_$q`sW?lZmBMxaE8+EZi*&>I)h5#BjRxGV8#j0f_S4v3=bzulix&5@}KG!3&Z% z`{{?x;_-73b7dBbyT(@3KAP}yi1wPMNh?mAYScQKJPMWn&^2g;?-t_60++oIXG)~W zw#t3lk_)zxf@nu8(lGS^X3aZL2_0w_Srebdg+{*W??%{f$ozzWm&2QCnzAODeF7eY z3*Gluz~9#zS&y+8LP=vjm`?;DV1>6V=_DN$;gpstZXO&#t%YE#UpYt;q7O%n6|XjZ zju9~P+v1Dd5&kB{WSdWjt-={&<4ikzjcR|Rb)d%_W0d>ySg*Kcx_%;*A#{?xkx4uI zgPP?wGRp4JHb?yd9pSVJ_f@tw6_q5V#vK&VToACsvOZuH$1~?1G{QZ|HA>1aS>DwQ zgQmpCrNoEpc+}q2#;IxJI-+<7;%xW4&`J2#=+DV>kQTafuJo15>)N;-%v^moS}~0V zMFHZJCyBw8ebC~~#n)X8V0I~%-a2xfCB>X3cMp7-&c%OnWH-9V?rSdpqWt+$0f@7Z z#4c~=*%Uw7bQZo&skLN0-MNRPk21i0la-blYOCmZw_fL}6tRI+{a1fXa8$1?-X{GS(`dy5|i?YtiI|AmgwhaQ`(UUt;IDom`!5 z@tpOPEnNOMOC{l-QWB5hlIY?fZlY3nMu@2_-s!Z&#?>`OhQfdav?f4+Hv{6+nI1>4 zQLCU%Ip`(I)V)Zgh##Bd_RQK#r(Zeu5V;N=QndxBQiO5sKeTkx&*O?tb&e;WrVZm6 z6E@~#B+)7W|Il)86$e79&d}!IdNK=b+?82k`=mXTx$YoW`QU!Wk6=k>yeW0bcz3jk84%a?k2KPdlQ)@%HJ01#$t z!+l8{lD~+SLzgtv$qY6|2sCu)VH-MhLno7o^e9mvo))<*OG6LUXuucItq_k?4Ar3yb0x5WKtiT*8zWz8F;YI+9| zb+S#%m$h+LR1ri7jPx_#7`b%{3T!Y0w7xKf;X$gGK0xf@>rg$Ka# zm;xb2F@`;Ii8)igY5A&K!iF$sH}wZ(sZ2KEYr!zTR;N_njnYVYg{=}M3SqYL|6~e| zGLNsB&M%tt(aN<-#`s;w5_A$2CPU>&S4C7#Oz^==xa-90qJc zhf4hr;`5LvwQ@IAt|A`&BW(^6DBCn1b*Oq^x~k*|702jYWhl&I$I$wYzm1lcN6IP( zFhgEBH@!gTbOLe0OYsPGV%uE21vg;VjHysCZX|BiD3BdV&A)lT` zO;OmOn;SW7>D!n}Pna!S;#&ZZurB@%8O>=684NC`Eh+&ywSwkHqoxQ2xU#~y6ToDE zirr5+gLLz1=usj6SkBAM-kDt=tNsORj1*kivz}@vln^)bIac%7kFZBPc1o=Fh@DI0 zs%F?XSiM{#+?A0DMC3l=guzb>k18QiqEB=0K&33Cv>`@z+siD;XAG8gOE|zV&!*Op z*wFA8wT>?HMVssYTwp5A?ie*B6<&mV66UZi=2SO?GEDHjbY7)7R&_}IJ_bzKNC`6; z1s@&wW-X?59!?*8k2dT&a`V~Pvnzqo=8{Di?7C6a zwPysxWJ!=zyEwRe>FEu4`F;4NKK9GaU~zIRGiH}dfGTyZQLF;ZB;A%?{V|!4dPCP zEkk&TNEgS=F?1gD2}T~4LbdXb0rK||_f9{!ouCtujIZMhA~q29=*-8^F7Fvnbr8fT zn=d+6D?KA1S+DT`2UR2ME+ID`tzQ28%Gtwkzcok>ZT|gXh_*T*$t@uQNNIrFDs9R1 zfR7`0V3ynxeuv^ar75KhueMNH-*Do7n-^^!QghRUW`-^-2X~lnFG`rJ!X1>;8VS&$ z9uDgcQNQ7fgv`Y5_Z;iWHW_#KCD`1!2fzt!T)8%m5%|17ze5nDU;$HnrWnD6*MZpl z4Fl@*{b~J>n+FL0K3dGgu!K_fS|o~SMKImOWrce0LBSkk^lFpX4OIL`cNdzuZWyQH zs6$Y`*%TbV57_$HRA)VdtJ5!?vlvy#tf`y$I9O^ca<;G8|E|IbmD47J=vTf_Br4u7 zBDmi;$?)S+nCYQNG-3oI0bOWQI@)ATzkH?m?Hej(x)yn4xkP}h7>G``N$hTP6v#cQQRQxH~I8ye9)x;0pN7Q>lf_7l}|kcJGtzO9d_RS zDBYR*&`);CH>T=twD5-Vn390BweGKB`OXn-Dn_;xFm>z?4IsmFM{X)s1O7F@#@ddf zQbrrshcUshxFz^|X5F{K4o|ctO#xjal^wOwHFWy`ik&#)ntyzGIqluWVoLenCX5x+ zWMOn;@?MZaoq4N3W!IxK;p_4Bse?Yo*)%+aP-$(Gor_Whv> zfI-_8l28}}G;m?=@odR^Zf)o!IZv*07D--|kx7D{?%l;;p8Xq^^NnXKt41ahtvGWr zq7A&z`o)qv_KTNi-yiD1_{eqe6qpHy|*Zk6jg z5Ik05w4xOe{2Aa$gD7pBZe*#$80utkkSk*JL4xr$c>Jx%S`w6C{5q;4A9xGayAT{` zm71CxO#;9yR)>$e$}(iZH&Q@c7-dH~yH~NW*;aMVwT@8_shN z7Y&;4z*N)oG;k<{`w5t-HZ{O-x9#}T@O5PaT=`}~oJYi!uykT+@|r};yBr;-5g1e? zfO={>CAExe-LGSmIP3Bf0st>k2p#0={3vy~OCd^zbvq9T??g{9hOh`7XitKTp0o_c zSY8&hOs9>b(oh)r#BX;L=?ByOik_Gih;n8Y|t< zf-bJfCFTbbj{*S#sz3ZNjW9_-Y^vv|v5%bmft>##Xns3tL%n^8w69FvawpghBOV>n zdUWe#lYM8Wa+kstKf~Z5R<$5Jt+CIy_g#2eN+=2vNbG0Rsbj3yo(PCf01@BY176xT zg3dwcg)vcN`PBe{{#Sq_KW6a}qqqmzwwmQ1w7fN>Z3+W9>0%Rg_%R7gTU88oO#2!q zC#~cLf~)Z*VGe*X$h4zzUgZ(F+qA0FbOMyvf}u~B$0 z+FT4PKg6~1+~(t50N6#g3QANc3O`hAM&zRT+JS)@^2JD79dmcC^(I(z9#W{=SIQ82pdYG|E80l+tb1@yH z?Vmtq;Rid(R6)(9#SY5S<_U97kltr5Fj(WO&$8XRM39`Ftiq`#LkC0P&qvVV%GG!fR9&tWxk1{tq|dHT0LRE4FU4=m6XBp~ofiJXJEKC9$V)gg2C8DOe2IIU;F+WOVVv-yE4K^OaejlB?z|EH|bQyX_3d$~MRHefq;2`_EZNDHy}sdSGULD52beBW}u9~kDlEPz*M zk+X3NRB})!NJkBr18xqKmiLYbiU!SVMqOH=_h_n#o`Z}T@2X($yc4j~6XA?ueu9uE zPSGtwrcCN)knFBi;og6$W-Vw5om*LEY)9ab0!>Bgl>61vd<}+hS@I&{2vQH;`YaB) z#ukXJwMbki;4JR}>9SQv)11Rhi$Ad*I|=`zUU7gCqmN+VOI;a6O|O_-*Jyf{2MF%u z1VLIb^#NJ7RDBmK1GNYwGAA)7ZY};Mm3mfuqYk2c zdG}b#5%Ps_XcoNG=3jAak+76M;1|U}xn*z(2WRhP1>}%A~etQ)zr97?}NV8p${Plj3un-9ctKJwGfmG@_caCk!tI8Q>VkV+EeotDmLA+nN$S)@{jitQZ5 ze$&2sn@IXHqBZb}O!X;|g>}T_KNkFJfo=&qvdgI;?VD1>W+SW|wo`@{WWTI5*S*Z_ z3g_~pM59r}IQ9`U5aR_rkD@eERz5%$z{2qq41!VjDydo@1kR5G;2cUFIg*Cq5A|ft zIm7o_7KD?9a;Tfh`ij*;emB1Bkj=qi7l=JBYs2$)AKAblH-f683F)44>lvhN73?Y*Y$7;xO zF?Y!Fl^wTQegVD4wY-=4gdOD8VB3l_lJqfMm=w}ichwQ34Npxfqd`ApKzRx1c^=sU zMUv;6x@K?!e55N$E5Fe_q$p{z&)srJw zy~ij$Sw#hFw9>cmSz&P zL*+y4;6A}WfhytH!F(gb($=s<4)}_PBz8t_uw1NZRSb}A272H!nVi?Q5Va;$(z~6b z{7-+Y5>BsSQg%9HZ~o?6b~0oNNIv!hLTJv>E5tw;N0F*_*i$rCIi<)^VWz6{J*))p-eES&n4?i|B}t#&{Mymm+)J z7;gxu9289|IsR-O`>kuh+O6X*5lSEKu!~$N3$|URQiHY!oM#Gu-6cXX=x=9j_~*;%tx5Q?~<^q|iSM3J?ZNu-Bu43F} znk>n}Vr0gbr@xh!)PO!P28ja1K_7(GmI-;(B?YpXWP{Q~y2i-wz$zmpGs8kg&y-AV zv@7JoKE=xd@OpovoHiWfpOZ)nmv40aFH0Oo2c+rqZv}1dq8CO?laX~R%cXDM{fEIV?o6rZJY(R zAI?a8Eq7-r$8JVUx*d_?&rZn21P*aQKbPqPbB>Ib6XOA&9VLhyUkpzjURgFl8VXD7 ztC5V>ihZoacUc;a84---$&x|ZgLjqGFu*;)f8#)I=0>8k-{2s(D-;&ze=WIADslcd zNG9>CKLg=ny+pd_SJPZ!LVvF2>0JAFntV?C^Bal>>Copln7Vy{osMbVfh!r?t&*Jm zZHGeZe=zF*<%j-nPG@dhe*AAQ0Kk_2;d=g;Q+t}Ol9(o*KF(+*yQoTLh=^Jcw?Fty z&j{;cp;Q%ad&S}~&LHEY^>Zc8s`ax=1h5To5JVe*+Yu3~mrdirP=|Gmx)Zg!a5aSW z$at`DV$6vv=5b@&^pL~qPnA+r$e7(Q$p@V?F6YZ&mNjT!VIcC@NlijeLs-A6J7`sv zK2en}U`lqzPn_W>ZruLQCKa<%SlE0|UhwJgsN2bTIIjG_P+{}VnAbzaHBq}=_65wJ zO*Iw;(p8vPh|dDOOeh1w%Fb&-Pz#fM)b1P8p0~MBgT#;7r3#+Q#M#4r0{db%j!Dea zd217Woo3_b9dbE+SH65%mHzztkG$j=bJ+W%OT8nz@5k`Y1LquCEr6s8zim<408Uj1@O9dh$$>?q5Z7W)*1wx<{@Q% ztZz;<$*NOJ#Q(|J@RQ7E%O*&*CvU)Vi=CETE1et^E{mc7W2#QCP6m zIfm)P{1qe;`|Gj?ugCqOfcQ(PKh{p|^^MScEg*@a#g{&t1*nFR^ zY8h`|zkaKeM|H1;5=9H7$a{CwZ_|&WEZ5lIIGqav{SPVxO{lYCPtMS!Uo0K!Qr1!G z2g}g)RmHhX(|EH(-4D?#=4-#=ddpkyoGp%m!yYomR_QQx_#?-}IcUU-dj%f@HI}tp zl1^~{4$TRisr=8t;U_{qE2`zCpJtGIQBaeXfBEx+%Yw~+B%xfK!_so%SLa43lT-u6 zMb)Z(|L}|%Mi$h^cwnnDxOHlO(-6ay7JNoy(UAT zZImB7_S%Z0xoj0EbiI>djCVS~k*Yj;tEa&yfpXnQ&$GFJ<(8kj8uq zuI+^$j~O)M#Fn3hex)6~a>n^_6;ed((nie0VrSX=pxS=M(URRUyR&W7ZpILmI{uK3 zOe=LXH)={N#a5T7?y{d>ClO>a_;`@G$ zCJYvJtia(nKP0_QC(rL%wn@a4WQdsI%HFCpKSFA{?eYEKv;{jJrhai1KPPs$kq#~9 zdJsFtR^?^?sHcJg^)3ZfEjHd910+V*YTW*8X5O?5a6&}4@}tzQKU|85kZ*9ZF0_TF z{TftV&4;F)QSaFUMvE1g*yeeAAwR^Vw=Gn1D{B>6L(_Kt`xsz>N;{f|6>JXQM;0m_ zc7_sE3r$efIw4DZyMxs_XObZ23d^qn-CL#k!xQ6LKVaow-Hlgixa9BKhW2mdL6If4 z4Kcui&PL}YD3X*q)?`xY^2gb95Vkmit4BWW_7AK8{Gm;M)ygu5%}1*KmFnhhW(&4! zE^o%zQVY||s;{g~x9gU9s@`?)z~;Z}H9Oyi;=r>RT@7NOr(=iP-5f?K=CiVXA!>_D zE^E8#!Epj71B6abuhFji;t%z&pKIWb6tL+%e2ti*WTblQPiF91{98_s;ZHtDcf-b$ ze3QR3*PhLci+`dT7}R! zbT4Gib{7ji=S{yXJzLf2^^9`C9=of@E+?%Bmr`NzlcyzO8y{@!2d z2F~Y-2t4wAqB5d<{_*2*s+W##a!pTgDE)+$AED#Dqrzvx<*qlHfLY#P6g2vuntF#k zEjzo(L(0`_g2PpS04DKLz5LAgVninh>>1fQP9}l(?P|*iUex`j*9`D zZk2o6g}UY28I4pq_tH1&wGyJ53!kxnXRDEz9lIT$r`XFwSD2a-rspwL$39 zlO;Z2W#VYOubXPvAMZgW9O zqWK~CxRadl-DIKqb)lp%W+s<`r88}`;H2YpFy3}u+Vkokm|_~6NClirNG_Gj8$eY0 zq(v=gBw1!73|7u?Zajr zVB>FVtx>d4v7+G_EWO^Oc+>}DUpF_f3J#fjyzq>9H=TY}y8Ybr8ZQ=kz^VbCv7}MA zR5q68F|8l?jLRG$R@iLbN>(#fkyW#WUVHWK$JH^robJ<#;J;Q#B8?86bB}V-ny;oD z)j+PRfpm#aa{5fVz-XyD_x)t%|1xuK zesjik-z_t0>#7&|l~@ea<#H{f{SG|#M|u~kMoQB8FW@&tZwa2{yRS-fSGLk2drk-Q z7@ljL;XD7QpA#?*hp%w9)_@JXsW2+4RegH=W}T)weeNTBn_AyOIS&=Blz96AhwEw0j7#f4T<>{hl z1ubYbP5!e}6^DO(GsMV+1i@B1tK3?I_p4g>5?RC!13ND;NuE&X{M zE5Lw!#a;GugW_LdR8GqQAQ<%F5aL4 zRQ9hNZ}M4G*3>JlN-tE&TSt5i4h`y+mGR~2sb~Dr^YlPBnz8Bd&>okF{=JU=?S%%! z@|QdT(|&+gfBP?Aj9(C~BrnK>8mx*vnP+75o}eyw?T`GxD7M&fU^_HBoF2vAE1P`? zzpKkRz9el@`&4i*=GIpu_JdP6xSY% zc@`2j?pd`Xp3Zd@&KmAvZD=*_9PFpeZCiOWYxKWv#72fCv?tO7#c*NxY=eYL`^JnphtD_&W(^uS$2g=e4e??bP#6IAWtw_pizM zm#L&p{c+pHH1AQ7)%MhrA%?4BTY)R8bK{?Zy+O~!Z;f*UKOYues~)twoe))d>b_49 zGmKed8Rr34l+Uk8cM$&WcFa#=JVYMw(+V!O6Q7uUe%Q73EG<+k`h`63bAHiW^fgq; zk*sMY6|H6@IPJgnL(2}lbTzU{~-~z}0eT*GaH4tUP#d&{iJDd@$N(WUFezU~basvc&J1&&`v*Z;n^4 zR8So0KDKO5?>56EMbQ5a^9pM8==hNozDiwp%CO%-@8ED;v4h>ad*-R0Ja1&$-D_Xl z-d47=?B1|`s-H_jn_hEzJh2!9U0dl!=0(Tz(r>76wuJbG?l8)Q>nJRa4IE^lIFY;Q zFXm%Tk9}6|RUaMPcIW6hg(n5Hv|9VmNAq$~PPeSP^sBC$%eOC7$~XPqUTIGqFy|Yv zY(zdEIcKcL0MM{wM@~7jfRmnHQv9i8$I~@z+QSs zi|(2uN4mBEPaYJu_SAd-+#^2q*~86^z(V<8(l%pf6MsFQSZ{y?p~=|cUN76)B-*5E zAE>a@v6e0VqdJkFb|V<9H&wRdr#B^)<#arDyzFiUOq;VRy#`(6Qw#0;9lk<89zZ<3^>T+$!Q=rhr5ROn zQ#tM}b_f}|l_bBL#aqMB|9bc%mw~3+4&RUJ56-X8dEf;WMFdwD`=fHgPp1mi_WZ2$ zVC?)%e7$4C^;|~J&Yz6Wxj={dW+$;>F5e;zLAJ4hmyOe{kmr}Tt($g}aJka2rw<3fBV5nGGSAR}J=g_L z*ztvat8W|5-ky6>YQM0Yp#FIDiGHrrSDLzITtc99*zRaWvQs8xYSSQk!CW46}Jc z1Ay;TMUF#f*D3?AdVJ4th1CBE(u{52>z}@^&_}%D9_q=|Y%e~n4tR17|25rq`P2xX za2s|HJ^cXeXau>{Jo8hwx8l!@%j9Poo5e7CENiy%Cf(Vgv#mBeW9C=o>!EE$Luud* zAiDUXILR(9b^JLs{t<36yvbDddr;pY<}L%@t)pRhASJelc@bYgIC?sa0M^`=C5k9?Nx zJxBM;Y=FMYez5Pik!!v5uy)KZo&JN;aD&-VcLm!fd%bPV`%R}cz-;8V9v@y*aJ1u) zFQ}HQ&1A(_a=Gi5-cAI7+?km+Mm?{gxQOYtWvbkH_zMeum7f+G9LfNtt1f-b1(+ST zU0W$TYP(i4JVLS{=khr;--#_E#@h}7E?rjq3jRD&09--${r2|m*y2KFMrm5`b?hk| zWp>zoEJQfiXt$w_D;72UyLON}jNHfi4HU!b(&aR_M%)eTdQb=J3@Q3X6Yb20Wl;PrTZyyjmrxvj1RJN6w<0=CSXspzF{= z&vtMz2Lv!X=vLO!Pp4aBEa>fB?&;r$`3W0g3V!B6qg~v&rObbMRdhiReMmL5)6fAd zVl>YYNO#3wKI$e-@;E*f)oOcA(UKu}h%LXB4fXp=u#pgn1dMbK_H@_dc>jp6r!`uo zFZfH&oTVwk^+*@;)$X&AX+-_HT+rcb`i+e`dLVHm1AKfe_nNP@f@`OzT-fT;eQbU7 zdHQ9zRE))*xM|k~-4TULZ2p-Ub_;RDN4MzFd65MRF5&^=L$Qk1)Y9jt6^?AjUVS+J ziTe~``}#guT8H0L_FEqbV-dB4a>mxBdRhSc87Pe2{Y&P(zd1gN#y?@k7^LdQYKr{~ zXL;#Q$z68vhv%nPgD;2u>Xq@*gZA54a3ZD!ef|lUz|TFbOS|wu*h7 zy)pJjvrnr|OWkV7`MnikLSZKt091OgSay#)N7*{)JhwQ!BE}A^=THcUFMwptWQ|pH zCR@yjX782vtvz-mxxdvWtI?Z_lhraR_fO&PlKuuP7>a?RX#)YE z4h1)j1pxV2)>I)DK&0mKon_7sDjCXt#dYU6L>OI*U6tNbpR`aIp*jb25x@vlKLuJ+dh^m;hb=lkjAxcbB2cb_Uf{m)f@e^cP< zIh>uC^1l7RD!b$Kz3bnEMy8S!hD(v8?^rxTvAId^z5%0W;%Z%^&{15b!+9L%zWga& z?=J$ils!YB30(KWti%8__AdcDkDOuT+_ui^<$k`NtL2r_QjO34bG7=B2aH_i3_xC3 ztuZ-Woc1jAS(p8=rC$5(Kg=pgOk_Y40r5^?4&6}U_rSg-6RcuqV&6tq3B`Y-<>x*T zt^FiN(4Hu|dv`4tn!eUvk4td-ZCxV#pHce_moX$9>KCWC-7^|&Ru+LD3Z47q2P66J z75}w^v87NzU8(1>v>$nE-A?P3y;yRT9js6Ni!%YyI=9jAZ%ZY>^9FX6^iqCuVbFlESQZ=_OtNVRTsd3GlBx?#ky_ z2thp^`#whQajQiO? z&34B#{&1D!Pt`(9Yn0N0Xa(QC7eOuGPrt!mA>XvbCQ~6Ua<|0hOc^_m;{GPTfBgd^ z|H5buoEyB?rFBrEd#e&)gX*MR$WP-lSkp0l4HzgI_-{spJH;B%mowB+{-5H>|FYQd z|GXCS|4;Y7U&s3Yig#6jfqeNH?Zqo$Mcthfa`4Vor>;k&_4-PMc6SqX|>mt z%RHuw=ck>=c?A8I_U^<)`N{-ei2oTE-f<=}Ab&=ncRFD~++of*$oU>s5uaVT0NQes z^;f!S=ci=A`lCo(nJV^-_>~g21T3?tma%t(3i(QfVrtM&D-mWB z08=f%@+r4_DL-?IHKvp~&$rQ#Nje z_P8wRUA`#M%2!VlX(j29%W3e`HZnaD1bJeBjy=mJZmKi^^5!dt59ZIQr(YP zsGMt1oKl1ko*iMiZTU`5+U?plHm;!7k_Bf8;d6EE_NCej)ulP-rP8x1oLFxKo6kBM z`scf`G}d{T>TC}S_W2bmlgq6;*Xq`$AFgnKFW6S8^MqdUkbO5Euxxb+Th0$S&t=FYpsGJdM)dIa@Dm=ovt#&7-^qU zn}2yKZRlAA_N-1>%mn0F3wqL!Ecm>VC+YkoD5a|bY|A8nt+T9H0P(WgcKSzZRJ2vf za+{VsLfija91s$0;`3tHfCNb2L>ujHtj&u*HoV=B?A61)p&3kdgcz#Xz$QhkX5hmt zDe75vZIaCkr3}G8)$uey*6WXIH?Tk$;azA2OyssAIVI zMQ9*6D1CWGo7?u}v%B?N>T(i!r(-PT;-Wa(y=N)5Jf|na?)xXazAIhbPlO!IZ~t*c zC7+lrKHJn%2vDvPqux}{os9O<@UKuLNhH}s{#odo`>^~;-WJ1Enk{)hbA|aJ4%r8Z z-=DV-%3n9)O2wrGPYlj{t9FTuU5!{^s9{WYO@fW4+93=O)D0Et+X;01N4>~7;yI@c z6;Ym{u9b)cZk9%pKM$Ad2cu1&kG8P3JT$t$;U)inle?Dnk*7)Lg6H!s4m;fSNAkXn zOqNU);>vCSkA>&;uB>cqY$Vx4H4JV1z$8891+a4hH)+f&ZvfY%tFFZ{RZkA7eE+i% zL+`^eAj?`j@vLJ7)#5VL=^4rR{oh^yvyq=h1n-SW8LXbWh6tm|8M6I9+WXG1rn6^% z)YVmyML-2XU;#S*5TYP8flv$~bd?Z_fG7!_ zXd(m%#SnVS{{-B-_tpR1eRVI-BR+nUGc#w-%x69`hhXntAiD}BIqHwKvm5~r?vww+ z^PtA6xphBc6885S3z>kyWBDF?z?>OeM&#uEV61nhQzNHDsQeCk$$oWbdHEa}@Pi5&xymrvcwIeS~3 zQP=3(#n^NB4+n|t<(@>NhYlKyQ0?lO%JRywp13ozBD;8bc+MW!6`Pa!GGQf;8ZDxV zT0A*C{pnp4zh>g%k(9~W4+_n(5sjh(Dx9cJqJBu2hSsOW=nF09FYhc3lzKB^lPSG5 zh}1iQXouIHd$3ebvnYR=87vbPP7XRMkcgy8Zje<~7WIlqyMZ$3?qjEJnF+B9P_ZjC zRLotkkHMl#+JY1$olO!FQ5V2so_e{Thv!w@1Kz)LjvYJZbocIA zdE4s4jBXUtG<@v~1Zn<9ZkkNk7+L^s-x{1W^*lDpbSpZ_RKs1Y^x3`w6C(a;qo8o< z%V>0LrD9`{(lIu#dzh(lsq&PYGBH0RvVU~rzQ&iu$%%UdW;xNkE!r|b+sR)rkBv-B zT2|Q%`uiumikB}R;pOcM-=*a@aZ^XsqUA_NvX`Y7_8=L5@6g zSMfk6)bjcB=Ybp9-@bhdViARN(P%X0nx&_4GrL;{;T+x^OO0LG)J{mx>Ig1wCqJNm z9#X->+k%tYFRJ<%|IRw^H0k+70mZ>pH@d*pyqtFN@El2bXyN4U3Gvj)dyL7Cj4}=V zgVyw1fEuJk8=KR&&FTh%dTvUxu9@l~Huea_XI5nA&m%%sWcNl}b<8Is;r!vJwv0Nc zXZwADo#wlDp<8F~bhyc!KjnPp}Ak451KgR?Lb?c=M#MKxuE4mOoBF zGFY0XuXVVGlC*d^1uK$v*bj1*hvy;mfc4&+({kwe!sKV<>T@(xjfMq9t>dhzw!CyD z)uct|dsF=W@~|D>3gC>j$!DMbcNo-l2rR@|0gNwaLUC-7!(sSS8w5Geb#X zd0hlP{M=o;jMm@^4;)@kgK&nnITziJ8=3i9@xx=;^`Jyq`?UOH9v+@kQjR5N22e|} zTQ{U+ohIdjQLCRmlZdRSFA;`tMU6`$iWjpN{fPJzC8NvPQ6o7P;~C7sobswucaG&B zoJYjtUc|sErGPBzlq00MSXb6PyNCMZn5cHF>ik1D^M`XXESFT zvwKvsbivI>U$xk9@XgyF<+_e6 zJYc$u(x3BhjP(y~dHjXKUoYN7foQ%dtz71Hvy^N9Ju!$%4fYgm6Dc36qhn;Ozu|b+ zDd>XJ-OEnS7o37LoECgCgr86c12oNN29J4%2R7%Q=V&ivO;)m&zPE{F)!(0?&kx@n zet9|*?6CHpm7mf~OlgZ9>rdwB-IBSpqqbK2Xn5+zlN^oZVVcp#QfA}fnamm|DEpeO z+OIr3e-eu39gtrJE6(Q`{08Z;$&enc4Vk3tv3U*QDkqM|iin1&c*N@(*+!>l$EOoS z6;&MiA#Uzzqg#EWHGc0F6FU1iwe?C)9ph1v#!oa|)qq2qhs-v;-2lEQZMoTI*S;;C ztG%c#;HuCl0sd^wCfZJW3Bz|^ww!a}XWV*jx#s-?^B^QW=OVwooTLWQ#OF6Ag-Tr8kU~{Rm4=H!yf^Jcb zn3g5N-gmQc$VS>Gv%YUCVEmY?)7SYPU`xG7dQgdD-*cPPSX+(3Ee{R+rhabj-_XCZ z*^Mt(*1hj7A^yr{22@?1j%r-!Z@e(2cCbm?or^ui(vB$|sTS_;?p!mf;8cl`k&#fTlH{Zn&rwk!D-*xig%fk(2~8LJ@{$4UUfyAUi-m8uH9%IFA>L>@_~E^~aFvlpaX`hT5{~(+a=K z-dgE-%At(#z0};UttAyh2>>Z+w(IpFE4qp@x(CzX8R#WI(~eFdLtH~-cAer zmui0xDc5-WAY6mfWJ(-glM`EOFuWAOl0Cy=;W{hVp^~wZA>Zdpf zKi6gyVgW@=ZOMLr$Ub=YF#r{UZF?~?`U#l*(pFge_~&O#Tg2dXiT7F!yaDh(zA#H1 zrjdbPJYJ&I#TnQOp+;TtcQh?;c^2P`lN@9*=xtp{U9UY^<6?}h5Cr`Da%pH7{TQWl z$ZBqGBXOm_OW}yu#Al)H$h!{ye>N?Isk_XS3x(v2q(jnUqEevNDqapsl&WT7>N+;J zyedyMA}#XaULKxgor+!VkaO2832=z#<7dQ*fhUuJ_+k^{*WStM`(qz*EARd1W>#*V z=x4!tY^Y%*QW&tB2Fzd2K(2DttzQX$bCd3(yIrfLS0Caq)>3FeJU7UTl~=1T`)cjO zzD#&mWTqH2W^S8tJPvVk5%xP|Q7NAF&Jz{S?-zQ}&DS3vI_wlC6*l%=I{_REIxN%> zX1eh`mvh0*$A!bz+aUrTyD1eRd=Tf2lTF5;T9d86&{I|Kcn zhV7wLkgrleC?rVBlAb%YUwW?}v>2E=kgJh}Kr+G{StmE;Iiwwzn(Qk|4}&vPKj5 zN$^7(!^KDe5F|Xx`A)kj7yo*r8Y5mY+sN4pqD7y{DJdyA+wD-q<#vhhI0C|@hnzJJ ziftp1$Hy6Xu0=k;M>NpZ7meUDh3c$Lsl18;vb=6pKKr~x%bnmlx7l^{kN`bP+0E@JIK^k zvCqzXxKukjhTpp5F@|O>>pXI=!_CL%B3F#CylvF$*RQRus~c|kO?-Nt(`{cmnmvV7 z$Xdm7X)E*A*@yWxlpv>$M?q8yQgyMq$ncc;cirWK4e;@jHV{NWH|6O+-U z)n71Vxp85dwm9dC_k-Enl-!$+gjQlhiDZ0)rnZE?Qf7sOYyD3c#vUPehJ+kj>D zVUzqcPQxOqQX)cnaIpH4R_!{rh0>CZ(TDK=7cgCvLf3gXceu&zrc8ygr@Ki-EGzB; zGvzJ(vfiIIBw%sentyMpCG=Y zq2d77rs<<@I~qnaGz6%@3>7YRL6BFYJ=_PywW}C&`k@&DhC5+84Pr$K{WhlD1$S(h zyXRF){|EQk4J*Ufw8fPOgFy0&9Y`41hjF=T>7DGfEqQG}giPOKhl)ckZ3IzZ!$v=a z?E%7=qbb4LZ)({ONl{2cM=R7ZP@fH2CMOFdU9a~8a>1VqusN_Kei zqKJy%PLZvCh%;)nu>-8nU7&0>{+R`#;YW73;82ESdvKh~4)PuqD@(NqX*GDzF{OvY z;d(|!#E0;3r1+Hp9Y6&rG8Vr`q31P57K>KCWlMJayG#-+GiyDcCWod_DE;LyeGh7b zCW!gmDrLeIjKv`-w2z19@NsS2GRjr6<>HQWi-B{`D>@HUIMqMK%=i7I1(g!8pDrTr z#kh<~RCqwV6~OBjndn&5Cj}>+L|rPlzTRnDnZE&Oxb4yrvtJ7Rsojrz zSle}MH$~mzT5E+1ab`ax5WBkyLy_KwL@7tlo2Q;!fLeMaKl67zTK(T7$)~u31-erE zA+i=L+$i0y@V{U}l7qR=6)oIbi!0>NxPOe@n{=D|ya?zirv3Nlsk+?f=g*%5d$AGz zX(;+SFw_H*SmDD50TgM+Iaiy`S6t;ZM+zEG)d0lPxwW=ZZ<2_{_N=jT_q3s&!!wFJA%(C`v+qwM@jqk?TZmD1K&$Gm*>a(C?(Kb z0)cRsfw>dD{vGP=?WOhQctdsNC9Tg5YG00n_2;wjhi{kb>FIf?Q3eJey}qSO8|coz z{+{-{_c8eK3Y?+P0=)!k8!+uvj>YCa%8wuSxkI4mzLFY2f7H~}TvQ8G5|NN-7_&aN zo5COVBLX_!k8`)W)eS8Q`@>ghpDR`mW^6p|=@pkhn9^Ba@LDUkt+ci#9mxsaa@zRt zGypIdkR`<8H9icTgtQtXpuz7GpASH|soQ6z$M9DAdItn6Z&90j<&gIU)6+9CG12M~=@YOp(WB}=W&W|Vvt&KQKIq#M zX_L1#EEY=@vGPNX#AGsI-PxMuaB4$RcXG{^?4=%UrAk`=$}qwR3>%pG zChYg8%t@Ajwrvno&Nd+_dr;5lFAY6?Mo^u!X%_55>Oe8{*A7$(Q^+y&R{gVty8l@cFKS(aTUHx z(*sJ4VPBgbsowwk=e>;f`L?KM&r1%VJEa zEI&Wri(qC8SRsNYggV={>HvHsA|_V5w8}lnZOWOKmv@qZ{l(wko%1DhGB3^Ga@!!~ z5-Drz0y)2=RCyMSjb#y5-APMTms>{1Tij6$8JbF@{-ty;Pc9t(>1{p+hn_KcS?%(H z{_a=F3j?cgEh{Y)Qs|6H^7KZEBWG*#s5fgpAt9l^F+7|CJIRRflw&!XUGsn!A`1p> zX!UZk3JF_7A7I{LDNJXVqSyJS)tj$_Ovx#%p;qM=6u=xE9f{?Ds`l511h(Dben)WD zsYoJ`=*~?D8jB=}%s(Bd2t{URXHQH{wgn%Gc~ew%dK6E1K*oxrGH&>+Pkqaeto|lw z2hQfmO|qxs;_@oeH>33qxy}P*_w{<7Inz zHHxbehDf<`B;OHkNRR2JR$ml?ciG1ODkkQHtOiBrzG?B4$|Sdi-PqWOfuTLGrM!28 zIa-N!_<^$lKMtmA2QtVCPz#3-3w2$r(wmK$l`Zg>gBEoy+ z$G4-Tsee%;F5iG^rI6sN`98zVmrxBb&3H}^6PaNHzGCxnGKgNqW1;1$uSN(m5;uX5frQtl&7P+D1w`vXf}x+s)XWa1~7){Ow z`$pZ!eLug;4NEv|i7KV1N1$7qgU}PoD+zZyJxWj)URP1k4*>;(uF1FPea}nlL!0ur zm4a>DGTci(miH5=o^ML0!YXZK?d8Jj(;4w- z4sRUWJp+Tm6tx|+6!XnTGYF!jf_(btVFV%s;YREOADCv6$i45K5Q{X>v;qH^Kb~KU zFXNd#63y*>(C8n1rIS-rF<_vpBq`%Kl9ia4*vhc7zZ}A(lq7bHUCg+fXDcrZ#e3O# zUqE$}T3fG!oiLkIn1P}%8z<-979CP~VPCB(A;ji|AVId=Txy?Fc`tZY@48??j4ST2 zdEEX73YMArO*P~VzQ8#&8gl%1;rX#Z*Tw-NqE0nfjj6~zHG8t%9yAsUw}V7>E$EiGH5mr3%b2$= zvOk8(mFG3cj}Co4!hhMTCSU`v*Wy%qNTp0#I-_HHkc;@|ifi~VQ65e`-#$Dw3~n&^ zw+2T=1#xTMADtu6?w79J*>dg29M$e((eZo4Gp$aDy~sqSwXb*v&0Yl;b@%5s?&v}a z^Gn{ityPZR(30L_e!UK{=eR*kuZ2=%fS%;~;^C&8jb3uerm50mC)$Pif^8B`ahp#` zELT-m%UTo(ECJ;$Kt|v9;%hKis6G>tAx3M-JlCMCCJwiK5gmAkLF@nShX|n=T)3kGnwdWb z3Rf(Uqobo0^{Q)Gv#Hj`Afs|XVlfrZCUVOfKb()~biC334{0aUFN-s1gq9@ZPHE}N z+Sh6F%B)WFB~Q6L2|ke981s#NmVl!|B47Dri5>jb7pVvH2$Nze&JH9*G6Qda9P{aU z+rD?CySpnTv=E%z*{T?7Q%t}0AyI&ZpnL%KC_iz?&d#o9Xb6f6Op}d-hp{ugXNL(# zN!cN@gnojrtDexv0Ku0*%cO3M$H1-x&c-paL*#R#KeM~Ygq87rX8&-$-u=%>sGcJS~iy)B$a*kq87Ms;Fv-ii+$Avayj- z^Yrv|49wHhv***N`-12?Q%I8ma|B2iK)=UELx8ON*>jS>YwP#QWAL3#u_b!+~Q2P)~!4e1$h*WQ| zdyUoa&ySlVr;78X_$#sd&J@u3WhZLvLHt7sGnPv){2BoceJHFxd6z6xt$kzyKE9i4lHi!(vdvHV8p{_0$O})Q1=f4tz%8I0_Jc}`^p!>Ob zp0Lr0Z`=J4{AQy-1n9w|i!<>ti3r%EXWO}Gn$uxO8a2qKHt!f^v z56P{pyhLyNY$=Z&;`SM}GIZ}d!ODPec)3NH`i}~Oyt3)7P!lBB$_LDiiX%1Vuj}Z%)CyG} zMX)=qZEZgWy?;yY?ZvFsjImc$gMK)Uhj$m0er#?OQI%98*ditxC@U+eodN=^MZ+|D z3aicfI-6vC(GAY7ksD{T_$3AtX{S@UGm2!LByiO?l7B$#lBT9Oqbn=+-Me?r%6@?5 z%7FS1!LKFKt-=0?qeH7aqNAc7J$i)EljW@qoNJh2Qm9nagQm5SL{_VQ^V3=Pc<_l* ztq$QpWgVU74p`cy42%Y5v1W6&HE3heu5B;((lH5Ke*nhU+>@&>lh#25;;W}3yY#i! zdO(JD1$}-C2oW(>p&@99FAF$T4^YMNN3hjF;|})7M54Y#G%(<ZiZDL6!99cmCWGw_avu(l;~7TCMyaBtZl9!NHS z@_qNQ6wkTQdPP-L5qQJu9i3)5xWBU}K4gR&H6yhu9X-<0G_$N_;!6=KoI;ei0PI;b9y>1bbW~kT)N#2=??h< zfq+y+$95LnT^-+tuJ-~3)sQyx8U!$%J)}-EoQrD#2V`Z-J})c~?giCH@%fu&fs$#8zWxO@zI>8Eo$#U*DaS)^Gky z^$ic_;P6Ub0~M#1W=AqVB8twZ_09BxngpW5U05Q#x=2ck`~bDz_g9ydnz8MXTH$Zt z)-8&edHO(tWooL5pNI0Uy*tylMCYa$Yr?&YnwnXQsxC!EMdt?i#9vA8Oz%#LmGNB9 v-icjf3aBXnHMfVB|2Jp*pBzVSY46WMACEx21wYsV=A61FI;B?~|MUL<8C^}D diff --git a/svg/sprite.svg b/svg/sprite.svg index f38bfabc0..2dc957abb 100644 --- a/svg/sprite.svg +++ b/svg/sprite.svg @@ -2619,7 +2619,7 @@ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccc" inkscape:connector-curvature="0" id="path5520" - d="m 532.5,16.999997 0,1 1,1 -4.5,4.5 0,0.5 0,1 1.5,0 4.5,-4.5 1,1 1,0 0,-3.5 0,-1 -1,0 z m -6.5,1 -1,1 0,9 1,1 9,0 1,-1 0,-5 -2,2 0,2 -1,0 -1,0 -4,0 -1,0 0,-5 0,-2 1,0 1,0 2,-2 z" + d="m 532.5,15.999997 0,1 1,1 -4.5,4.5 0,0.5 0,1 1.5,0 4.5,-4.5 1,1 1,0 0,-3.5 0,-1 -1,0 z m -6.5,1 -1,1 0,9 1,1 9,0 1,-1 0,-5 -2,2 0,2 -1,0 -1,0 -4,0 -1,0 0,-5 0,-2 1,0 1,0 2,-2 z" style="color:#000000;fill:#597be7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> From f897504443104d338b7af9ee83158df7399a025b Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 3 Apr 2013 16:12:29 -0700 Subject: [PATCH 06/14] Add warning to generated file --- data/locales.js | 10 ++++++++++ data/update_locales.js | 11 ++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/data/locales.js b/data/locales.js index 7bd71aa90..84e926275 100644 --- a/data/locales.js +++ b/data/locales.js @@ -1,3 +1,13 @@ +/* + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + THIS FILE IS GENERATED BY `make translations`. Don't make changes to it. + + Instead, edit the English strings in data/core.yaml or data/presets.yaml, or + contribute translations on https://www.transifex.com/projects/p/id-editor/. + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ locale.en = { "modes": { "add_area": { diff --git a/data/update_locales.js b/data/update_locales.js index 92b887ad0..ca94c2a4c 100644 --- a/data/update_locales.js +++ b/data/update_locales.js @@ -27,7 +27,16 @@ var sourceCore = yaml.load(fs.readFileSync('./data/core.yaml', 'utf8')), asyncMap(resources, getResource, function(err, locales) { if (err) return console.log(err); - var out = ''; + var out = '/*\n' + + ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + '\n' + + ' THIS FILE IS GENERATED BY `make translations`. Don\'t make changes to it.\n' + + '\n' + + ' Instead, edit the English strings in data/core.yaml or data/presets.yaml, or\n' + + ' contribute translations on https://www.transifex.com/projects/p/id-editor/.\n' + + '\n' + + ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + ' */\n'; var locale = _.merge(sourceCore, sourcePresets); locales.forEach(function(l) { locale = _.merge(locale, l); From ef44d43568acda6ad2b780784a3df831a00df9b1 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 3 Apr 2013 16:12:38 -0700 Subject: [PATCH 07/14] Update translations --- data/locales.js | 2116 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 1963 insertions(+), 153 deletions(-) diff --git a/data/locales.js b/data/locales.js index 84e926275..2c99a455e 100644 --- a/data/locales.js +++ b/data/locales.js @@ -6389,6 +6389,9 @@ locale.nl = { "city": "Stad" } }, + "admin_level": { + "label": "Bestuurlijk niveau" + }, "aeroway": { "label": "Type" }, @@ -6772,6 +6775,9 @@ locale.nl = { "barrier/wall": { "name": "Muur" }, + "boundary/administrative": { + "name": "Bestuurlijke grens" + }, "building": { "name": "Gebouw" }, @@ -6781,6 +6787,9 @@ locale.nl = { "building/entrance": { "name": "Ingang" }, + "building/house": { + "name": "Huis" + }, "entrance": { "name": "Ingang" }, @@ -7002,9 +7011,16 @@ locale.nl = { "man_made/survey_point": { "name": "Landmeetkundig referentiepunt" }, + "man_made/wastewater_plant": { + "name": "Waterzuiveringsinstallatie", + "terms": "rioolwaterzuiveringsinstallatie,afvalwaterzuiveringsinstallatie" + }, "man_made/water_tower": { "name": "Watertoren" }, + "man_made/water_works": { + "name": "Waterwinstation" + }, "natural": { "name": "Natuurlijk" }, @@ -7380,21 +7396,22 @@ locale.nl = { } } }; +locale.eo = {}; locale.fr = { "modes": { "add_area": { "title": "Polygone", - "description": "Les polygones peuvent être des parcs, des batîments, des lacs ou tout autre objet surfacique.", + "description": "Ajouter des parcs, des bâtiments, des lacs ou d'autres polygones à la carte.", "tail": "Cliquez sur la carte pour ajouter un polygone tel qu'un parc, un lac ou un bâtiment." }, "add_line": { "title": "Ligne", - "description": "Les lignes peuvent être des autoroutes, des routes, des chemins ou encore des caneaux.", - "tail": "Cliquez sur la carte pour ajouter une nouvelle ligne telle qu'une route ou un nouveau chemin." + "description": "Les lignes peuvent être des autoroutes, des routes, des chemins ou encore des canaux.", + "tail": "Cliquez sur la carte pour ajouter une nouvelle ligne telle qu'une route ou un chemin." }, "add_point": { "title": "Point", - "description": "Les points peuvent être des restaurants, des monuments, ou encore des boites aux lettres.", + "description": "Les points peuvent être des restaurants, des monuments, ou encore des boîtes aux lettres.", "tail": "Cliquez sur la carte pour ajouter un point tel qu'un restaurant ou un monument." }, "browse": { @@ -7402,7 +7419,7 @@ locale.fr = { "description": "Naviguer ou zoomer sur la carte." }, "draw_area": { - "tail": "Cliquez pour ajouter un point à la zone. Cliquez sur le dernier point pour fermer la zone." + "tail": "Cliquez pour ajouter des points à votre polygone. Cliquez sur le premier point pour clore le polygone." }, "draw_line": { "tail": "Cliquez pour ajouter un point à la ligne. Cliquez sur une autre ligne pour les connecter, puis faîtes un double-clique pour terminer la ligne." @@ -7411,55 +7428,61 @@ locale.fr = { "operations": { "add": { "annotation": { - "point": "Ajouter un point.", - "vertex": "Ajouter un noeud à une ligne." + "point": "Un point créé.", + "vertex": "Un nœud ajouté à une ligne." } }, "start": { "annotation": { - "line": "Commencer une nouvelle ligne.", - "area": "Commencer un polygone." + "line": "Une ligne commencée.", + "area": "Un polygone commencé." } }, "continue": { "annotation": { - "line": "Continuer une ligne.", - "area": "Continuer un polygone." + "line": "Une ligne continuée.", + "area": "Un polygone continué." } }, "cancel_draw": { - "annotation": "Annuler un ajout." + "annotation": "Modification annulée." }, "change_tags": { - "annotation": "Modifier les tags." + "annotation": "Attributs modifiés." }, "circularize": { "title": "Arrondir", + "description": { + "line": "Rendre circulaire cette ligne.", + "area": "Rendre circulaire ce polygone." + }, "key": "O", "annotation": { - "line": "Créer un cercle linéaire.", - "area": "Créer un cercle surfacique (disque)." - } + "line": "Ligne rendue circulaire.", + "area": "Polygone rendu circulaire." + }, + "not_closed": "Cet élément ne peut pas être rendu circulaire car il ne boucle pas." }, "orthogonalize": { "title": "Orthogonaliser", "description": "Rendre une forme orthogonale.", "key": "Q", "annotation": { - "line": "Orthogonaliser une ligne orthogonale.", - "area": "Orthogonaliser un polygone orthogonale." - } + "line": "Ligne rendue orthogonale.", + "area": "Polygone rendu orthogonal." + }, + "not_closed": "Cet élément ne peut être orthogonalisé car il ne forme pas de boucle." }, "delete": { "title": "Supprimer", "description": "Supprime l'élément de la carte.", "annotation": { - "point": "Supprime un point.", - "vertex": "Supprime le noeud d'une ligne.", - "line": "Supprime une ligne.", - "area": "Supprime un polygone.", - "relation": "Supprime une relation.", - "multiple": "Supprime {n} objets." + "point": "Point supprimé", + "vertex": "Nœud d'une ligne supprimé.", + "line": "Ligne supprimée.", + "area": "Polygone supprimé.", + "relation": "Relation supprimée.", + "multiple": "{n} objets supprimés." } }, "connect": { @@ -7472,27 +7495,31 @@ locale.fr = { }, "disconnect": { "title": "Séparer", - "description": "Sépare les lignes l'une de l'autre.", + "description": "Séparer les lignes/contours l'un de l'autre.", "key": "D", - "annotation": "Sépare les lignes." + "annotation": "Lignes non connectées.", + "not_connected": "Il n'y a pas ici de lignes/polygones à déconnecter." }, "merge": { "title": "Fusionner", - "description": "Fusionne les lignes.", + "description": "Fusionne ces lignes.", "key": "C", - "annotation": "Fusionne les {n} ligne." + "annotation": "Fusionne les {n} ligne.", + "not_eligible": "Ces éléments ne peuvent pas être fusionnés.", + "not_adjacent": "Ces lignes ne peuvent pas être fusionnées car elles ne sont pas connectés." }, "move": { "title": "Déplacer", - "description": "Déplace l'élément à un autre endroit.", + "description": "Déplacer l'élément à un autre endroit.", "key": "M", "annotation": { - "point": "Déplace un point.", - "vertex": "Déplace le noeud d'une ligne.", - "line": "Déplace une ligne.", - "area": "Déplace un polygone.", - "multiple": "Déplace un groupe d'objets." - } + "point": "Point déplacé.", + "vertex": "Nœud d'une ligne déplacé.", + "line": "Ligne déplacée.", + "area": "Polygone déplacé.", + "multiple": "Plusieurs objets déplacés" + }, + "incomplete_relation": "Cet élément ne peut pas être déplacé car il n'a pas été téléchargé dans son intégralité." }, "rotate": { "title": "Rotation", @@ -7507,24 +7534,38 @@ locale.fr = { "title": "Inverser", "description": "Inverse le sens d'une ligne.", "key": "V", - "annotation": "Inverse le sens d'une ligne." + "annotation": "Sens d'une ligne inversé." }, "split": { "title": "Couper", - "key": "X" + "description": { + "line": "Couper cette ligne en deux au niveau du point sélectionné.", + "area": "Couper le contour de ce polygone en deux.", + "multiple": "Couper les lignes/polygones en deux au niveau du point sélectionné." + }, + "key": "X", + "annotation": { + "line": "Coupe une ligne.", + "area": "Couper le contour d'un polygone.", + "multiple": "Couper {n} lignes/contour de polygone." + }, + "not_eligible": "Les lignes ne peuvent pas être coupées à leurs extrémités.", + "multiple_ways": "Il y a trop de ligne à cet endroit pour pouvoir couper." } }, "nothing_to_undo": "Rien à annuler.", "nothing_to_redo": "Rien à refaire.", - "just_edited": "Vous venez de participer à OpenStreetMap!", + "just_edited": "Vous venez de participer à OpenStreetMap !", "browser_notice": "Les navigateurs supportés par cet éditeur sont : Firefox, Chrome, Safari, Opera et Internet Explorer (version 9 et supérieures). Pour éditer la carte, veuillez mettre à jour votre navigateur ou utiliser Potlatch 2.", "view_on_osm": "Consulter dans OSM", "zoom_in_edit": "Zoomer pour modifier la carte", "logout": "Déconnexion", + "loading_auth": "Connexion à OpenStreetMap...", "report_a_bug": "Signaler un bug", "commit": { "title": "Sauvegarder vos modifications", "description_placeholder": "Description succinte de vos contributions", + "message_label": "Description de l'édition", "upload_explanation": "{user} : les modifications apportées seront visibles par l'ensemble des services utilisant les données d'OpenStreetMap.", "save": "Sauvegarder", "cancel": "Annuler", @@ -7549,13 +7590,13 @@ locale.fr = { "no_documentation_combination": "Aucune documentation n'est disponible pour cette combinaison de tag", "no_documentation_key": "Aucune documentation n'est disponible pour cette clé", "show_more": "Plus d'infornations", - "new_tag": "Nouveau tag", - "view_on_osm": "Visualiser sur OSM", + "new_tag": "Nouvel attribut", + "view_on_osm": "Visualiser sur OSM →", "editing_feature": "Édition de {feature}", - "additional": "Tags complémentaires", + "additional": "Attributs complémentaires", "choose": "Que souhaitez vous ajouter?", "results": "{n} résultats pour {search}", - "reference": "Consulter sur le Wiki d'OpenStreetMap", + "reference": "Consulter sur le Wiki d'OpenStreetMap →", "back_tooltip": "Changer le type de l'objet " }, "background": { @@ -7566,26 +7607,28 @@ locale.fr = { "reset": "réinitialiser" }, "restore": { - "heading": "Vous avez des changements non sauvés.", - "description": "Vous avez des changements non sauvegardés d'une précédente édition. Souhaitez-vous restaurer ces changements?", + "heading": "Vous avez des changements non sauvegardés.", + "description": "Vous avez des changements non sauvegardés d'une précédente édition. Souhaitez-vous restaurer ces changements ?", "restore": "Restaurer", - "reset": "Annuler" + "reset": "Réinitialiser" }, "save": { "title": "Sauvegarder", - "help": "Envoie des modifications au serveyr OpenStreetMap afin qu'elles soient visibles par les autres contributeurs.", + "help": "Envoi des modifications au serveur OpenStreetMap afin qu'elles soient visibles par les autres contributeurs.", "no_changes": "Aucune modification à sauvegarder", "error": "Une erreur est survenue lors de l'enregistrement des données", - "uploading": "Envoie des modifications vers OpenStreetMap.", + "uploading": "Envoi des modifications vers OpenStreetMap.", "unsaved_changes": "Vous avez des modifications non enregistrées" }, "splash": { - "welcome": "Bienvenue sur ID l'editeur en ligne d'OpenStreetMap", - "text": "Cette version {version}, est une version de développement. Si vous souhaitez plus d'informations, veuillez consulter {website} ou pour signaler un bug {github}.", + "welcome": "Bienvenue sur ID, l'éditeur en ligne d'OpenStreetMap", + "text": "Cette version {version} est une version de développement. Si vous souhaitez plus d'informations, veuillez consulter {website} ou {github} pour signaler un bug.", + "walkthrough": "Commencer le tutorial", "start": "Editer" }, "source_switch": { "live": "live", + "lose_changes": "Vos dernières modifications n'ont pas été sauvées. Si vous changez de serveur de carte, celles-ci seront perdues. Êtes-vous sûr de vouloir changer de serveur de carte ?", "dev": "dev" }, "tag_reference": { @@ -7594,40 +7637,101 @@ locale.fr = { "used_with": "Utilisé avec {type}" }, "validations": { - "untagged_point": "Point sans aucun tag ne faisant partie ni d'une ligne, ni d'un polygone", - "untagged_line": "Ligne sans aucun tag", - "untagged_area": "Polygone sans aucun tag", - "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": "Ce tag {tag} suppose que cette ligne devrait être un polygone, or ce n'est pas le cas", - "deprecated_tags": "Tags obsolètes : {tags}" + "untagged_point": "Point sans aucun attribut ne faisant partie ni d'une ligne, ni d'un polygone", + "untagged_line": "Ligne sans aucun attribut", + "untagged_area": "Polygone sans aucun attribut", + "many_deletions": "Vous allez supprimer {n} objets. Êtes-vous sûr de vouloir faire-cela ? Ces éléments seront supprimés de la carte visible sur openstreetmap.org.", + "tag_suggests_area": "Cet attribut {tag} suppose que cette ligne devrait être un polygone, or ce n'est pas le cas", + "deprecated_tags": "Attributs obsolètes : {tags}" }, "zoom": { "in": "Zoomer", "out": "Dézoomer" }, + "cannot_zoom": "Impossible de zoomer plus en arrière dans ce mode.", "gpx": { "local_layer": "Fichier GPX personnel", "drag_drop": "Glisser et déposer un fichier .gpx sur la page" }, "help": { - "title": "Aide" + "title": "Aide", + "help": "#Aide\n\n Ceci est un éditeur pour [OpenStreetMap](http://www.openstreetmap.org/), la carte du\n monde gratuite et éditable. Vous pouvez l'utiliser pour ajouter ou corriger les données\n dans votre zone, et participer ainsi à la réalisation d'une carte du monde libre de droits.\n\n Les modifications que vous réaliserez seront visibles de tout le monde. Pour commencer\n à éditer, vous devez créer un [compte gratuit sur OpenStreetMap](https://www.openstreetmap.org/user/new).\n\n [iD editor](http://ideditor.com/) est un projet collaboratif dont le [code source est\n disponible sur GitHub](https://github.com/systemed/iD).\n", + "imagery": "# Fond de carte\n\nLes photos aériennes sont une source importantes pour cartographier. Une\ncompilation de photos prises d'avion, imageries satellites, et autres sources\nlibre d'utilisation sont disponibles dans l'éditeur dans le menu \"Configuration\ndu fond de carte\" à gauche.\n\nPar défaut, l'imagerie aérienne de [Bing Maps](http://www.bing.com/maps/)\nest utilisée dans l'éditeur, mais lorsque vous zoomez sur la carte, d'autres sources\nsont parfois disponibles dans certaines zones. Certains pays tels que la France, les\nEtats-Unis ou le Danemark disposent d'image de très haute qualité sur certaines\nzones.\n\nCertaines images sont parfois décalées par rapport aux données, notamment\nà cause d'un mauvais calibrage. Si vous voyez de nombreux éléments tous décalés\npar rapport au fond de carte, ne déplacez pas immédiatement ces éléments. A la\nplace, vous pouvez ajuster le fond de carte afin qu'il soit aligné aux données en\ncliquant sur \"Corriger l'alignement\" en bas de l'interface de configuration du fond\nde carte.\n", + "addresses": "# Adresses\n\nLes adresses sont des informations très utiles.\n\nDans OpenStreetMap, les adresses sont enregistrées comme attributs des\nbâtiments le long des routes.\n\nVous pouvez ajouter une adresse sur les éléments modélisés avec un polygone\net sur ceux modélisés avec des points. La meilleure source de données afin\nde cartographier les adresses reste le relevé sur le terrain, car la copie de\ndonnées à partir de contenu non libre de droits est interdite.\n", + "buildings": "# Bâtiments\n\nOpenStreetMap est la plus grande base de données au monde sur le bâti.\nVous pouvez améliorer cette base de données.\n\n### Sélection\n\nVous pouvez sélectionner un bâtiment en cliquant sur son contour. Le bâtiment\nsera ainsi surligné, une boîte à outils apparaîtra ainsi qu'un panneau contenant\nles informations sur le bâtiment.\n\n### Correction\n\nParfois, un bâtiment est mal placé ou possède des informations incorrectes.\n\nPour déplacer un bâtiment dans son intégralité, sélectionnez-le, puis cliquez\nsur l'outil \"Déplacer\". Déplacez ensuite la souris, puis cliquez lorsque le\nbâtiment est placé correctement.\n\nPour corriger la forme d'un bâtiment, glissez-déposez les points du contour\ndu bâtiment.\n\n### Création\n\nL'une des problématiques concernant les bâtiments est qu'ils peuvent être\nreprésentés à la fois par un point ou par un polygone. La règle d'or est de\n_dessiner les bâtiments avec des polygone dès que c'est possible_, et de\ncartographier les entreprises, équipements, adresses, et tout ce qui ne\ndépend pas directement de la construction comme des points placés\nau sein de la forme du bâtiment.\n\nDessinez un bâtiment en cliquant sur le bouton \"Polygone\" en haut à gauche\nde l'interface, ajoutez des points en cliquant sur la carte et terminez la forme\nen cliquant sur le premier point, ou en appuyant sur la touche \"Entrée\" de\nvotre clavier.\n\n### Suppression\n\nSi un bâtiment dessiné est inexistant (par exemple s'il n'existe pas sur l'image\nsatellite et que vous avez vérifié sur place que ce n'était pas une construction\nrécente), vous pouvez le supprimer. Attention avant de supprimer un élément ;\ntout le monde peut constater que vous l'avez supprimé, et il peut s'agir d'un\nélément plus récent que l'image satellite.\n\nVous pouvez supprimer un bâtiment en le sélectionnant, puis en cliquant sur\nl'icône représentant une poubelle, ou en appuyant sur la touche \"Suppr\" de\nvotre clavier.\n" + }, + "intro": { + "navigation": { + "drag": "La vue principale montre les données OpenStreetMap par dessus un fond de carte. Vous pouvez naviguer au sein de la vue en faisant du cliquer-glisser, ou avec les barres de navigation, comme n'importe quelle carte sur Internet. **Faites glisser la carte !**", + "select": "Les éléments cartographiques sont de trois types : les points, les lignes et les polygones. Chaque élément peut être sélectionné en cliquant dessus. **Cliquez sur le point pour le sélectionner.**", + "header": "L'entête nous montre le type d'élément.", + "pane": "Lorsqu'un élément est sélectionné, l'éditeur d'éléments est affiché. L'entête nous indique le type d'élément et le panneau principal nous montre les attributs de l'élément, tels que son nom et son adresse. **Fermez l'éditeur d'éléments en cliquant sur le bouton de fermeture en haut à droite.**" + }, + "points": { + "add": "Des points peuvent être utilisés pour représenter des éléments comme des magasins, restaurants ou monuments. Ils indiquent une position précise et décrivent ce qu'il y a à cet endroit. **Cliquez sur le bouton \"Point\" pour ajouter un point.**", + "place": "Le point peut être placé en cliquant sur la carte. **Placer le point sur le dessus du bâtiment.**", + "search": "De nombreux éléments peuvent être représentés par des points. Le point que vous venez d'ajouter est un café (Cafe). **Cherchez \"Cafe\".**", + "choose": "**Sélectionnez \"Cafe\" dans le tableau.**", + "describe": "Le point est désormais marqué comme étant un café. Nous pouvons ajouter davantage d'informations grâce à l'éditeur d'élément. **Ajoutez un nom au café.**", + "close": "L'éditeur d'éléments peut être fermé en cliquant sur le bouton de fermeture. **Fermez l'éditeur d'éléments.**", + "reselect": "Souvent, des points existent déjà, mais contiennent des erreurs ou sont incomplets. Vous pouvez éditer des points déjà existants. **Sélectionnez le point que vous venez de créer.*", + "fixname": "**Modifier le nom et fermez l'éditeur d'éléments.**", + "reselect_delete": "Tous les éléments de la carte peuvent être supprimés. **Cliquez sur le point que vous venez de créer.**", + "delete": "Le menu autour du point contient des opérations que vous pouvez lui appliquer, notamment sa suppression. **Supprimez le point.**" + }, + "areas": { + "add": "Les polygones permettent de détailler plus précisément des éléments cartographiques. Ils permettent de renseigner les limites géographiques d'un élément. Les polygones peuvent être utiliser pour décrire les mêmes éléments que les points, et sont souvent à privilégier. **Cliquez sur le bouton \"Polygone\" pour ajouter un nouveau polygone.**", + "corner": "Les polygones sont dessinés en plaçant des nœuds l'un après l'autre. **Ajoutez un premier nœud sur un coin de l'aire de jeu.**", + "place": "Dessinez le polygone en plaçant d'autres nœuds. Terminez le polygone en cliquant sur le point de départ. **Dessinez un polygone pour représenter l'aire de jeu.**", + "search": "**Recherchez \"Aire de jeu\" (Playground).**", + "choose": "**Sélectionnez \"Aire de jeu\" (Playground) dans le tableau.**", + "describe": "**Ajouter un nom, et fermez l'éditeur d'éléments.**" + }, + "lines": { + "add": "Les lignes sont utilisées pour représenter des éléments tels que des routes, des chemins de fer ou des rivières. **Cliquez sur le bouton \"Ligne\" pour ajouter une nouvelle ligne.**", + "start": "**Commencez la ligne en cliquant sur l'extrémité de la route.**", + "intersect": "Cliquez pour ajouter plus de points. Si nécessairen, vous pouvez glisser-déplacer la carte tout en dessinant. Les routes et la majorité des autres éléments linéaires font partie d'un réseau plus grand. Il est très important que les lignes soient connectées convenablement afin que des applications comme le calcul d'itinéraire puissent fonctionner. **Cliquez sur Flower Street pour créer une intersection et interconnecter les deux lignes.**", + "finish": "Les lignes peuvent être terminées en cliquant une nouvelle fois sur le dernier point créé. **Terminez la route.**", + "road": "**Sélectionnez \"Route\" dans le tableau.**", + "residential": "Il y a différent types de routes, le plus commun est \"Résidentielle\" (Residential). **Sélectionnez le type \"Résidentielle\".**", + "describe": "**Donnez un nom à la rue et fermez l'éditeur d'éléments.**", + "restart": "La route nécessite d'être interconnectée avec Flower Street." + }, + "startediting": { + "help": "Plus d'informations et ce tutorial sont disponibles ici.", + "save": "N'oubliez pas de sauver régulièrement vos modifications !", + "start": "Commencer à cartographier !" + } }, "presets": { "fields": { + "access": { + "label": "Accès" + }, "address": { "label": "Adresse", "placeholders": { + "housename": "Nom du bâtiment", "number": "123", "street": "Rue", "city": "Ville" } }, + "admin_level": { + "label": "Niveau administratif" + }, "aeroway": { "label": "Type" }, "amenity": { "label": "Type" }, + "atm": { + "label": "Distributeur de billets" + }, + "barrier": { + "label": "Type" + }, "bicycle_parking": { "label": "Type" }, @@ -7643,9 +7747,15 @@ locale.fr = { "capacity": { "label": "Capacité" }, + "collection_times": { + "label": "Horaires de collecte" + }, "construction": { "label": "Type" }, + "country": { + "label": "Pays" + }, "crossing": { "label": "Type" }, @@ -7653,10 +7763,16 @@ locale.fr = { "label": "Cuisine" }, "denomination": { - "label": "Denomination " + "label": "Dénomination " + }, + "denotation": { + "label": "Signification" }, "elevation": { - "label": "Elevation " + "label": "Altitude" + }, + "emergency": { + "label": "Urgence" }, "entrance": { "label": "Type" @@ -7664,6 +7780,9 @@ locale.fr = { "fax": { "label": "Fax" }, + "fee": { + "label": "Prix" + }, "highway": { "label": "Type" }, @@ -7673,7 +7792,9 @@ locale.fr = { "internet_access": { "label": "Accès Internet", "options": { - "wlan": "Wifi" + "wlan": "Wifi", + "wired": "Par câble", + "terminal": "Ordinateur" } }, "landuse": { @@ -7694,6 +7815,15 @@ locale.fr = { "maxspeed": { "label": "Limite de vitesse" }, + "name": { + "label": "Nom" + }, + "natural": { + "label": "Naturel" + }, + "network": { + "label": "Réseau" + }, "note": { "label": "Note" }, @@ -7703,35 +7833,48 @@ locale.fr = { "oneway": { "label": "Sens unique" }, + "oneway_yes": { + "label": "Sens unique" + }, "opening_hours": { "label": "Heures" }, "operator": { - "label": "Operateur " + "label": "Opérateur" }, "phone": { - "label": "Telephone " + "label": "Téléphone " }, "place": { "label": "Type" }, + "power": { + "label": "Type" + }, "railway": { "label": "Type" }, + "ref": { + "label": "Référence" + }, "religion": { "label": "Religion", "options": { - "christian": "Christianisme", - "muslim": "Musulmane", - "buddhist": "Budhiste ", + "christian": "Chrétienne", + "muslim": "Islamique", + "buddhist": "Bouddhiste", "jewish": "Juive", - "hindu": "Indouiste ", - "taoist": "Taoiste " + "hindu": "Hindouiste", + "shinto": "Shintoïste", + "taoist": "Taoïste" } }, "service": { "label": "Type" }, + "shelter": { + "label": "Abri" + }, "shop": { "label": "Type" }, @@ -7741,6 +7884,15 @@ locale.fr = { "sport": { "label": "Sport" }, + "structure": { + "label": "Structure", + "options": { + "bridge": "Pont", + "tunnel": "Tunnel", + "embankment": "Remblai", + "cutting": "Tranchée" + } + }, "surface": { "label": "Surface" }, @@ -7759,6 +7911,9 @@ locale.fr = { "wetland": { "label": "Type" }, + "wheelchair": { + "label": "Accès en fauteuil roulant" + }, "wikipedia": { "label": "Wikipedia" }, @@ -7767,122 +7922,328 @@ locale.fr = { } }, "presets": { + "aeroway": { + "name": "Aviation" + }, "aeroway/aerodrome": { - "name": "Aeroport " + "name": "Aéroport", + "terms": "avion,aéroport,aérodrome" + }, + "aeroway/helipad": { + "name": "Héliport", + "terms": "hélicoptère,helipad,héliport" + }, + "amenity": { + "name": "Équipements" }, "amenity/bank": { - "name": "Banque" + "name": "Banque", + "terms": "coffre,dépôt,économies,compte,épargne,trésorerie" }, "amenity/bar": { "name": "Bar" }, + "amenity/bench": { + "name": "Banc" + }, "amenity/bicycle_parking": { - "name": "Parc à velos " + "name": "Parking à vélos " }, "amenity/bicycle_rental": { - "name": "Location de velos " + "name": "Location de vélos" }, "amenity/cafe": { - "name": "Cafe " + "name": "Café", + "terms": "café,salon de thé" }, "amenity/cinema": { - "name": "Cinema " + "name": "Cinéma", + "terms": "cinéma,film,ciné,cinématographe,salle obscure,projection" + }, + "amenity/courthouse": { + "name": "Tribunal" + }, + "amenity/embassy": { + "name": "Embassade" }, "amenity/fast_food": { "name": "Fast Food" }, "amenity/fire_station": { - "name": "Caserne de pompier" + "name": "Caserne de pompiers" + }, + "amenity/fuel": { + "name": "Station service" }, "amenity/grave_yard": { "name": "Cimetière" }, "amenity/hospital": { - "name": "Hopital " + "name": "Hopital", + "terms": "clinique,CHU,centre hospitalier,hôpital,infirmerie,hospice,cabinet,maison de repos,urgences,soins" }, "amenity/library": { - "name": "Bibliotheque " + "name": "Bibliotheque" + }, + "amenity/marketplace": { + "name": "Place de marché" }, "amenity/parking": { - "name": "Parking " + "name": "Parking" }, "amenity/pharmacy": { "name": "Pharmacie" }, "amenity/place_of_worship": { - "name": "Lieu de culte" + "name": "Lieu de culte", + "terms": "église,chapelle,mosquée,synagogue,espace prière,cathédrale,sanctuaire,temple" }, "amenity/place_of_worship/christian": { - "name": "Eglise " + "name": "Église", + "terms": "église,chapelle,mosquée,synagogue,espace prière,cathédrale,sanctuaire,temple" }, "amenity/place_of_worship/jewish": { - "name": "Cynagogue " + "name": "Cynagogue", + "terms": "juif,synagogue" }, "amenity/place_of_worship/muslim": { - "name": "Mosque " + "name": "Mosquée", + "terms": "musulman,mosquée" }, "amenity/police": { - "name": "Poste de police" + "name": "Poste de police", + "terms": "police,gendarmerie,forces de l'ordre,flics,poulets,bleus" }, "amenity/post_box": { - "name": "Boite aux lettres" + "name": "Boite aux lettres", + "terms": "boîte aux lettres,poste,la poste" + }, + "amenity/post_office": { + "name": "Bureau de poste" }, "amenity/pub": { "name": "Pub" }, "amenity/restaurant": { - "name": "Restaurant" + "name": "Restaurant", + "terms": "bar,cafétéria,café,restaurant,restauration,snack,fast food,brasserie,distributeur,sandwiches" }, "amenity/school": { - "name": "Ecole " + "name": "École", + "terms": "école,maternelle,collège,université,faculté,fac,institut,apprentissage,formation,cours" + }, + "amenity/swimming_pool": { + "name": "Piscine" + }, + "amenity/telephone": { + "name": "Téléphone" + }, + "amenity/theatre": { + "name": "Théatre", + "terms": "théâtre,pièce,représentation,séance" }, "amenity/toilets": { - "name": "Toiletes " + "name": "Toiletes" + }, + "amenity/townhall": { + "name": "Mairie", + "terms": "mairie,administration" }, "amenity/university": { - "name": "Universite " + "name": "Université" + }, + "barrier": { + "name": "Barrière" + }, + "barrier/block": { + "name": "Bloc" + }, + "barrier/bollard": { + "name": "Poteau" + }, + "barrier/cattle_grid": { + "name": "Grille à bétail" + }, + "barrier/city_wall": { + "name": "Mur d'enceinte" + }, + "barrier/cycle_barrier": { + "name": "Barrière à vélos" + }, + "barrier/ditch": { + "name": "Fossé" + }, + "barrier/entrance": { + "name": "Ouverture" + }, + "barrier/fence": { + "name": "Clôture" + }, + "barrier/gate": { + "name": "Portail" + }, + "barrier/hedge": { + "name": "Haie" + }, + "barrier/kissing_gate": { + "name": "Portillon à chicane mobile" + }, + "barrier/lift_gate": { + "name": "Barrière levante" + }, + "barrier/retaining_wall": { + "name": "Mur de soutènement" + }, + "barrier/stile": { + "name": "Échalier" + }, + "barrier/toll_booth": { + "name": "Péage" + }, + "barrier/wall": { + "name": "Mur" + }, + "boundary/administrative": { + "name": "Frontière administrative" }, "building": { - "name": "Batiment " + "name": "Batiment" + }, + "building/apartments": { + "name": "Résidence" + }, + "building/entrance": { + "name": "Entrée" + }, + "building/house": { + "name": "Maison" }, "entrance": { - "name": "Entree " + "name": "Entrée" + }, + "highway": { + "name": "Route" + }, + "highway/bridleway": { + "name": "Sentier équestre", + "terms": "piste cavalière,sentier équestre,sentier pour cheveaux" }, "highway/bus_stop": { - "name": "Arret de bus " + "name": "Arret de bus" }, "highway/crossing": { - "name": "Passage pieton " + "name": "Passage piéton", + "terms": "passage piéton,zebra" + }, + "highway/cycleway": { + "name": "Voie cyclable" + }, + "highway/footway": { + "name": "Voie piétonne", + "terms": "passage,chemin,route,rue,autoroute,avenue,boulevard,chaussée,chemin de fer,rails,piste,allée,sentier,voie" + }, + "highway/motorway": { + "name": "Autoroute" + }, + "highway/motorway_link": { + "name": "Bretelle d'autoroute", + "terms": "rampe" + }, + "highway/path": { + "name": "Chemin non carrossable" }, "highway/primary": { "name": "Route principale" }, + "highway/primary_link": { + "name": "Voie d'accès à une route primaire", + "terms": "rampe" + }, "highway/residential": { - "name": "Route residentielle " + "name": "Route résidentielle" + }, + "highway/road": { + "name": "Voie de type inconnu" }, "highway/secondary": { "name": "Route secondaire" }, + "highway/secondary_link": { + "name": "Voie d'accès à une route secondaire", + "terms": "rampe" + }, + "highway/service": { + "name": "Route d'accès" + }, "highway/steps": { - "name": "Escaliers" + "name": "Escaliers", + "terms": "marches,escalier" }, "highway/tertiary": { "name": "Route tertiaire" }, + "highway/tertiary_link": { + "name": "Voie d'accès à une route tertiaire", + "terms": "rampe" + }, + "highway/track": { + "name": "Chemin carrossable" + }, "highway/traffic_signals": { - "name": "Feux tricolores" + "name": "Feux tricolores", + "terms": "feux,feu rouge,feu tricolore" + }, + "highway/trunk": { + "name": "Voie rapide" + }, + "highway/trunk_link": { + "name": "Voie d'accès à une voie rapide", + "terms": "rampe" }, "highway/turning_circle": { - "name": "Rond point" + "name": "Zone de manœuvre" + }, + "highway/unclassified": { + "name": "Route de desserte locale" }, "historic": { "name": "Site historique" }, + "historic/archaeological_site": { + "name": "Site archéologique" + }, + "historic/boundary_stone": { + "name": "Borne frontière" + }, + "historic/castle": { + "name": "Château" + }, + "historic/memorial": { + "name": "Mémorial" + }, "historic/monument": { "name": "Monument" }, + "historic/ruins": { + "name": "Ruines" + }, + "historic/wayside_cross": { + "name": "Croix/Calvaire" + }, + "historic/wayside_shrine": { + "name": "Bildstock" + }, + "landuse": { + "name": "Type de terrain" + }, + "landuse/allotments": { + "name": "Jardins familiaux" + }, + "landuse/basin": { + "name": "Bassin" + }, "landuse/cemetery": { - "name": "Cimetiere " + "name": "Cimetiere" }, "landuse/commercial": { "name": "Commerciale" @@ -7893,6 +8254,9 @@ locale.fr = { "landuse/farm": { "name": "Ferme" }, + "landuse/farmyard": { + "name": "Bâtiments de ferme" + }, "landuse/forest": { "name": "Forêt" }, @@ -7902,53 +8266,463 @@ locale.fr = { "landuse/industrial": { "name": "Industrielle" }, + "landuse/meadow": { + "name": "Prairie" + }, + "landuse/orchard": { + "name": "Verger" + }, + "landuse/quarry": { + "name": "Carrière" + }, "landuse/residential": { - "name": "Residentielle " + "name": "Residentielle" + }, + "landuse/vineyard": { + "name": "Vigne" + }, + "leisure": { + "name": "Loisirs" + }, + "leisure/garden": { + "name": "Jardin" }, "leisure/golf_course": { "name": "Parcours de golf" }, + "leisure/marina": { + "name": "Marina" + }, "leisure/park": { - "name": "Parc" + "name": "Parc", + "terms": "esplanade,forêt,jardin,gazon,pelouse,prairie,place,terrain de jeux,aire de jeux,square,bois" + }, + "leisure/pitch": { + "name": "Terrain de sport" + }, + "leisure/pitch/american_football": { + "name": "Terrain de football américain" + }, + "leisure/pitch/baseball": { + "name": "Terrain de baseball" + }, + "leisure/pitch/basketball": { + "name": "Terrain de basketball" + }, + "leisure/pitch/soccer": { + "name": "Terrain de football" }, "leisure/pitch/tennis": { "name": "Court de tennis" }, + "leisure/playground": { + "name": "Jeux pour enfants" + }, + "leisure/slipway": { + "name": "Plan incliné" + }, + "leisure/stadium": { + "name": "Stade" + }, + "leisure/swimming_pool": { + "name": "Piscine" + }, + "man_made": { + "name": "Édifices" + }, "man_made/lighthouse": { "name": "Phare" }, + "man_made/pier": { + "name": "Jetée" + }, + "man_made/survey_point": { + "name": "Poteau de triangulation" + }, + "man_made/wastewater_plant": { + "name": "Station d'épuration", + "terms": "épuration,eaux usées" + }, + "man_made/water_tower": { + "name": "Château d'eau" + }, + "man_made/water_works": { + "name": "Station de pompage d'eau potable" + }, + "natural": { + "name": "Nature" + }, "natural/bay": { "name": "Baie" }, "natural/beach": { "name": "Plage" }, + "natural/cliff": { + "name": "Falaise" + }, + "natural/coastline": { + "name": "Ligne de côte", + "terms": "ligne de côte,littoral,trait de côte" + }, + "natural/glacier": { + "name": "Glacier" + }, + "natural/grassland": { + "name": "Graminées" + }, + "natural/heath": { + "name": "Lande" + }, + "natural/peak": { + "name": "Sommet", + "terms": "mont,sommet,pic,aiguille,crête,colline,dent" + }, + "natural/scrub": { + "name": "Friche, garrigue, maquis" + }, + "natural/spring": { + "name": "Source" + }, "natural/tree": { "name": "Arbre" }, + "natural/water": { + "name": "Eau" + }, "natural/water/lake": { - "name": "Lac" + "name": "Lac", + "terms": "lac,étang" + }, + "natural/water/pond": { + "name": "Étang", + "terms": "bassin,retenue,étang,lac" + }, + "natural/water/reservoir": { + "name": "Bassin de retenue" + }, + "natural/wetland": { + "name": "Zone humide" + }, + "natural/wood": { + "name": "Bois" + }, + "office": { + "name": "Bureau" + }, + "other": { + "name": "Autre" + }, + "other_area": { + "name": "Autre" + }, + "place": { + "name": "Toponymie" + }, + "place/hamlet": { + "name": "Hameau" }, "place/island": { - "name": "Ile " + "name": "Île", + "terms": "archipel,atoll,récif,presqu'île,haut fond,barre,îlot" + }, + "place/locality": { + "name": "Lieu-dit" }, "place/village": { "name": "Village" }, + "power": { + "name": "Énergie" + }, + "power/generator": { + "name": "Centrale de production d'électricité" + }, + "power/line": { + "name": "Câble aérien" + }, + "power/pole": { + "name": "Poteau" + }, + "power/sub_station": { + "name": "Transformateur" + }, + "power/tower": { + "name": "Pylône haute-tension " + }, + "power/transformer": { + "name": "Transformateur" + }, + "railway": { + "name": "Ferroviaire" + }, + "railway/abandoned": { + "name": "Voie ferrée désaffectée" + }, + "railway/disused": { + "name": "Voie ferrée désaffectée" + }, + "railway/level_crossing": { + "name": "Passage à niveau", + "terms": "passage à niveau,garde-barrière" + }, + "railway/monorail": { + "name": "Monorail" + }, + "railway/rail": { + "name": "Voie ferrée" + }, + "railway/station": { + "name": "Gare" + }, + "railway/subway": { + "name": "Métro" + }, + "railway/subway_entrance": { + "name": "Bouche de métro" + }, + "railway/tram": { + "name": "Tramway", + "terms": "Autopartage" + }, "shop": { "name": "Magasin" }, + "shop/alcohol": { + "name": "Magasin de vente d'alcool" + }, + "shop/bakery": { + "name": "Boulangerie" + }, + "shop/beauty": { + "name": "Salon de beauté" + }, + "shop/beverages": { + "name": "Vente de boissons alcolisées" + }, + "shop/bicycle": { + "name": "Magasin de vélos" + }, + "shop/books": { + "name": "Librairie" + }, + "shop/boutique": { + "name": "Petit magasin de mode" + }, "shop/butcher": { - "name": "Boucher " + "name": "Boucher" + }, + "shop/car": { + "name": "Concessionnaire automobile" + }, + "shop/car_parts": { + "name": "Magasin de pièces automobiles" + }, + "shop/car_repair": { + "name": "Garage" + }, + "shop/chemist": { + "name": "Pharmacie" + }, + "shop/clothes": { + "name": "Magasin de vêtements" + }, + "shop/computer": { + "name": "Magasin d'informatique" + }, + "shop/confectionery": { + "name": "Confiserie" + }, + "shop/convenience": { + "name": "Magasin d'appoint" + }, + "shop/deli": { + "name": "Épicerie de luxe" + }, + "shop/department_store": { + "name": "Grand magasin" + }, + "shop/doityourself": { + "name": "Magasin de bricolage" + }, + "shop/dry_cleaning": { + "name": "Nettoyage à sec" + }, + "shop/electronics": { + "name": "Magasin de matériel électronique" + }, + "shop/fishmonger": { + "name": "Poissonnerie" + }, + "shop/florist": { + "name": "Fleuriste" + }, + "shop/furniture": { + "name": "Magasin de meubles" + }, + "shop/garden_centre": { + "name": "Magasin spécialiste du jardin" + }, + "shop/gift": { + "name": "Boutique de cadeaux" + }, + "shop/greengrocer": { + "name": "Primeur" + }, + "shop/hairdresser": { + "name": "Salon de coiffure" + }, + "shop/hardware": { + "name": "Quincaillerie" + }, + "shop/hifi": { + "name": "Magasin de matériel hi-fi" + }, + "shop/jewelry": { + "name": "Bijouterie" + }, + "shop/kiosk": { + "name": "Kiosque" + }, + "shop/laundry": { + "name": "Laverie" + }, + "shop/mall": { + "name": "Centre commercial" + }, + "shop/mobile_phone": { + "name": "Magasin de téléphonie mobile" + }, + "shop/motorcycle": { + "name": "Vendeur de motos" + }, + "shop/music": { + "name": "Vente d'instruments de musique" + }, + "shop/newsagent": { + "name": "Kiosque à journaux" + }, + "shop/optician": { + "name": "Opticien" + }, + "shop/outdoor": { + "name": "Magasin d'équipement de randonnée" + }, + "shop/pet": { + "name": "Animalerie" + }, + "shop/shoes": { + "name": "Magasin de chaussures" + }, + "shop/sports": { + "name": "Magasin d'équipement sportif" + }, + "shop/stationery": { + "name": "Papeterie" }, "shop/supermarket": { - "name": "Supermarche " + "name": "Supermarche", + "terms": "boutique,magasin,supermarché,puces,marché,hypermarché,centre commercial,ZAC,zone d'activité commerciale,kiosque" + }, + "shop/toys": { + "name": "Magasin de jouets" + }, + "shop/travel_agency": { + "name": "Agence de voyages" + }, + "shop/tyres": { + "name": "Magasin de pneus" + }, + "shop/vacant": { + "name": "Commerce désaffecté" + }, + "shop/variety_store": { + "name": "Magasin à prix unique" + }, + "shop/video": { + "name": "Vidéo-club" }, "tourism": { "name": "Tourisme" }, + "tourism/alpine_hut": { + "name": "Refuge de montagne" + }, + "tourism/artwork": { + "name": "Œuvre d'art" + }, + "tourism/attraction": { + "name": "Attraction touristique" + }, + "tourism/camp_site": { + "name": "Camping" + }, + "tourism/caravan_site": { + "name": "Aire pour caravanes" + }, + "tourism/chalet": { + "name": "Chalet" + }, + "tourism/guest_house": { + "name": "Chambre d'hôtes", + "terms": "B&B,Bed & Breakfast,Bed and Breakfast,maison d'hôtes,chambre d'hôtes" + }, + "tourism/hostel": { + "name": "Auberge de jeunesse" + }, + "tourism/hotel": { + "name": "Hôtel" + }, + "tourism/information": { + "name": "Office de tourisme" + }, + "tourism/motel": { + "name": "Motel" + }, "tourism/museum": { - "name": "Musee " + "name": "Musée", + "terms": "exhibition,vernissage,galerie d'art,fondation,musée" + }, + "tourism/picnic_site": { + "name": "Aire de pique-nique" + }, + "tourism/theme_park": { + "name": "Parc d'attraction" + }, + "tourism/viewpoint": { + "name": "Point de vue" + }, + "tourism/zoo": { + "name": "Zoo" + }, + "waterway": { + "name": "Eau" + }, + "waterway/canal": { + "name": "Canal" + }, + "waterway/dam": { + "name": "Barrage" + }, + "waterway/ditch": { + "name": "Fossé" + }, + "waterway/drain": { + "name": "Canal d'évacuation d'eau pluviale" + }, + "waterway/river": { + "name": "Rvière", + "terms": "ruisseau,cours d'eau,caniveau,ru,étier,ruisselet,ravine" + }, + "waterway/riverbank": { + "name": "Berge" + }, + "waterway/stream": { + "name": "Cours d'eau étroit", + "terms": "ruisseau,cours d'eau,caniveau,ru,étier,ruisselet,ravine" + }, + "waterway/weir": { + "name": "Seuil" } } } @@ -10470,11 +11244,16 @@ locale.ja = { }, "circularize": { "title": "円状に並べる", + "description": { + "line": "ラインを円状に整形", + "area": "エリアを円状に整形" + }, "key": "O", "annotation": { "line": "ラインを円状に整形", "area": "エリアを円状に整形" - } + }, + "not_closed": "エリアが閉じられていないため、円状に整形することができません" }, "orthogonalize": { "title": "角の直交化", @@ -10483,7 +11262,8 @@ locale.ja = { "annotation": { "line": "ラインの角を90度に整形", "area": "エリアの角を90度に整形" - } + }, + "not_closed": "エリアが閉じられていないため、四角形に整形することができません" }, "delete": { "title": "削除", @@ -10509,13 +11289,16 @@ locale.ja = { "title": "接続解除", "description": "ウェイの接続を解除して切り離す", "key": "D", - "annotation": "ウェイの接続を解除" + "annotation": "ウェイの接続を解除", + "not_connected": "ライン/エリアの接続を解除できません" }, "merge": { "title": "結合", "description": "複数のラインを結合", "key": "C", - "annotation": "{n} 本のラインを結合" + "annotation": "{n} 本のラインを結合", + "not_eligible": "地物情報がマージできません", + "not_adjacent": "ラインをマージするには、ラインが結合している必要があります。" }, "move": { "title": "移動", @@ -10527,7 +11310,8 @@ locale.ja = { "line": "ラインの移動", "area": "エリアの移動", "multiple": "Moved multiple objects." - } + }, + "incomplete_relation": "地物全体がダウンロードされていないため、移動させることができません。" }, "rotate": { "title": "Rotate", @@ -10546,7 +11330,19 @@ locale.ja = { }, "split": { "title": "分割", - "key": "X" + "description": { + "line": "このポイントを境としてラインを分割", + "area": "このエリアの外周を2つに分割", + "multiple": "このポイントを境としてライン/エリアを分割" + }, + "key": "X", + "annotation": { + "line": "ラインの分割", + "area": "エリア外周を分割", + "multiple": "{n} ライン/エリア外周を分割" + }, + "not_eligible": "基点/終端を境としたライン分割はできません。", + "multiple_ways": "複数のラインを分割します" } }, "nothing_to_undo": "やり直す変更点がありません", @@ -10560,6 +11356,7 @@ locale.ja = { "report_a_bug": "バグ報告", "commit": { "title": "編集結果を保存", + "description_placeholder": "貢献のための簡単な解説", "message_label": "コミットメッセージ", "upload_explanation": "編集した内容を {user} アカウントでアップロードし、OpenStreetMapを利用しているすべてのユーザが閲覧できるようにします", "save": "Save", @@ -10643,12 +11440,21 @@ locale.ja = { "in": "ズームイン", "out": "ズームアウト" }, + "cannot_zoom": "現在のモードでは、これ以上ズームアウトできません。", "gpx": { "local_layer": "ローカルマシン上のGPXファイル", "drag_drop": "この場所に .gpxファイルをドラッグ&ドロップ" }, "help": { - "title": "ヘルプ" + "title": "ヘルプ", + "help": "# ヘルプ\n\nこのアプリケーションは、自由に編集できる世界地図 [OpenStreetMap](http://www.openstreetmap.org/)編集用のエディタです。あなたが知っている地域についての情報を追加したり、編集したりして、誰もが使いやすい情報としてデータをオープンに広めましょう。\n\nあなたが編集した結果は、OpenStreetMapを利用するすべてのひとが閲覧することができます。編集するためには [無料のOpenStreetMapアカウント](https://www.openstreetmap.org/user/new) が必要です。\n\nこの [iD エディタ](http://ideditor.com/) の[ソースコードはGitHubで管理](https://github.com/systemed/iD)されており、誰もが参加できるプロジェクトとして公開されています。\n", + "editing_saving": "# データの編集と保存\n\nこのエディタはオンライン環境で使用されることが前提となっています、現在あなたはブラウザを通じてアクセスしているはずです。\n\n### 地物の選択\n\nポイント情報や道路など地物情報は、地図上に表示されている対象をクリックすることで選択ができます。選択された地物はハイライトされ、詳細情報が記載されたパネルが表示されます。このパネル内の情報を編集することで、対象の地物の情報を編集できます。\n\nキーボードのShiftキーを押しながら地図上をクリックし、ドラッグすることで、地物を範囲選択することが可能です。ドラッグした範囲はボックスで表示され、そのボックス内の地物がすべて選択されます。複数の地物に対して編集を行いたいときに便利です。\n\n### 編集内容の保存\n\n道路や建物、特定の場所などの追加/編集結果は、OSMサーバにセーブされるまではあなたのローカルPC上に格納されます。編集に失敗しても慌てないでください。巻き戻しボタン(Undo)をクリックすることで、編集作業を巻き戻すことができます。同じ編集をもう一度実施したい場合は、巻き戻しのキャンセルボタン(redo)をクリックしてください。\n\n編集に区切りがついたら、'保存'をクリックして作業を終了してください。例えば街の一区画の編集が終わり、そこから別の場所の編集に移動する場合などです。データを保存する前に、編集内容をもう一度見直しましょう。データが間違っている可能性がある場所がエディタ上に表示されますので、必要に応じて修正を行なってください。\n\n編集内容に問題がなければ、そのまま保存を行いましょう。あなたの編集内容を簡潔に表すコメントを記入した後、もう一度'保存'をクリックすると、あなたの編集内容が[OpenStreetMap.org](http://www.openstreetmap.org/)に投稿されます。投稿されたデータはあなた以外のすべての利用者に対しても表示されるようになり、そこに情報を追加したり、編集したりすることができるようになります。\n\n編集を一度に完了させることができない場合は、ブラウザのエディタ表示をそのままにしておきましょう。同じブラウザとエディタを使うことで、後々、作業の続きを実施することができます。\n\n", + "roads": "# 道路\n\nこのエディタは道路を作成、修正、削除する機能を備えています。小路、自動車道、山道、自転車道等々、編集対象となる道路の種別に制限はありません。交差する道路を細かく地図に描くことも可能です。\n\n### 選択\n\n対象の道路をクリックすることで、選択することができます。選択された道路は強調表示され、ラインに対する操作を行う小さなツール項目がその近くに表示されます。道路の詳細情報は、サイドバーに一覧表示されます。\n\n### 修正\n\n既に描かれている道路の中には、背景画像の衛星写真やGPSトラックと明らかに位置が異なるものがあります。そうした道路を見つけたら、道路を正しい位置に修正しましょう。\n\nまずは変更対象となる道路をクリックして選択します。対象の道路が強調表示され、操作可能なポイントがラインの上に表示されて、位置の変更が可能となります。ラインとポイントを、より正しいと思われる位置に移動させてください。ライン上のポイントを増やすには、ラインの上でダブルクリックすることで、その位置にポイントを作成することが可能です。\n\n道路の接続状態が誤っている場合は、どちらかの道路の上に表示されているポイントをもう一つのラインの上に移動させ、2つのラインを接続してください。道路の接続は地図にとって非常に重要であり、車輌のナビゲーションを行うためには道路が正しく接続されていることが必須となります。\n\n'移動'ツールをクリックするか、キーボードでショートカットキー 'M' を押すことで、道路全体を一度に移動させることができます。もう一度クリックすることで、その位置へ対象が移動します。\n\n### 削除\n\n描かれている道路が完全に間違っている場合 - 衛星写真に映っておらず、より理想としては実際に現地で道路が無いことを確認できた場合 - その道路のデータそのものを削除し、地図から消去することが可能です。地物を削除する際の注意として、編集結果は他の編集と同様すべての利用者の目に触れること、また、衛星写真は撮影日時が古い可能性があり、道路が新しく敷設されているかもしれないことを意識してください。\n\n道路を削除するには、対象のラインをクリックして選択し、ツール項目からゴミ箱アイコンをクリックするか、'Delete'キーを押してください。\n\n### 新規作成\n\n道路があるはずなのにまだ描かれていない? エディタ左上に表示されている'ライン'アイコンをクリックするか、ショートカットキー'2'を押すと、ラインの新規描画を行うことができます。\n\n地図をクリックすることで、その地点からラインの描画が開始されます。もし既に描かれている道路から枝分かれした道路の場合は、既存道路で分岐が行われている部分をクリックして、その位置から描画を始めるようにしてください。\n\n衛星画像やGPSログなどで表示されている道路の形に添ってクリックし、ポイントを作成してください。描画している道路が他の道路と交差している場合は、交差している位置でクリックし、ラインを接続してください。描画を終了するには、終了する位置でダブルクリックするか、キーボードの'Return'、あるいは'Enter'キーを押してください。\n\n", + "gps": "# GPS\n\nOpenStreetMapにおいて、GPSデータは最も信用できる情報源です。iDエディタはあなたのPC上にある`.gpx`ファイルのトレース機能をサポートしています。GPSログは、スマートフォンのアプリケーションやGPSロガーを使用することで収集することができます。\n\nGPSを使用した現地調査の詳細な進め方については、 [GPSによる調査](http://learnosm.org/jp/beginner/using-gps/)を参照してください。\n\nGPXログファイルをエディタの上にドラッグ&ドロップすることで、ファイルの内容をエディタ上に表示させることができます。ファイル形式の読み込みが正常に完了すると、ログは明るい緑色の線としてエディタ上に表示されます。エディタの左側に配置されている'背景画像設定'メニューをクリックすると、ログの表示/非表示、GPXが配置されたレイヤーへのズームを設定することができます。\n\nこのGPXログファイルはOpenStreetMapへ直接アップロードされたものではありません。このログを参考情報として地図を描いたり、あなたが追加する地物の配置場所の参考情報とするのがよいでしょう。\n", + "imagery": "# 背景画像\n\n地図を作成するにあたって、航空写真は重要なリソースのひとつです。上空からの撮影、衛星写真、自由な利用が認められた情報源などは、画面左側の'背景画像設定'メニューから表示させることが可能です。\n\nデフォルト設定では[Bing Maps](http://www.bing.com/maps/)の衛星写真レイヤーが表示されていますが、地図のズームレベル変更などで新しい場所を表示する際に別のリソースを表示させることが可能です。英国やフランス、デンマークでは、特定の地域に限り非常に細密な画像が利用可能です。\n\n画像提供側の間違いが原因で、背景画像と地図データの位置がずれていることがあります。既存道路の多くが一方向にずれている場合、すべての地物の位置を一度に移動させてしまう前に背景画像の表示位置を調整し、オフセットがされていないか確認を行なってください。位置の調整は、背景画像設定の一番下に表示されている'背景画像をずらす'という項目から行うことができます。\n", + "addresses": "# 住所\n\n住所情報は地図において最も有用な情報のひとつです。\n\n住所情報は街路の付帯情報として扱われることがほとんどですが、OpenStreetMapにおける住所情報は、街路にそって配置されている建物の属性として記録されます。\n\n住所情報は建物を表す輪郭に付与しても構いませんし、独立したポイントとして配置してもかまいません。また、住所データの最適な情報源は現地調査、あるいは個人の記憶によるものです。GoogleMapsなど、他の地図からの転載は特別な許諾がない限り固く禁止されています。\n\n注: 日本では住所システムの体系が異なるため、街路を基とする上記の方法を適用することはできません。\n", + "inspector": "# 地物情報表示ウィンドウ\n\n地図上の地物を選択すると、画面右側に入力ウィンドウが表示されます。地物に関する詳細情報の編集はこのウィンドウから行います。\n\n### 地物種別の選択\n\nポイントやライン、エリアを描画する際、描いた地物の種別を選択することができます。これによって、ラインが高速道路なのか住宅道路なのか、ポイントがスーパーマーケットなのか喫茶店なのか、などを表現します。地物情報表示ウィンドウには、よく利用される地物が表示されています。その他の地物を表示させたい場合は、検索ボックスから検索を行なってください。\n\n地物種別が表示されている右下にある'i'ボタンをクリックすることで、その種別の詳細情報を表示させることができます。アイコンをクリックすることで、種別を確定させることができます。\n\n### フォームを利用したタグ編集\n\n地物の種別を選択した後、あるいは既になんらかの種別が割り当て済の対象を選択した際には、その地物の名称や住所などの詳細情報がウィンドウ内に表示されます。\n\n表示中のフィールドの下部にあるアイコンをクリックすると、追加の入力フィールドが表示されます。例えば[Wikipedia](http://www.wikipedia.org/)情報や、車椅子の利用可否などです。\n\n入力ウィンドウの一番下に配置されている 'タグ項目を追加'をクリックすると、要素に対する自由記入フォームが表示されます。利用されることが多いタグの組み合わせは[Taginfo](http://taginfo.openstreetmap.org/)から検索が可能です。\n\n入力ウィンドウに記入した内容は、エディタ上の地図に即座に反映されます。'やり直し'ボタンをクリックすることで、いつでも入力内容を取り消すことが可能です。\n\n### 地物情報表示ウィンドウを閉じる\n\nウィンドウを閉じるには、ウィンドウ右上のXボタンをクリックするか、キーボードの'Escape'キーを押すか、地図上のどこかをクリックしてください。\n", + "buildings": "# 建物\n\nOpenStreetMapは世界でも有数の建物情報データベースです。このデータベースへの情報追加や改善は誰しもが参加可能です。\n\n### 選択\n\n建物の輪郭をクリックすると、その建物を選択することができます。建物はハイライト表示され、小さなツール項目と、画面右側にその建物の詳細情報が表示されます。\n\n### 修正\n\n建物の位置や、付与されているタグが誤っていることがあります。\n\n建物全体の位置を移動させるには、'移動'ツールのアイコンをクリックしてください。マウスを動かして建物を正しい位置へ移動させ、もう一度クリックして位置を確定させます。\n\n同様に、建物を形成しているポイントをクリックして正しい位置へ移動させることで、建物の形状を修正することができます。\n\n### 新規作成\n\nOpenStreetMapで建物を描く場合によくあがる質問として、建物をエリアとポイントのどちらで描いたほうがよいか、というものがあります。最善の方法では _できる限り、建物はエリアとして描き_ 、会社や個人宅、施設など、建物から独立した情報は別途ポイントとして、エリアとして描かれた建物の内側に配置します。\n\n画面左上に表示されている項目から'エリア'ボタンをクリックして、建物をエリアとして描いてみましょう。エリアの描画を終了するにはキーボードの'Return'キーを押すか、エリアを描き始めたポイントをもう一度クリックしてください。\n\n### 削除\n\nもし建物の情報が完全に間違っている場合 - 衛星写真に映っておらず、より理想としては実際に現地で建物が無いことを確認できた場合 - その建物データそのものを削除し、地図から消去することが可能です。地物を削除する際の注意として、編集結果は他の編集と同様すべての利用者の目に触れること、また、衛星写真は撮影日時が古い可能性があり、建物が新しく建設されているかもしれないことを意識してください。\n\n建物を削除するには、対象をクリックして選択し、ツール項目からゴミ箱アイコンをクリックするか、'Delete'キーを押してください。\n" }, "intro": { "navigation": { @@ -10671,13 +11477,26 @@ locale.ja = { }, "areas": { "add": "エリアで描くことで、その地物をより詳細に描いてみましょう。ポイントと違い、エリアではその地物の境界線を表現することが可能です。ポイントで表現している地物のほとんどは、エリアとしても描くことが可能です。**エリアボタンをクリックすることで、新しいエリアを描くことができます。**", + "corner": "複数のポイントを描くことで、エリアの境界線を表現することができます。**エリアを作成して、児童公園を描いてみましょう。**", "place": "ポイントを描くことで、エリアを表現することができます。エリアの描画を完了するには、描き始めた場所をもう一度クリックしてください。**エリアを作成して、児童公園を描いてみましょう。**", "search": "**児童公園を検索**", "choose": "**画面から児童公園を選択**", "describe": "**児童公園に名称を追加して、タグ情報編集ウィンドウを閉じましょう。**" }, "lines": { - "add": "ラインは道路や線路、河川など、線として表現される情報を示すことができます。**ライン ボタンをクリックして、新しくラインを描いてみましょう。**" + "add": "ラインは道路や線路、河川など、線として表現される情報を示すことができます。**ライン ボタンをクリックして、新しくラインを描いてみましょう。**", + "start": "**地図上をクリックすることで、ラインの描画が開始されます。まずは道路を描いてみましょう。**", + "intersect": "ライン上をクリックすることで、その位置にポイントが作成されます。ラインを描いている途中でも、必要な場合は表示位置をドラッグして移動させることが可能です。道路をはじめとして多くのラインは、より大きなネットワークに接続されています。経路探索アプリケーションを正常に動作させるため、ラインは他のラインと正常に接続されていることが重要です。**Flower Streetをクリックして、2本のラインの交差点を作成してみましょう。**", + "finish": "最後のポイントをもう一度クリックすることで、ラインの描画を完了させることができます。**道路の描画を完了させましょう。**", + "road": "**グリッドの中から道路を選択してください**", + "residential": "道路にはいくつもの種類があり、住宅道路が最もよく使われます。**道路種別から住宅道路を選択してください。**", + "describe": "**道路に名前情報を付与して、詳細情報ウィンドウを閉じます**", + "restart": "この街路は、Flower Streetと接続する必要があります。" + }, + "startediting": { + "help": "より詳しい解説を含め、全文は以下から閲覧可能です。", + "save": "変更内容はこまめに保存するよう気をつけてください!", + "start": "マッピング開始!" } }, "presets": { @@ -10688,10 +11507,15 @@ locale.ja = { "address": { "label": "住所", "placeholders": { + "housename": "地番", "number": "123", + "street": "所属する街路名", "city": "市町村名" } }, + "admin_level": { + "label": "Admin Level" + }, "aeroway": { "label": "タイプ" }, @@ -10719,9 +11543,15 @@ locale.ja = { "capacity": { "label": "収容可能な数量" }, + "collection_times": { + "label": "情報取得日時" + }, "construction": { "label": "タイプ" }, + "country": { + "label": "Country" + }, "crossing": { "label": "タイプ" }, @@ -10731,6 +11561,9 @@ locale.ja = { "denomination": { "label": "宗派" }, + "denotation": { + "label": "表示" + }, "elevation": { "label": "標高" }, @@ -10900,7 +11733,8 @@ locale.ja = { "name": "施設, amenity" }, "amenity/bank": { - "name": "銀行" + "name": "銀行", + "terms": "資金調達、会計事務所、信用組合、受託銀行、ファンド、投資信託、準備銀行" }, "amenity/bar": { "name": "バー" @@ -10919,7 +11753,11 @@ locale.ja = { "terms": "コーヒー, 紅茶, 喫茶店" }, "amenity/cinema": { - "name": "映画館" + "name": "映画館", + "terms": "映画館、上映施設、スクリーン、銀幕" + }, + "amenity/courthouse": { + "name": "裁判所" }, "amenity/embassy": { "name": "大使館" @@ -10937,7 +11775,8 @@ locale.ja = { "name": "墓地" }, "amenity/hospital": { - "name": "病院" + "name": "病院", + "terms": "クリニック、緊急医療施設、健保サービス、ホスピス、診療所、老人ホーム、療養所、病室、外科医、病棟" }, "amenity/library": { "name": "図書館" @@ -10952,10 +11791,12 @@ locale.ja = { "name": "薬局, ドラッグストア" }, "amenity/place_of_worship": { - "name": "宗教施設" + "name": "宗教施設", + "terms": "修道院、会堂、礼拝堂、聖堂、内陣、教会、チャペル、祈祷所、神の家、祈りの場所、モスク、神社、寺院、シナゴーグ" }, "amenity/place_of_worship/christian": { - "name": "教会" + "name": "教会", + "terms": "修道院、会堂、礼拝堂、聖堂、内陣、教会、チャペル、祈祷所、神の家、祈りの場所、モスク、神社、寺院、シナゴーグ" }, "amenity/place_of_worship/jewish": { "name": "シナゴーグ", @@ -10966,10 +11807,12 @@ locale.ja = { "terms": "イスラム教, モスク" }, "amenity/police": { - "name": "警察" + "name": "警察", + "terms": "警察署、警察、交番、派出所" }, "amenity/post_box": { - "name": "郵便ポスト" + "name": "郵便ポスト", + "terms": "投函箱、郵便ポスト" }, "amenity/post_office": { "name": "郵便局" @@ -10978,10 +11821,12 @@ locale.ja = { "name": "居酒屋, パブ" }, "amenity/restaurant": { - "name": "レストラン" + "name": "レストラン", + "terms": "バー、カフェテリア、カフェ、喫茶店、喫茶室、ダイナー、ディナールーム、ドーナツ店、軽飲食、食事処、休憩所、茶屋、ハンバーガースタンド、ホットドッグスタンド、ランチルーム、ピッツァリア、サロン、お休み処" }, "amenity/school": { - "name": "学校" + "name": "学校", + "terms": "大学、短大、単科大学、職業訓練所、専門学校、研究所、牢獄、校舎、学舎" }, "amenity/swimming_pool": { "name": "プール" @@ -10997,7 +11842,8 @@ locale.ja = { "name": "お手洗い, トイレ" }, "amenity/townhall": { - "name": "市町村役場" + "name": "市町村役場", + "terms": "村役場、市役所、郡庁舎、市営ビル、市区センター" }, "amenity/university": { "name": "大学" @@ -11011,6 +11857,9 @@ locale.ja = { "barrier/bollard": { "name": "杭" }, + "barrier/cattle_grid": { + "name": "家畜柵" + }, "barrier/city_wall": { "name": "市壁" }, @@ -11029,15 +11878,30 @@ locale.ja = { "barrier/gate": { "name": "門, ゲート" }, + "barrier/hedge": { + "name": "垣根" + }, "barrier/kissing_gate": { "name": "牧場用ゲート" }, + "barrier/lift_gate": { + "name": "遮断ゲート" + }, + "barrier/retaining_wall": { + "name": "擁壁" + }, + "barrier/stile": { + "name": "踏み越し段" + }, "barrier/toll_booth": { "name": "料金所" }, "barrier/wall": { "name": "壁" }, + "boundary/administrative": { + "name": "行政区境" + }, "building": { "name": "建物" }, @@ -11047,6 +11911,9 @@ locale.ja = { "building/entrance": { "name": "エントランス" }, + "building/house": { + "name": "番地" + }, "entrance": { "name": "エントランス" }, @@ -11054,19 +11921,22 @@ locale.ja = { "name": "道路" }, "highway/bridleway": { - "name": "乗馬道" + "name": "乗馬道", + "terms": "大通り、乗馬道、馬道" }, "highway/bus_stop": { "name": "バス停" }, "highway/crossing": { - "name": "横断歩道" + "name": "横断歩道", + "terms": "横断歩道" }, "highway/cycleway": { "name": "自転車道" }, "highway/footway": { - "name": "歩道" + "name": "歩道", + "terms": "けもの道、山道、コース、歩道、自動車道、路地、航路、軌道、抜け道、通路、小路、線路、道路、経路、街道、農道、大通り" }, "highway/motorway": { "name": "高速道路" @@ -11135,6 +12005,12 @@ locale.ja = { "historic": { "name": "歴史的な場所" }, + "historic/archaeological_site": { + "name": "考古遺跡" + }, + "historic/boundary_stone": { + "name": "境界石碑" + }, "historic/castle": { "name": "城郭" }, @@ -11159,6 +12035,12 @@ locale.ja = { "landuse/allotments": { "name": "市民菜園" }, + "landuse/basin": { + "name": "遊水地" + }, + "landuse/cemetery": { + "name": "霊園" + }, "landuse/commercial": { "name": "商業区" }, @@ -11208,7 +12090,8 @@ locale.ja = { "name": "停泊所" }, "leisure/park": { - "name": "公園" + "name": "公園", + "terms": "遊歩道、森林、庭園、芝生、緑地、遊び場、プラザ、レクリエーションエリア、スクエア、広場" }, "leisure/pitch": { "name": "運動場" @@ -11228,9 +12111,15 @@ locale.ja = { "leisure/pitch/tennis": { "name": "テニスコート" }, + "leisure/playground": { + "name": "児童公園" + }, "leisure/slipway": { "name": "進水所" }, + "leisure/stadium": { + "name": "スタジアム" + }, "leisure/swimming_pool": { "name": "プール" }, @@ -11246,9 +12135,16 @@ locale.ja = { "man_made/survey_point": { "name": "調査・観測地点" }, + "man_made/wastewater_plant": { + "name": "下水処理施設", + "terms": "浄水設備、排水処理施設、下水処理場" + }, "man_made/water_tower": { "name": "給水塔" }, + "man_made/water_works": { + "name": "上下水施設" + }, "natural": { "name": "自然物" }, @@ -11262,7 +12158,8 @@ locale.ja = { "name": "崖" }, "natural/coastline": { - "name": "海岸線" + "name": "海岸線", + "terms": "海岸" }, "natural/glacier": { "name": "氷河, 凍土" @@ -11274,7 +12171,8 @@ locale.ja = { "name": "低木地" }, "natural/peak": { - "name": "山頂" + "name": "山頂", + "terms": "岩峰、山頂、頂、頂点、てっぺん、山、丘、丘陵、極み" }, "natural/scrub": { "name": "茂み" @@ -11289,10 +12187,12 @@ locale.ja = { "name": "水面" }, "natural/water/lake": { - "name": "湖" + "name": "湖", + "terms": "湖、入江、池" }, "natural/water/pond": { - "name": "池" + "name": "池", + "terms": "池、水車用貯水池、ため池、小さな湖" }, "natural/water/reservoir": { "name": "貯水池" @@ -11312,12 +12212,25 @@ locale.ja = { "other_area": { "name": "その他" }, + "place": { + "name": "地名" + }, + "place/hamlet": { + "name": "Hamlet" + }, "place/island": { - "name": "島" + "name": "島", + "terms": "群島、サンゴ礁、小島、岩礁、砂州、湾岸" + }, + "place/locality": { + "name": "Locality" }, "place/village": { "name": "村" }, + "power": { + "name": "電力" + }, "power/generator": { "name": "発電所" }, @@ -11333,6 +12246,9 @@ locale.ja = { "power/tower": { "name": "送電塔" }, + "power/transformer": { + "name": "変圧施設" + }, "railway": { "name": "線路" }, @@ -11343,17 +12259,28 @@ locale.ja = { "name": "廃棄済み路線" }, "railway/level_crossing": { - "name": "踏切" + "name": "踏切", + "terms": "踏切" + }, + "railway/monorail": { + "name": "モノレール" }, "railway/rail": { "name": "線路" }, + "railway/station": { + "name": "鉄道駅" + }, "railway/subway": { "name": "地下鉄" }, "railway/subway_entrance": { "name": "地下鉄入り口" }, + "railway/tram": { + "name": "トラム", + "terms": "路面電車" + }, "shop": { "name": "店舗" }, @@ -11453,6 +12380,9 @@ locale.ja = { "shop/kiosk": { "name": "キオスク" }, + "shop/laundry": { + "name": "コインランドリー" + }, "shop/mall": { "name": "ショッピングセンター" }, @@ -11462,6 +12392,12 @@ locale.ja = { "shop/motorcycle": { "name": "バイク販売" }, + "shop/music": { + "name": "CD/レコード" + }, + "shop/newsagent": { + "name": "新聞" + }, "shop/optician": { "name": "メガネ" }, @@ -11481,7 +12417,8 @@ locale.ja = { "name": "文具店" }, "shop/supermarket": { - "name": "スーパーマーケット" + "name": "スーパーマーケット", + "terms": "店舗、ショッピングプラザ、バザー、ブティック、チェーン店、安売り販売、ガレリア、モール、マート、アウトレット、ショッピングセンター、スーパーマーケット、中古品販売" }, "shop/toys": { "name": "おもちゃ屋" @@ -11523,16 +12460,24 @@ locale.ja = { "name": "コテージ" }, "tourism/guest_house": { - "name": "民宿" + "name": "民宿", + "terms": "B&B、ベッドアンドブレックファスト" + }, + "tourism/hostel": { + "name": "共同宿泊" }, "tourism/hotel": { "name": "ホテル" }, + "tourism/information": { + "name": "観光案内" + }, "tourism/motel": { "name": "モーテル" }, "tourism/museum": { - "name": "博物館, 美術館" + "name": "博物館, 美術館", + "terms": "展示、ギャラリー、ホール、図書館、現代美術、見世物" }, "tourism/picnic_site": { "name": "ピクニック場" @@ -11562,13 +12507,15 @@ locale.ja = { "name": "排水路" }, "waterway/river": { - "name": "河川" + "name": "河川", + "terms": "小川、渓流、支流、流れ、細流、入江、河口、水脈、川床、水路" }, "waterway/riverbank": { "name": "河川流域" }, "waterway/stream": { - "name": "小川" + "name": "小川", + "terms": "小川、渓流、支流、流れ、細流、入江、河口、水脈、川床、水路、氾濫、浸水域、湿地" }, "waterway/weir": { "name": "堰" @@ -12360,14 +13307,14 @@ locale.pl = { }, "geocoder": { "title": "Znajdź miejsce", - "placeholder": "znajdź miejsce", + "placeholder": "Znajdź miejsce", "no_results": "Nie można znaleźć miejsca o nazwie '{name}'" }, "geolocate": { - "title": "Pokaż moją pozycję." + "title": "Pokaż moją pozycję" }, "inspector": { - "no_documentation_combination": "Nie ma dokumentacji dla tej kombinacji tagu.", + "no_documentation_combination": "Nie ma dokumentacji dla tej kombinacji tagu", "no_documentation_key": "Nie ma dokumentacji dla tego klucza", "show_more": "Pokaż więcej", "new_tag": "Nowy tag", @@ -12428,6 +13375,7 @@ locale.pl = { "in": "Powiększ", "out": "Zmniejsz" }, + "cannot_zoom": "Nie można bardziej oddalić widoku w obecnym trybie.", "gpx": { "local_layer": "Lokalny plik GPX", "drag_drop": "Przeciągnij i upuść plik .gpx na stronę" @@ -12500,6 +13448,9 @@ locale.pl = { "city": "Miasto" } }, + "admin_level": { + "label": "Poziom administracyjny" + }, "aeroway": { "label": "Typ" }, @@ -12830,9 +13781,15 @@ locale.pl = { "barrier/bollard": { "name": "Słupek" }, + "barrier/cattle_grid": { + "name": "Przeszkoda dla bydła" + }, "barrier/city_wall": { "name": "Mur miejski" }, + "barrier/cycle_barrier": { + "name": "Przegroda dla rowerzystów" + }, "barrier/ditch": { "name": "Rów" }, @@ -12848,12 +13805,24 @@ locale.pl = { "barrier/hedge": { "name": "Żywopłot" }, + "barrier/lift_gate": { + "name": "Szlaban" + }, + "barrier/retaining_wall": { + "name": "Mur oporowy" + }, "barrier/stile": { "name": "Przełaz" }, + "barrier/toll_booth": { + "name": "Punkt poboru opłat" + }, "barrier/wall": { "name": "Mur" }, + "boundary/administrative": { + "name": "Granica administracyjna" + }, "building": { "name": "Budynek" }, @@ -12863,6 +13832,9 @@ locale.pl = { "building/entrance": { "name": "Wejście" }, + "building/house": { + "name": "Dom" + }, "entrance": { "name": "Wejście" }, @@ -12928,15 +13900,30 @@ locale.pl = { "historic": { "name": "Miejsce historyczne" }, + "historic/archaeological_site": { + "name": "Wykopalisko archeologiczne" + }, + "historic/boundary_stone": { + "name": "Kamień graniczny" + }, "historic/castle": { "name": "Zamek" }, + "historic/memorial": { + "name": "Miejsce pamięci" + }, "historic/monument": { "name": "Pomnik" }, "historic/ruins": { "name": "Ruiny" }, + "historic/wayside_cross": { + "name": "Przydrożny krzyż" + }, + "historic/wayside_shrine": { + "name": "Przydrożna kapliczka" + }, "landuse": { "name": "Użytkowanie gruntów" }, @@ -12994,6 +13981,9 @@ locale.pl = { "leisure/golf_course": { "name": "Pole golfowe" }, + "leisure/marina": { + "name": "Przystań" + }, "leisure/park": { "name": "Park" }, @@ -13018,6 +14008,9 @@ locale.pl = { "leisure/playground": { "name": "Plac zabaw" }, + "leisure/slipway": { + "name": "Pochylnia okrętowa" + }, "leisure/stadium": { "name": "Stadion" }, @@ -13036,9 +14029,15 @@ locale.pl = { "man_made/survey_point": { "name": "Punkt geodezyjny" }, + "man_made/wastewater_plant": { + "name": "Oczyszczalnia ścieków" + }, "man_made/water_tower": { "name": "Wieża ciśnień" }, + "man_made/water_works": { + "name": "Filtracja wody" + }, "natural": { "name": "Natura" }, @@ -13121,9 +14120,18 @@ locale.pl = { "power/generator": { "name": "Elektrownia" }, + "power/line": { + "name": "Linia elektryczna" + }, + "power/pole": { + "name": "Słup elektryczny" + }, "power/sub_station": { "name": "Podstacja" }, + "power/tower": { + "name": "Wieża wysokiego napięcia" + }, "power/transformer": { "name": "Transformator" }, @@ -13133,12 +14141,18 @@ locale.pl = { "railway/abandoned": { "name": "Nieużywany tor" }, + "railway/disused": { + "name": "Nieużywany tor" + }, "railway/level_crossing": { "name": "Rogatka" }, "railway/rail": { "name": "Tor" }, + "railway/station": { + "name": "Dworzec kolejowy" + }, "railway/subway": { "name": "Metro" }, @@ -13157,6 +14171,12 @@ locale.pl = { "shop/bakery": { "name": "Piekarnia" }, + "shop/beauty": { + "name": "Salon piękności" + }, + "shop/bicycle": { + "name": "Sklep rowerowy" + }, "shop/books": { "name": "Księgarnia" }, @@ -13166,12 +14186,42 @@ locale.pl = { "shop/butcher": { "name": "Rzeźnik" }, + "shop/car": { + "name": "Dealer samochodowy" + }, + "shop/car_parts": { + "name": "Sklep z częściami do samochodów" + }, + "shop/car_repair": { + "name": "Warsztat samochodowy" + }, + "shop/chemist": { + "name": "Drogeria" + }, + "shop/clothes": { + "name": "Sklep odzieżowy" + }, "shop/computer": { "name": "Sklep komputerowy" }, "shop/confectionery": { "name": "Konfekcja" }, + "shop/convenience": { + "name": "Sklep ogólnospożywczy" + }, + "shop/deli": { + "name": "Delikatesy" + }, + "shop/department_store": { + "name": "Dom towarowy" + }, + "shop/doityourself": { + "name": "Sklep dla majsterkowiczów" + }, + "shop/dry_cleaning": { + "name": "Pralnia chemiczna" + }, "shop/electronics": { "name": "Sklep elektroniczny" }, @@ -13184,12 +14234,21 @@ locale.pl = { "shop/furniture": { "name": "Sklep meblowy" }, + "shop/garden_centre": { + "name": "Centrum ogrodnicze" + }, "shop/greengrocer": { "name": "Warzywniak" }, "shop/hairdresser": { "name": "Fryzjer" }, + "shop/hardware": { + "name": "Sklep z narzędziami" + }, + "shop/hifi": { + "name": "Sklep ze sprzętem Hi-fi" + }, "shop/jewelry": { "name": "Jubiler" }, @@ -13202,6 +14261,12 @@ locale.pl = { "shop/mall": { "name": "Centrum handlowe" }, + "shop/mobile_phone": { + "name": "Sklep z telefonami komórkowymi" + }, + "shop/motorcycle": { + "name": "Dealer motocykli" + }, "shop/music": { "name": "Sklep muzyczny" }, @@ -13211,6 +14276,9 @@ locale.pl = { "shop/optician": { "name": "Optyk" }, + "shop/outdoor": { + "name": "Sklep turystyczny" + }, "shop/pet": { "name": "Sklep zoologiczny" }, @@ -14190,6 +15258,7 @@ locale.ru = { }, "intro": { "startediting": { + "save": "Не забывайте регулярно сохранять свои изменения!", "start": "Рисовать карту" } }, @@ -14583,6 +15652,9 @@ locale.ru = { "building/entrance": { "name": "Вход" }, + "building/house": { + "name": "Дом" + }, "entrance": { "name": "Вход" }, @@ -14809,7 +15881,8 @@ locale.ru = { "name": "Скала" }, "natural/coastline": { - "name": "Береговая линия" + "name": "Береговая линия", + "terms": "берег" }, "natural/glacier": { "name": "Ледник" @@ -14979,6 +16052,9 @@ locale.ru = { "shop/department_store": { "name": "Универсам" }, + "shop/electronics": { + "name": "Магазин электроники" + }, "shop/fishmonger": { "name": "Рыбный магазин" }, @@ -15205,6 +16281,10 @@ locale.es = { }, "circularize": { "title": "Redondear", + "description": { + "line": "Redondear línea", + "area": "Redondear área." + }, "key": "O", "annotation": { "line": "Redondear línea.", @@ -15250,7 +16330,9 @@ locale.es = { "title": "Combinar", "description": "Combinar líneas.", "key": "C", - "annotation": "{n} líneas combinadas." + "annotation": "{n} líneas combinadas.", + "not_eligible": "Estos elementos no pueden ser juntados", + "not_adjacent": "Estas líneas no pueden ser juntadas porque no están conectadas" }, "move": { "title": "Mover", @@ -15263,6 +16345,15 @@ locale.es = { "area": "Área movida" } }, + "rotate": { + "title": "Rotar", + "description": "Rotar objeto sobre su punto central", + "key": "R", + "annotation": { + "line": "Línea rotada", + "area": "Área rotada" + } + }, "reverse": { "title": "Invertir", "description": "Invertir sentido de la linea.", @@ -15271,7 +16362,14 @@ locale.es = { }, "split": { "title": "Dividir", - "key": "D" + "description": { + "line": "Dividir línea en dos en este punto" + }, + "key": "D", + "annotation": { + "line": "Dividir línea" + }, + "multiple_ways": "Hay demasiadas líneas para dividir" } }, "nothing_to_undo": "Nada que deshacer", @@ -15281,10 +16379,12 @@ locale.es = { "view_on_osm": "Ver en OSM", "zoom_in_edit": "Acerca para editar el mapa", "logout": "Cerrar sesión", + "loading_auth": "Conectando a OpenStreetMap", "report_a_bug": "Reportar un error", "commit": { "title": "Guardar Cambios", "description_placeholder": "Breve descripción de tus contribuciones", + "message_label": "Mensaje de commit", "upload_explanation": "Los cambios que subes como {user} serán visibles en todos los mapas que usen datos de OpenStreetMap.", "save": "Guardar", "cancel": "Cancelar", @@ -15308,8 +16408,15 @@ locale.es = { "inspector": { "no_documentation_combination": "No hay documentación disponible para esta combinación de etiquetas", "no_documentation_key": "No hay documentación disponible para esta tecla", + "show_more": "Ver más", "new_tag": "Nueva etiqueta", - "view_on_osm": "Ver en OSM" + "view_on_osm": "Ver en OSM", + "editing_feature": "Editando {feature}", + "additional": "Etiquetas adicionales", + "choose": "Selecciona tipo", + "results": "{n} resultados para {search}", + "reference": "Ver en OpenStreetMap Wiki →", + "back_tooltip": "Cambiar tipo" }, "background": { "title": "Fondo", @@ -15319,6 +16426,7 @@ locale.es = { "reset": "reiniciar" }, "restore": { + "heading": "Tienes cambios sin guardar", "description": "Tienes cambios no guardados de una sesión de edición previa. ¿Quieres recuperar tus cambios?", "restore": "Restaurar", "reset": "Descartar" @@ -15326,16 +16434,19 @@ locale.es = { "save": { "title": "Guardar", "help": "Guardar los cambios en OpenStreetMap haciéndolos visibles a otros usuarios.", + "no_changes": "No hay cambios.", "error": "Ha ocurrido un error tratando de guardar", "uploading": "Subiendo cambios a OpenStreetMap", "unsaved_changes": "Tienes cambios sin guardar" }, "splash": { "welcome": "Bienvenido al editor de OpenStreetMap iD", - "text": "Esto es una versión {version} de desarrollo. Para más información visita {website} y reporta cualquier error en {github}." + "text": "Esto es una versión {version} de desarrollo. Para más información visita {website} y reporta cualquier error en {github}.", + "start": "Editar" }, "source_switch": { "live": "en vivo", + "lose_changes": "Tienes cambios sin guardar. Si cambias de servidor de mapas, tus cambios serán descartados. Estas seguro?", "dev": "dev" }, "tag_reference": { @@ -15354,6 +16465,21 @@ locale.es = { "zoom": { "in": "Acercar", "out": "Alejar" + }, + "gpx": { + "local_layer": "Archivo GPX local", + "drag_drop": "Arrastra un fichero .gpx a la página" + }, + "help": { + "title": "Ayuda" + }, + "intro": { + "points": { + "fixname": "Cambiar nombre y cerrar el editor" + }, + "startediting": { + "start": "Empezar" + } } }; locale.sv = { @@ -16086,6 +17212,9 @@ locale.tr = { "aeroway/helipad": { "name": "Helikopter Pisti" }, + "amenity": { + "name": "Dinlenme tesisi" + }, "amenity/bank": { "name": "Banka" }, @@ -16212,6 +17341,9 @@ locale.tr = { "entrance": { "name": "Giriş" }, + "highway": { + "name": "Otoyol" + }, "highway/bus_stop": { "name": "Otobüs Durağı" }, @@ -16269,6 +17401,9 @@ locale.tr = { "landuse/industrial": { "name": "Endüstri" }, + "landuse/meadow": { + "name": "Çayır" + }, "landuse/residential": { "name": "Yerleşim" }, @@ -16433,6 +17568,9 @@ locale.tr = { }, "waterway/river": { "name": "Akarsu" + }, + "waterway/stream": { + "name": "Dere" } } } @@ -16492,11 +17630,16 @@ locale.uk = { }, "circularize": { "title": "Закруглити", + "description": { + "line": "Робить з лінії коло.", + "area": "Перетворює полігон на коло." + }, "key": "O", "annotation": { "line": "Лінія перетворена на коло.", "area": "Полігон перетворено на коло." - } + }, + "not_closed": "Неможливо перетворити на коло — лінія не замкнена." }, "orthogonalize": { "title": "Ортогоналізувати", @@ -16505,7 +17648,8 @@ locale.uk = { "annotation": { "line": "Випрямлено кути лінії.", "area": "Випрямлено кути полігону." - } + }, + "not_closed": "Неможливо зробити кути прямими — лінія не замкнена." }, "delete": { "title": "Вилучити", @@ -16531,13 +17675,16 @@ locale.uk = { "title": "Роз’єднати", "description": "Роз’єднати лінії одна від одної.", "key": "D", - "annotation": "Роз’єднано лінії." + "annotation": "Роз’єднано лінії.", + "not_connected": "Недостатньо ліній/полігонів для роз’єднання." }, "merge": { "title": "Поєднати", "description": "Поєднати лінії.", "key": "C", - "annotation": "З’єднати {n} ліній." + "annotation": "З’єднати {n} ліній.", + "not_eligible": "Ці об’єкти неможливо злити.", + "not_adjacent": "Ці лінії неможливо злити, бо вони не з’єднані." }, "move": { "title": "Посунтуи", @@ -16549,7 +17696,8 @@ locale.uk = { "line": "Лінію посунуто.", "area": "Полігон посунуто.", "multiple": "Посунуто кілька об’єктів." - } + }, + "incomplete_relation": "Цей об’єкт неможливо посунути, бо він не повністю завантажний." }, "rotate": { "title": "Обернути", @@ -16568,7 +17716,17 @@ locale.uk = { }, "split": { "title": "Розділити", - "key": "X" + "description": { + "line": "Розділити лінію на дві в цій точці.", + "area": "Розділити межі цього полігону надвоє.", + "multiple": "Розділити лінію/полігон надвоє в цій точці." + }, + "key": "X", + "annotation": { + "line": "Розділити лінію." + }, + "not_eligible": "Неможливо розділити лінію на її початку чи кінці.", + "multiple_ways": "Забагато ліній для розділення." } }, "nothing_to_undo": "Скасовувати нічого.", @@ -16610,7 +17768,7 @@ locale.uk = { "show_more": "Ще", "new_tag": "Новий теґ", "view_on_osm": "Подивтись в ОСМ", - "editing_feature": "Властивості {feature}", + "editing_feature": "{feature}", "additional": "Додаткові теґи", "choose": "Виберіть тип об’єкту", "results": "знайдено {n} об’єктів на запит {search}", @@ -16658,6 +17816,7 @@ locale.uk = { "untagged_point": "Точка без теґів, що не є частиною лінію чи полігону", "untagged_line": "Лінія без теґів", "untagged_area": "Полігон без теґів", + "many_deletions": "Ви збираєтесь вилучити {n} об’єктів. Ви дійсно бажаєте це зробити? Таке вилучення призведе до їх зникнення з мапи openstreetmap.org.", "tag_suggests_area": "Теґ {tag} зазвичай ставться на полігони, але об’єкт ним не є", "deprecated_tags": "Застарілі теґи: {tags}" }, @@ -16672,13 +17831,28 @@ locale.uk = { "help": { "title": "Довідка", "help": "# Довідка\n\nЦе редактор для [OpenStreetMap](http://www.openstreetmap.org/),\nвільної мапи світу, яку може редагувати кожний. Ви можете використовувати \nредактор для додавання та уточнення даних у вашій місцевості, роблячи \nмапу вільних та відкритих даних світу ще кращою.\n\nВаші правки будуть доступні кожному, хто користується мапою OpenStreetMap. \nДля того, щоб їх вносити вам потрібно [зареєструватись в OpenStreetMap](https://www.openstreetmap.org/user/new).\n\n[Редактор iD](http://ideditor.com/) — є спільним проектом [сирці якого \nдоступні на GitHub](https://github.com/systemed/iD).\n", - "editing_saving": "# Редагування та збереження\n\nЦей редактор створений переважно для роботи онлайн, і ви зараз\nпрацюєте з ним на веб-сайті.\n\n### Виділення об’єктів\n\nДля виділення об’єктів на мапі, таких як дороги чи пам’ятки, треба\nклацнути по них на мапі. Виділені об’єкти будуть підсвічені, з’явиться\nпанель з подробицями про них та меню із переліком того, що можна\nзробити.\n\nДля виділення кількох об’єктів натисніть 'Shift', клацніть та потягніть\nмишею по мапі. Будуть виділені всі об’єкти, що попали у прямокутник\nвиділення, це дозволить вам виконувати дії одночасно над кількома\nоб’єктами одночасно.\n\n### Збереження правок\n\nПісля того як ви зробили зміни, виправивши дорогу, чи будинок, вони є\nлокальними доки ви не збережете їх на сервері. Не хвилюйтесь, якщо\nви припустились помилки, ви можете відмінити зміни натиснувши на\nкнопку 'Відмінити', а також повернути зміни — натиснувши 'Повернути'\n\nНатисніть 'Зберегти', щоб закінчити групу правок, наприклад, якщо ви\nзакінчили роботу над одним районом міста і бажаєте перейти до іншого.\nВи будете мати можливість переглянути те, що ви зробили, а редактор\nзапропонує вам корисні поради та видасть попередження, якщо у ваші\nправки не виглядають вірними.\n\nЯкщо все виглядає добре, ви можете додати коротке пояснення того, що\nви зробили та натиснути кнопку 'Зберегти' ще раз, щоб надіслати зміни\nдо [OpenStreetMap.org](http://www.openstreetmap.org/), де вони стануть\nдоступні для всіх інших користувачів для перегляду та вдосконалення.\n\nЯкщо ви не можете закінчити ваші правки за один раз, ви можете лишити\nвікно з редактором відкритим і повернутись (на тому самому комп’ютері та\nоглядачі) до роботи потім — редактор запропонує вам відновити вашу\nроботу.\n" + "editing_saving": "# Редагування та збереження\n\nЦей редактор створений переважно для роботи онлайн, і ви зараз\nпрацюєте з ним на веб-сайті.\n\n### Виділення об’єктів\n\nДля виділення об’єктів на мапі, таких як дороги чи пам’ятки, треба\nклацнути по них на мапі. Виділені об’єкти будуть підсвічені, з’явиться\nпанель з подробицями про них та меню із переліком того, що можна\nзробити.\n\nДля виділення кількох об’єктів натисніть 'Shift', клацніть та потягніть\nмишею по мапі. Будуть виділені всі об’єкти, що попали у прямокутник\nвиділення, це дозволить вам виконувати дії одночасно над кількома\nоб’єктами одночасно.\n\n### Збереження правок\n\nПісля того як ви зробили зміни, виправивши дорогу, чи будинок, вони є\nлокальними доки ви не збережете їх на сервері. Не хвилюйтесь, якщо\nви припустились помилки, ви можете відмінити зміни натиснувши на\nкнопку 'Відмінити', а також повернути зміни — натиснувши 'Повернути'\n\nНатисніть 'Зберегти', щоб закінчити групу правок, наприклад, якщо ви\nзакінчили роботу над одним районом міста і бажаєте перейти до іншого.\nВи будете мати можливість переглянути те, що ви зробили, а редактор\nзапропонує вам корисні поради та видасть попередження, якщо у ваші\nправки не виглядають вірними.\n\nЯкщо все виглядає добре, ви можете додати коротке пояснення того, що\nви зробили та натиснути кнопку 'Зберегти' ще раз, щоб надіслати зміни\nдо [OpenStreetMap.org](http://www.openstreetmap.org/), де вони стануть\nдоступні для всіх інших користувачів для перегляду та вдосконалення.\n\nЯкщо ви не можете закінчити ваші правки за один раз, ви можете лишити\nвікно з редактором відкритим і повернутись (на тому самому комп’ютері та\nоглядачі) до роботи потім — редактор запропонує вам відновити вашу\nроботу.\n", + "roads": "# Дороги\n\nВи можете створювати, виправляти та вилучати дороги з допомогою\nцього редактора. Дороги можуть бути будь-якого типу: автомагістралі, \nстежки, велодоріжки та багато інших — все що частіше за все має\nперетин між собою, повинне бути нанесено на мапу.\n\n### Виділення\n\nКлацніть по дорозі для того щоб її вибрати. Вона стані підсвіченою\nпо всій довжині, поряд на мапі з’явиться невеличке меню з інструментами,\nа на бічній панелі буде показано додаткову інформацію про дорогу.\n\n### Зміна\n\nДоволі часто вам будуть траплятись дороги, що не співпадають із дорогами\nна супутниковому знімку чи треками GPS. Ви можете виправити їх положення.\nАле з початку вирівняйте положення знімку по треках GPS. \n\nПотім клацніть по дорозі, яку ви маєте намір змінити. Вона стане підсвіченою\nі на ній з’являться контрольні точки, які можна рухати, підлаштовуючи положення\nта форму дороги. Якщо вам потрібно додати нову точку, для підвищення деталізації,\nдодайте її подвійним клацанням на відрізку дороги. \n\nЯкщо дорога повинна з’єднуватись з іншою дорогою, але на мапі лінії не\nз’єднані, підтягніть одну із контрольних точок однієї дорого до іншої, для\nїх з’єднання. Мати з’єднані дороги — дуже важливо для мапи, а особливо\nдля впровадження можливості прокладання маршрутів.\n\nВи також можете обрати інструмент 'Перемістити' або натиснути 'M' для \nпереміщення всієї дороги, повторне клацання зберігає нове положення\nдороги.\n\n### Вилучення\n\nЯкщо дороги накреслені зовсім невірно і це добре видно по супутникових\nзнімках, а, в ідеалі, ви точно знаєте що їх у цьому місці немає — ви можете\nїх вилучити, що призведе до їх вилучення з мапи. Проте будьте уважними,\nвилучення, як і інші виправлення, призведуть до змін на мапі, що доступна\nкожному; також зауважте, що супутникові знімки з часом застарівають, отже\nновозбудована дорога буде на них відсутня. \n\nВи можете вилучити дорогу клацнувши на неї для виділення, потім натиснувши\nна значок із смітником чи натиснувши клавішу 'Delete'.\n\n### Створення\n\nЩо робити — знайшли місце де повинна бути дорога, а її там немає? Оберіть \nінструмент 'Лінія' зверху ліворуч або натисніть клавішу '2' для того, щоб\nрозпочати креслення ліній.\n\nКлацніть на початку дороги на мапі для того, щоб розпочати креслення. Якщо\nдорога відгалужується від існуючої дороги, розпочніть з місця їх з’єднання.\n\nПотім клацайте вздовж дороги так щоб утворився правильний шлях, відповідно\nдо супутникових знімків та/чи треків GPS. Якщо дорога, яку ви креслите, перетинає\nіншу дорогу, з’єднуйте їх клацаючи в точці їх перехрещення. Для закінчення\nкреслення виконайте подвійне клацання мишею чи натисніть 'Enter' на \nклавіатурі.\n", + "gps": "# GPS\n\nGPS дані є найбільш надійним джерелом даних для OpenStreetMap.\nЦей редактор підтримує роботу з локальними треками  — файлами `.gpx`\nз вашого комп’ютера. Ви можете отримати GPS треки за допомогою\nчисленних застосунків для смартфонів так само, як і з допомогою\nспеціального GPS-обладнання. \n\nДля того, щоб дізнатись як проводити збір GPS даних прочитайте\n[Збір інформації за допомогою GPS](http://learnosm.org/en/beginner/using-gps/).\n\nДля того, щоб скористатись GPX треками, перетягніть файл GPX у\nредактор мап. Після того, як його буде розпізнано, він буде доданий\nна мапу у вигляді лінії світло-зеленого кольору. Клацніть на меню\n'Налаштування фону' ліворуч для того, щоб показати, чи приховати,\nабо масштабувати новий шар з GPX.\n\nGPX трек не буде завантажений безпосередньо до OpenStreetMap,\nкращій спосіб його використання — креслити об’єкти на мапі,\nвикористовуючи його для керівництва для додавання об’єктів.\n" }, "intro": { "navigation": { "drag": "На основній мапі показуються данні OpenStreetMap поверх фонового зображення. Ви можете рухатись мапою перетягуючи її так само, як і на будь якій іншій веб-мапі. **Потягніть мапу!**", "select": "Об’єкти мапи показані трьома різними способами: у вигляді точок, ліній та полігонів. Для того щоб їх виділити треба клацнути по них. **Клацніть на точку для її виділення.**", - "header": "В заголовку показується тип об’єкта." + "header": "В заголовку показується тип об’єкта.", + "pane": "Коли об’єкт мапи виділено, з’являється редактор його властивостей. В заголовку буде показаний тип об’єкта, а на головній панелі — атрибути об’єкта, такі як його назва та адреса. **Закрийте редактор об’єктів натиснувши на кнопку вгорі праворуч.**" + }, + "points": { + "add": "Точки використовуються для того, щоб позначати такі об’єкти як магазини, ресторани чи пам’ятники. Ними позначаються відповідні місця та додається опис того, що було позначено. **Натисніть на кнопку 'Точка' для додавання нової точки.**", + "place": "Для додавання точки треба клацнути на мапі. **Додайте точку поверх будівлі.**", + "search": "Існує багато різноманітних об’єктів, які можуть бути представлені точками. Нехай точка, яку ви додали буде Кафе. **Знайдіть 'Кафе' серед інших шаблонів**", + "choose": "**Виберіть Кафе із запропонованих варіантів.**", + "describe": "Тепер наша точка позначена, як кафе. Використовуючи редактор об’єктів ви можете додати більше інформації про об’єкт. **Додайте назву**", + "close": "Редактор об’єктів можна закрити клацнувши на кнопку вгорі праворуч. **Закрийте редактор об’єктів**" + }, + "startediting": { + "save": "Не забувайте регулярно зберігати свої зміни!", + "start": "Розпочати!" } }, "presets": { @@ -18982,3 +20156,639 @@ locale.vi = { } } }; +locale.hr = { + "presets": { + "fields": { + "address": { + "label": "Adresa", + "placeholders": { + "housename": "Kućni broj", + "number": "123", + "street": "Ulica", + "city": "Grad" + } + }, + "atm": { + "label": "Bankomat" + }, + "building": { + "label": "Građevina" + }, + "building_area": { + "label": "Građevina" + }, + "building_yes": { + "label": "Građevina" + }, + "capacity": { + "label": "Kapacitet" + }, + "country": { + "label": "Država" + }, + "cuisine": { + "label": "Hrana" + }, + "elevation": { + "label": "Visina" + }, + "fee": { + "label": "Plaćanje" + }, + "internet_access": { + "label": "Dostupan internet", + "options": { + "wlan": "Wifi" + } + }, + "layer": { + "label": "Sloj" + }, + "levels": { + "label": "Razina" + }, + "maxspeed": { + "label": "Ograničenje brzine" + }, + "natural": { + "label": "Priroda" + }, + "network": { + "label": "Mreža" + }, + "note": { + "label": "Bilješka" + }, + "oneway": { + "label": "Jednosmjerna" + }, + "opening_hours": { + "label": "Sati" + }, + "operator": { + "label": "Operator" + }, + "phone": { + "label": "Telefon" + }, + "religion": { + "label": "Religija", + "options": { + "christian": "Kršćanski", + "muslim": "Muslimanski", + "buddhist": "Budistički", + "jewish": "Židovski", + "hindu": "Hinduistički", + "shinto": "Šintoistički", + "taoist": "Taoistički" + } + }, + "shelter": { + "label": "Sklonište" + }, + "source": { + "label": "Izvor" + }, + "sport": { + "label": "Sport" + }, + "structure": { + "label": "Konstrukcija", + "options": { + "bridge": "Most", + "tunnel": "Tunel", + "embankment": "Nasip", + "cutting": "Usjek" + } + }, + "surface": { + "label": "Površina" + }, + "website": { + "label": "Web stranica" + }, + "wheelchair": { + "label": "Pristup s invalidskim kolicima" + }, + "wikipedia": { + "label": "Wikipedia" + } + }, + "presets": { + "aeroway": { + "name": "Pista" + }, + "aeroway/aerodrome": { + "name": "Zračna luka" + }, + "amenity/bank": { + "name": "Banka" + }, + "amenity/bar": { + "name": "Bar" + }, + "amenity/bench": { + "name": "Klupa" + }, + "amenity/bicycle_parking": { + "name": "Parking za bicikle" + }, + "amenity/bicycle_rental": { + "name": "Najam bicikla" + }, + "amenity/cafe": { + "name": "Kafić" + }, + "amenity/cinema": { + "name": "Kino" + }, + "amenity/courthouse": { + "name": "Zgrada suda" + }, + "amenity/embassy": { + "name": "Ambasada" + }, + "amenity/fast_food": { + "name": "Brza hrana" + }, + "amenity/fire_station": { + "name": "Vatrogasna postaja" + }, + "amenity/fuel": { + "name": "Benzinska postaja" + }, + "amenity/grave_yard": { + "name": "Groblje" + }, + "amenity/hospital": { + "name": "Bolnica" + }, + "amenity/library": { + "name": "Knjižnica" + }, + "amenity/marketplace": { + "name": "Tržnica" + }, + "amenity/parking": { + "name": "Parking" + }, + "amenity/pharmacy": { + "name": "Ljekarna" + }, + "amenity/place_of_worship": { + "name": "Vjerski objekt" + }, + "amenity/place_of_worship/christian": { + "name": "Crkva" + }, + "amenity/place_of_worship/jewish": { + "name": "Sinagoga" + }, + "amenity/place_of_worship/muslim": { + "name": "Džamija" + }, + "amenity/police": { + "name": "Policija" + }, + "amenity/post_box": { + "name": "Poštanski sandučić" + }, + "amenity/post_office": { + "name": "Pošta" + }, + "amenity/pub": { + "name": "Pivnica" + }, + "amenity/restaurant": { + "name": "Restoran" + }, + "amenity/school": { + "name": "Škola" + }, + "amenity/swimming_pool": { + "name": "Sportski bazen" + }, + "amenity/telephone": { + "name": "Telefon" + }, + "amenity/theatre": { + "name": "Kazalište" + }, + "amenity/toilets": { + "name": "Toalet" + }, + "amenity/townhall": { + "name": "Gradska vjećnica" + }, + "amenity/university": { + "name": "Sveučilište" + }, + "barrier": { + "name": "Prepreka" + }, + "barrier/block": { + "name": "Blok" + }, + "barrier/bollard": { + "name": "Stup" + }, + "barrier/city_wall": { + "name": "Gradske zidine" + }, + "barrier/cycle_barrier": { + "name": "Biciklistička prepreka" + }, + "barrier/ditch": { + "name": "Prokop" + }, + "barrier/fence": { + "name": "Ograda" + }, + "barrier/gate": { + "name": "Kapija" + }, + "barrier/hedge": { + "name": "Živica" + }, + "barrier/lift_gate": { + "name": "Rampa" + }, + "barrier/wall": { + "name": "Zid" + }, + "building": { + "name": "Zgrada" + }, + "building/apartments": { + "name": "Apartmani" + }, + "building/entrance": { + "name": "Ulaz" + }, + "building/house": { + "name": "Kuća" + }, + "entrance": { + "name": "Ulaz" + }, + "highway": { + "name": "Prometnica" + }, + "highway/bus_stop": { + "name": "Autobusna stanica" + }, + "highway/crossing": { + "name": "Križanje" + }, + "highway/cycleway": { + "name": "Biciklistička staza" + }, + "highway/footway": { + "name": "Pješačka staza" + }, + "highway/motorway": { + "name": "Autoput" + }, + "highway/path": { + "name": "Staza" + }, + "highway/primary": { + "name": "Primarna cesta" + }, + "highway/residential": { + "name": "Lokalna cesta" + }, + "highway/service": { + "name": "Servisna cesta" + }, + "highway/traffic_signals": { + "name": "Prometni znak" + }, + "highway/turning_circle": { + "name": "Kružni tok" + }, + "highway/unclassified": { + "name": "Neklasificirana cesta" + }, + "historic": { + "name": "Povijesno područje" + }, + "historic/archaeological_site": { + "name": "Arheološko područje" + }, + "historic/boundary_stone": { + "name": "Suhozid" + }, + "historic/castle": { + "name": "Dvorac" + }, + "historic/monument": { + "name": "Spomenik" + }, + "historic/ruins": { + "name": "Ruševina" + }, + "landuse": { + "name": "Korištenje" + }, + "landuse/allotments": { + "name": "Vrtovi" + }, + "landuse/cemetery": { + "name": "Groblje" + }, + "landuse/commercial": { + "name": "Poslovno" + }, + "landuse/construction": { + "name": "Građevinsko" + }, + "landuse/farm": { + "name": "Gospodarstvo" + }, + "landuse/farmyard": { + "name": "Gospodarsko imanje" + }, + "landuse/forest": { + "name": "Šuma" + }, + "landuse/grass": { + "name": "Travnjak" + }, + "landuse/industrial": { + "name": "Industrijsko" + }, + "landuse/meadow": { + "name": "Livada" + }, + "landuse/orchard": { + "name": "Voćnjak" + }, + "landuse/quarry": { + "name": "Kamenolom" + }, + "landuse/residential": { + "name": "Stambeno" + }, + "landuse/vineyard": { + "name": "Vinograd" + }, + "leisure": { + "name": "Razonoda" + }, + "leisure/garden": { + "name": "Vrt" + }, + "leisure/golf_course": { + "name": "Golf tečaj" + }, + "leisure/park": { + "name": "Park" + }, + "leisure/pitch": { + "name": "Sportski teren" + }, + "leisure/pitch/american_football": { + "name": "Američki nogomet" + }, + "leisure/pitch/baseball": { + "name": "Baseball igralište" + }, + "leisure/pitch/basketball": { + "name": "Košarkaški teren" + }, + "leisure/pitch/soccer": { + "name": "Nogometno igralište" + }, + "leisure/pitch/tennis": { + "name": "Teniski teren" + }, + "leisure/playground": { + "name": "Igralište" + }, + "leisure/stadium": { + "name": "Stadion" + }, + "leisure/swimming_pool": { + "name": "Sportski bazen" + }, + "man_made/lighthouse": { + "name": "Svjetionik" + }, + "man_made/pier": { + "name": "Mol" + }, + "man_made/water_tower": { + "name": "Vodo-toranj" + }, + "natural": { + "name": "Priroda" + }, + "natural/bay": { + "name": "Zaljev" + }, + "natural/beach": { + "name": "Plaža" + }, + "natural/cliff": { + "name": "Litica" + }, + "natural/coastline": { + "name": "Obalna linija", + "terms": "obala" + }, + "natural/glacier": { + "name": "Glečer" + }, + "natural/grassland": { + "name": "Travnjak" + }, + "natural/peak": { + "name": "Planinski vrh" + }, + "natural/scrub": { + "name": "Šikara" + }, + "natural/tree": { + "name": "Stablo" + }, + "natural/water": { + "name": "Voda" + }, + "natural/water/lake": { + "name": "Jezero" + }, + "natural/water/pond": { + "name": "Ribnjak" + }, + "natural/water/reservoir": { + "name": "Akumulacija" + }, + "natural/wetland": { + "name": "Močvara" + }, + "natural/wood": { + "name": "Šuma" + }, + "office": { + "name": "Ured" + }, + "other": { + "name": "Ostalo" + }, + "other_area": { + "name": "Ostalo" + }, + "place": { + "name": "Mjesto" + }, + "place/hamlet": { + "name": "Zaseok" + }, + "place/island": { + "name": "Otok" + }, + "place/locality": { + "name": "Lokalitet" + }, + "place/village": { + "name": "Selo" + }, + "power/sub_station": { + "name": "Podzemna postaja" + }, + "power/transformer": { + "name": "Transformator" + }, + "railway": { + "name": "Željeznička pruga" + }, + "railway/rail": { + "name": "Željeznica" + }, + "railway/station": { + "name": "Željeznička postaja" + }, + "railway/subway": { + "name": "Podzemna željeznica" + }, + "railway/subway_entrance": { + "name": "Ulaz u podzemnu željeznicu" + }, + "railway/tram": { + "name": "Tramvaj" + }, + "shop": { + "name": "Prodavaonica" + }, + "shop/bakery": { + "name": "Pekara" + }, + "shop/books": { + "name": "Knjižara" + }, + "shop/butcher": { + "name": "Mesnica" + }, + "shop/confectionery": { + "name": "Slastičarnica" + }, + "shop/doityourself": { + "name": "Uradi sam" + }, + "shop/fishmonger": { + "name": "Ribarnica" + }, + "shop/florist": { + "name": "Cvjećarna" + }, + "shop/furniture": { + "name": "Salon namještaja" + }, + "shop/garden_centre": { + "name": "Vrtni centar" + }, + "shop/hairdresser": { + "name": "Frizerski salon" + }, + "shop/kiosk": { + "name": "Kiosk" + }, + "shop/laundry": { + "name": "Praonica rublja" + }, + "shop/supermarket": { + "name": "Veletrgovina" + }, + "tourism": { + "name": "Turizam" + }, + "tourism/alpine_hut": { + "name": "Planinska kuća" + }, + "tourism/attraction": { + "name": "Turistička atrakcija" + }, + "tourism/camp_site": { + "name": "Kamp" + }, + "tourism/chalet": { + "name": "Bungalov" + }, + "tourism/hostel": { + "name": "Hostel" + }, + "tourism/hotel": { + "name": "Hotel" + }, + "tourism/information": { + "name": "Informacije" + }, + "tourism/motel": { + "name": "Motel" + }, + "tourism/museum": { + "name": "Muzej" + }, + "tourism/picnic_site": { + "name": "Izletište" + }, + "tourism/theme_park": { + "name": "Tematski park" + }, + "tourism/viewpoint": { + "name": "Vidikovac" + }, + "tourism/zoo": { + "name": "Zološki vrt" + }, + "waterway": { + "name": "Vodni put" + }, + "waterway/canal": { + "name": "Kanal" + }, + "waterway/dam": { + "name": "Brana" + }, + "waterway/ditch": { + "name": "Prokop" + }, + "waterway/drain": { + "name": "Kanal" + }, + "waterway/river": { + "name": "Rijeka" + }, + "waterway/riverbank": { + "name": "Riječni tok" + }, + "waterway/stream": { + "name": "Potok" + }, + "waterway/weir": { + "name": "Brana" + } + } + } +}; From 2c68e0efd77034c2e51ad2a6f51a947f1ae6b5f7 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 3 Apr 2013 16:18:02 -0700 Subject: [PATCH 08/14] presets.yaml shouldn't be edited either --- data/locales.js | 4 ++-- data/update_locales.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/locales.js b/data/locales.js index 2c99a455e..5195c8456 100644 --- a/data/locales.js +++ b/data/locales.js @@ -3,8 +3,8 @@ THIS FILE IS GENERATED BY `make translations`. Don't make changes to it. - Instead, edit the English strings in data/core.yaml or data/presets.yaml, or - contribute translations on https://www.transifex.com/projects/p/id-editor/. + Instead, edit the English strings in data/core.yaml, or contribute + translations on https://www.transifex.com/projects/p/id-editor/. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ diff --git a/data/update_locales.js b/data/update_locales.js index ca94c2a4c..ae4c6a1f4 100644 --- a/data/update_locales.js +++ b/data/update_locales.js @@ -32,8 +32,8 @@ asyncMap(resources, getResource, function(err, locales) { '\n' + ' THIS FILE IS GENERATED BY `make translations`. Don\'t make changes to it.\n' + '\n' + - ' Instead, edit the English strings in data/core.yaml or data/presets.yaml, or\n' + - ' contribute translations on https://www.transifex.com/projects/p/id-editor/.\n' + + ' Instead, edit the English strings in data/core.yaml, or contribute\n' + + ' translations on https://www.transifex.com/projects/p/id-editor/.\n' + '\n' + ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + ' */\n'; From ff3405ae023f9192eb6de6d22e8d1ab6a7573cdd Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 3 Apr 2013 16:29:28 -0700 Subject: [PATCH 09/14] Reapply 92ceae9 --- js/lib/d3.v3.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/js/lib/d3.v3.js b/js/lib/d3.v3.js index 4fe49a2e7..e60a029ad 100644 --- a/js/lib/d3.v3.js +++ b/js/lib/d3.v3.js @@ -1506,7 +1506,13 @@ d3.behavior.zoom = function() { function mouseup() { if (moved) d3_eventCancel(); w.on("mousemove.zoom", null).on("mouseup.zoom", null); - if (moved && d3.event.target === eventTarget) w.on("click.zoom", click, true); + if (moved && d3.event.target === eventTarget) { + w.on("click.zoom", click, true); + window.setTimeout(function() { + // Remove click block if click didn't fire + w.on("click.zoom", null); + }, 0); + } } function click() { From 7e2485dd87b7900b16db611553bc418de52e61e9 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 3 Apr 2013 16:41:32 -0700 Subject: [PATCH 10/14] Capture better stack traces --- js/lib/d3.v3.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/lib/d3.v3.js b/js/lib/d3.v3.js index e60a029ad..b8c1708f8 100644 --- a/js/lib/d3.v3.js +++ b/js/lib/d3.v3.js @@ -1227,6 +1227,7 @@ function d3_selection_on(type, listener, capture) { function onAdd() { var l = wrap(listener, d3_array(arguments)); + if (typeof Raven !== 'undefined') l = Raven.wrap(l); onRemove.call(this); this.addEventListener(type, this[name] = l, l.$ = capture); l._ = listener; From c1df01cec1e7a9cc0addc1300029fec988e8926f Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 3 Apr 2013 16:45:40 -0700 Subject: [PATCH 11/14] Fix global leak --- js/id/ui/tag_editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/id/ui/tag_editor.js b/js/id/ui/tag_editor.js index 82f01f561..129988af5 100644 --- a/js/id/ui/tag_editor.js +++ b/js/id/ui/tag_editor.js @@ -73,7 +73,7 @@ iD.ui.TagEditor = function(context, entity) { .call(tagList, preset.id === 'other'); if (!entity.isNew()) { - osmLink = tageditorpreset.append('div') + var osmLink = tageditorpreset.append('div') .attr('class', 'col12 inspector-inner') .append('a') .attr('href', 'http://www.openstreetmap.org/browse/' + entity.type + '/' + entity.osmId()) From d429b20fa99e44e74ad8859f1dd6bf8415bec8dc Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 3 Apr 2013 17:26:42 -0700 Subject: [PATCH 12/14] Disable a transition that crashes Safari (fixes #1188) --- css/app.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/css/app.css b/css/app.css index bcba11599..cbec945d5 100644 --- a/css/app.css +++ b/css/app.css @@ -333,7 +333,8 @@ button { display: inline-block; height:40px; border-radius:4px; - -webkit-transition: all 100ms; + /* Crashes Safari: https://github.com/systemed/iD/issues/1188 */ + /*-webkit-transition: all 100ms;*/ -moz-transition: all 100ms; -o-transition: all 100ms; transition: all 100ms; From d72ede2e2d5d0219d52247d66abaf3c08c8c6ae5 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 4 Apr 2013 10:36:11 -0700 Subject: [PATCH 13/14] Update to mocha 1.9, manage with npm --- package.json | 1 + test/index.html | 4 +- test/index_packaged.html | 4 +- test/lib/mocha.css | 227 -- test/lib/mocha.js | 5299 -------------------------------------- 5 files changed, 5 insertions(+), 5530 deletions(-) delete mode 100644 test/lib/mocha.css delete mode 100644 test/lib/mocha.js diff --git a/package.json b/package.json index d3cd8dcc9..dffb50136 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "d3": "3", "smash": "0.0", "uglify-js": "~2.2.5", + "mocha": "~1.9", "mocha-phantomjs": "~1.1.1", "glob": "~3.1.21", "js-yaml": "~2.0.3", diff --git a/test/index.html b/test/index.html index f732d4dd0..280b7c00a 100644 --- a/test/index.html +++ b/test/index.html @@ -3,12 +3,12 @@ Mocha Tests - +

- + diff --git a/test/index_packaged.html b/test/index_packaged.html index db71efdad..913af83fa 100644 --- a/test/index_packaged.html +++ b/test/index_packaged.html @@ -3,12 +3,12 @@ Mocha Tests - +
- + diff --git a/test/lib/mocha.css b/test/lib/mocha.css deleted file mode 100644 index 81adbd527..000000000 --- a/test/lib/mocha.css +++ /dev/null @@ -1,227 +0,0 @@ -@charset "UTF-8"; -body { - font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; - padding: 60px 50px; -} - -#mocha ul, #mocha li { - margin: 0; - padding: 0; -} - -#mocha ul { - list-style: none; -} - -#mocha h1, #mocha h2 { - margin: 0; -} - -#mocha h1 { - margin-top: 15px; - font-size: 1em; - font-weight: 200; -} - -#mocha h1 a { - text-decoration: none; - color: inherit; -} - -#mocha h1 a:hover { - text-decoration: underline; -} - -#mocha .suite .suite h1 { - margin-top: 0; - font-size: .8em; -} - -.hidden { - display: none; -} - -#mocha h2 { - font-size: 12px; - font-weight: normal; - cursor: pointer; -} - -#mocha .suite { - margin-left: 15px; -} - -#mocha .test { - margin-left: 15px; -} - -#mocha .test.pending:hover h2::after { - content: '(pending)'; - font-family: arial; -} - -#mocha .test.pass.medium .duration { - background: #C09853; -} - -#mocha .test.pass.slow .duration { - background: #B94A48; -} - -#mocha .test.pass::before { - content: '✓'; - font-size: 12px; - display: block; - float: left; - margin-right: 5px; - color: #00d6b2; -} - -#mocha .test.pass .duration { - font-size: 9px; - margin-left: 5px; - padding: 2px 5px; - color: white; - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - -ms-border-radius: 5px; - -o-border-radius: 5px; - border-radius: 5px; -} - -#mocha .test.pass.fast .duration { - display: none; -} - -#mocha .test.pending { - color: #0b97c4; -} - -#mocha .test.pending::before { - content: '◦'; - color: #0b97c4; -} - -#mocha .test.fail { - color: #c00; -} - -#mocha .test.fail pre { - color: black; -} - -#mocha .test.fail::before { - content: '✖'; - font-size: 12px; - display: block; - float: left; - margin-right: 5px; - color: #c00; -} - -#mocha .test pre.error { - color: #c00; - max-height: 300px; - overflow: auto; -} - -#mocha .test pre { - display: inline-block; - font: 12px/1.5 monaco, monospace; - margin: 5px; - padding: 15px; - border: 1px solid #eee; - border-bottom-color: #ddd; - -webkit-border-radius: 3px; - -webkit-box-shadow: 0 1px 3px #eee; - -moz-border-radius: 3px; - -moz-box-shadow: 0 1px 3px #eee; -} - -#mocha .test h2 { - position: relative; -} - -#mocha .test a.replay { - position: absolute; - top: 3px; - right: -20px; - text-decoration: none; - vertical-align: middle; - display: block; - width: 15px; - height: 15px; - line-height: 15px; - text-align: center; - background: #eee; - font-size: 15px; - -moz-border-radius: 15px; - border-radius: 15px; - -webkit-transition: opacity 200ms; - -moz-transition: opacity 200ms; - transition: opacity 200ms; - opacity: 0.2; - color: #888; -} - -#mocha .test:hover a.replay { - opacity: 1; -} - -#mocha-report.pass .test.fail { - display: none; -} - -#mocha-report.fail .test.pass { - display: none; -} - -#mocha-error { - color: #c00; - font-size: 1.5 em; - font-weight: 100; - letter-spacing: 1px; -} - -#mocha-stats { - position: fixed; - top: 15px; - right: 10px; - font-size: 12px; - margin: 0; - color: #888; -} - -#mocha-stats .progress { - float: right; - padding-top: 0; -} - -#mocha-stats em { - color: black; -} - -#mocha-stats a { - text-decoration: none; - color: inherit; -} - -#mocha-stats a:hover { - border-bottom: 1px solid #eee; -} - -#mocha-stats li { - display: inline-block; - margin: 0 5px; - list-style: none; - padding-top: 11px; -} - -code .comment { color: #ddd } -code .init { color: #2F6FAD } -code .string { color: #5890AD } -code .keyword { color: #8A6343 } -code .number { color: #2F6FAD } diff --git a/test/lib/mocha.js b/test/lib/mocha.js deleted file mode 100644 index ed4095007..000000000 --- a/test/lib/mocha.js +++ /dev/null @@ -1,5299 +0,0 @@ -;(function(){ - - -// CommonJS require() - -function require(p){ - var path = require.resolve(p) - , mod = require.modules[path]; - if (!mod) throw new Error('failed to require "' + p + '"'); - if (!mod.exports) { - mod.exports = {}; - mod.call(mod.exports, mod, mod.exports, require.relative(path)); - } - return mod.exports; - } - -require.modules = {}; - -require.resolve = function (path){ - var orig = path - , reg = path + '.js' - , index = path + '/index.js'; - return require.modules[reg] && reg - || require.modules[index] && index - || orig; - }; - -require.register = function (path, fn){ - require.modules[path] = fn; - }; - -require.relative = function (parent) { - return function(p){ - if ('.' != p.charAt(0)) return require(p); - - var path = parent.split('/') - , segs = p.split('/'); - path.pop(); - - for (var i = 0; i < segs.length; i++) { - var seg = segs[i]; - if ('..' == seg) path.pop(); - else if ('.' != seg) path.push(seg); - } - - return require(path.join('/')); - }; - }; - - -require.register("browser/debug.js", function(module, exports, require){ - -module.exports = function(type){ - return function(){ - - } -}; -}); // module: browser/debug.js - -require.register("browser/diff.js", function(module, exports, require){ -/* See license.txt for terms of usage */ - -/* - * Text diff implementation. - * - * This library supports the following APIS: - * JsDiff.diffChars: Character by character diff - * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace - * JsDiff.diffLines: Line based diff - * - * JsDiff.diffCss: Diff targeted at CSS content - * - * These methods are based on the implementation proposed in - * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). - * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 - */ -var JsDiff = (function() { - function clonePath(path) { - return { newPos: path.newPos, components: path.components.slice(0) }; - } - function removeEmpty(array) { - var ret = []; - for (var i = 0; i < array.length; i++) { - if (array[i]) { - ret.push(array[i]); - } - } - return ret; - } - function escapeHTML(s) { - var n = s; - n = n.replace(/&/g, "&"); - n = n.replace(//g, ">"); - n = n.replace(/"/g, """); - - return n; - } - - - var fbDiff = function(ignoreWhitespace) { - this.ignoreWhitespace = ignoreWhitespace; - }; - fbDiff.prototype = { - diff: function(oldString, newString) { - // Handle the identity case (this is due to unrolling editLength == 0 - if (newString == oldString) { - return [{ value: newString }]; - } - if (!newString) { - return [{ value: oldString, removed: true }]; - } - if (!oldString) { - return [{ value: newString, added: true }]; - } - - newString = this.tokenize(newString); - oldString = this.tokenize(oldString); - - var newLen = newString.length, oldLen = oldString.length; - var maxEditLength = newLen + oldLen; - var bestPath = [{ newPos: -1, components: [] }]; - - // Seed editLength = 0 - var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); - if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) { - return bestPath[0].components; - } - - for (var editLength = 1; editLength <= maxEditLength; editLength++) { - for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) { - var basePath; - var addPath = bestPath[diagonalPath-1], - removePath = bestPath[diagonalPath+1]; - oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; - if (addPath) { - // No one else is going to attempt to use this value, clear it - bestPath[diagonalPath-1] = undefined; - } - - var canAdd = addPath && addPath.newPos+1 < newLen; - var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; - if (!canAdd && !canRemove) { - bestPath[diagonalPath] = undefined; - continue; - } - - // Select the diagonal that we want to branch from. We select the prior - // path whose position in the new string is the farthest from the origin - // and does not pass the bounds of the diff graph - if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { - basePath = clonePath(removePath); - this.pushComponent(basePath.components, oldString[oldPos], undefined, true); - } else { - basePath = clonePath(addPath); - basePath.newPos++; - this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined); - } - - var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath); - - if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) { - return basePath.components; - } else { - bestPath[diagonalPath] = basePath; - } - } - } - }, - - pushComponent: function(components, value, added, removed) { - var last = components[components.length-1]; - if (last && last.added === added && last.removed === removed) { - // We need to clone here as the component clone operation is just - // as shallow array clone - components[components.length-1] = - {value: this.join(last.value, value), added: added, removed: removed }; - } else { - components.push({value: value, added: added, removed: removed }); - } - }, - extractCommon: function(basePath, newString, oldString, diagonalPath) { - var newLen = newString.length, - oldLen = oldString.length, - newPos = basePath.newPos, - oldPos = newPos - diagonalPath; - while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) { - newPos++; - oldPos++; - - this.pushComponent(basePath.components, newString[newPos], undefined, undefined); - } - basePath.newPos = newPos; - return oldPos; - }, - - equals: function(left, right) { - var reWhitespace = /\S/; - if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) { - return true; - } else { - return left == right; - } - }, - join: function(left, right) { - return left + right; - }, - tokenize: function(value) { - return value; - } - }; - - var CharDiff = new fbDiff(); - - var WordDiff = new fbDiff(true); - WordDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\s+|\b)/)); - }; - - var CssDiff = new fbDiff(true); - CssDiff.tokenize = function(value) { - return removeEmpty(value.split(/([{}:;,]|\s+)/)); - }; - - var LineDiff = new fbDiff(); - LineDiff.tokenize = function(value) { - return value.split(/^/m); - }; - - return { - diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); }, - diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); }, - diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); }, - - diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, - - createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { - var ret = []; - - ret.push("Index: " + fileName); - ret.push("==================================================================="); - ret.push("--- " + fileName + (typeof oldHeader === "undefined" ? "" : "\t" + oldHeader)); - ret.push("+++ " + fileName + (typeof newHeader === "undefined" ? "" : "\t" + newHeader)); - - var diff = LineDiff.diff(oldStr, newStr); - if (!diff[diff.length-1].value) { - diff.pop(); // Remove trailing newline add - } - diff.push({value: "", lines: []}); // Append an empty value to make cleanup easier - - function contextLines(lines) { - return lines.map(function(entry) { return ' ' + entry; }); - } - function eofNL(curRange, i, current) { - var last = diff[diff.length-2], - isLast = i === diff.length-2, - isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed); - - // Figure out if this is the last line for the given file and missing NL - if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { - curRange.push('\\ No newline at end of file'); - } - } - - var oldRangeStart = 0, newRangeStart = 0, curRange = [], - oldLine = 1, newLine = 1; - for (var i = 0; i < diff.length; i++) { - var current = diff[i], - lines = current.lines || current.value.replace(/\n$/, "").split("\n"); - current.lines = lines; - - if (current.added || current.removed) { - if (!oldRangeStart) { - var prev = diff[i-1]; - oldRangeStart = oldLine; - newRangeStart = newLine; - - if (prev) { - curRange = contextLines(prev.lines.slice(-4)); - oldRangeStart -= curRange.length; - newRangeStart -= curRange.length; - } - } - curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?"+":"-") + entry; })); - eofNL(curRange, i, current); - - if (current.added) { - newLine += lines.length; - } else { - oldLine += lines.length; - } - } else { - if (oldRangeStart) { - // Close out any changes that have been output (or join overlapping) - if (lines.length <= 8 && i < diff.length-2) { - // Overlapping - curRange.push.apply(curRange, contextLines(lines)); - } else { - // end the range and output - var contextSize = Math.min(lines.length, 4); - ret.push( - "@@ -" + oldRangeStart + "," + (oldLine-oldRangeStart+contextSize) - + " +" + newRangeStart + "," + (newLine-newRangeStart+contextSize) - + " @@"); - ret.push.apply(ret, curRange); - ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); - if (lines.length <= 4) { - eofNL(ret, i, current); - } - - oldRangeStart = 0; newRangeStart = 0; curRange = []; - } - } - oldLine += lines.length; - newLine += lines.length; - } - } - - return ret.join('\n') + '\n'; - }, - - convertChangesToXML: function(changes){ - var ret = []; - for ( var i = 0; i < changes.length; i++) { - var change = changes[i]; - if (change.added) { - ret.push(""); - } else if (change.removed) { - ret.push(""); - } - - ret.push(escapeHTML(change.value)); - - if (change.added) { - ret.push(""); - } else if (change.removed) { - ret.push(""); - } - } - return ret.join(""); - } - }; -})(); - -if (typeof module !== "undefined") { - module.exports = JsDiff; -} - -}); // module: browser/diff.js - -require.register("browser/events.js", function(module, exports, require){ - -/** - * Module exports. - */ - -exports.EventEmitter = EventEmitter; - -/** - * Check if `obj` is an array. - */ - -function isArray(obj) { - return '[object Array]' == {}.toString.call(obj); -} - -/** - * Event emitter constructor. - * - * @api public - */ - -function EventEmitter(){}; - -/** - * Adds a listener. - * - * @api public - */ - -EventEmitter.prototype.on = function (name, fn) { - if (!this.$events) { - this.$events = {}; - } - - if (!this.$events[name]) { - this.$events[name] = fn; - } else if (isArray(this.$events[name])) { - this.$events[name].push(fn); - } else { - this.$events[name] = [this.$events[name], fn]; - } - - return this; -}; - -EventEmitter.prototype.addListener = EventEmitter.prototype.on; - -/** - * Adds a volatile listener. - * - * @api public - */ - -EventEmitter.prototype.once = function (name, fn) { - var self = this; - - function on () { - self.removeListener(name, on); - fn.apply(this, arguments); - }; - - on.listener = fn; - this.on(name, on); - - return this; -}; - -/** - * Removes a listener. - * - * @api public - */ - -EventEmitter.prototype.removeListener = function (name, fn) { - if (this.$events && this.$events[name]) { - var list = this.$events[name]; - - if (isArray(list)) { - var pos = -1; - - for (var i = 0, l = list.length; i < l; i++) { - if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { - pos = i; - break; - } - } - - if (pos < 0) { - return this; - } - - list.splice(pos, 1); - - if (!list.length) { - delete this.$events[name]; - } - } else if (list === fn || (list.listener && list.listener === fn)) { - delete this.$events[name]; - } - } - - return this; -}; - -/** - * Removes all listeners for an event. - * - * @api public - */ - -EventEmitter.prototype.removeAllListeners = function (name) { - if (name === undefined) { - this.$events = {}; - return this; - } - - if (this.$events && this.$events[name]) { - this.$events[name] = null; - } - - return this; -}; - -/** - * Gets all listeners for a certain event. - * - * @api public - */ - -EventEmitter.prototype.listeners = function (name) { - if (!this.$events) { - this.$events = {}; - } - - if (!this.$events[name]) { - this.$events[name] = []; - } - - if (!isArray(this.$events[name])) { - this.$events[name] = [this.$events[name]]; - } - - return this.$events[name]; -}; - -/** - * Emits an event. - * - * @api public - */ - -EventEmitter.prototype.emit = function (name) { - if (!this.$events) { - return false; - } - - var handler = this.$events[name]; - - if (!handler) { - return false; - } - - var args = [].slice.call(arguments, 1); - - if ('function' == typeof handler) { - handler.apply(this, args); - } else if (isArray(handler)) { - var listeners = handler.slice(); - - for (var i = 0, l = listeners.length; i < l; i++) { - listeners[i].apply(this, args); - } - } else { - return false; - } - - return true; -}; -}); // module: browser/events.js - -require.register("browser/fs.js", function(module, exports, require){ - -}); // module: browser/fs.js - -require.register("browser/path.js", function(module, exports, require){ - -}); // module: browser/path.js - -require.register("browser/progress.js", function(module, exports, require){ - -/** - * Expose `Progress`. - */ - -module.exports = Progress; - -/** - * Initialize a new `Progress` indicator. - */ - -function Progress() { - this.percent = 0; - this.size(0); - this.fontSize(11); - this.font('helvetica, arial, sans-serif'); -} - -/** - * Set progress size to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.size = function(n){ - this._size = n; - return this; -}; - -/** - * Set text to `str`. - * - * @param {String} str - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.text = function(str){ - this._text = str; - return this; -}; - -/** - * Set font size to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.fontSize = function(n){ - this._fontSize = n; - return this; -}; - -/** - * Set font `family`. - * - * @param {String} family - * @return {Progress} for chaining - */ - -Progress.prototype.font = function(family){ - this._font = family; - return this; -}; - -/** - * Update percentage to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - */ - -Progress.prototype.update = function(n){ - this.percent = n; - return this; -}; - -/** - * Draw on `ctx`. - * - * @param {CanvasRenderingContext2d} ctx - * @return {Progress} for chaining - */ - -Progress.prototype.draw = function(ctx){ - var percent = Math.min(this.percent, 100) - , size = this._size - , half = size / 2 - , x = half - , y = half - , rad = half - 1 - , fontSize = this._fontSize; - - ctx.font = fontSize + 'px ' + this._font; - - var angle = Math.PI * 2 * (percent / 100); - ctx.clearRect(0, 0, size, size); - - // outer circle - ctx.strokeStyle = '#9f9f9f'; - ctx.beginPath(); - ctx.arc(x, y, rad, 0, angle, false); - ctx.stroke(); - - // inner circle - ctx.strokeStyle = '#eee'; - ctx.beginPath(); - ctx.arc(x, y, rad - 1, 0, angle, true); - ctx.stroke(); - - // text - var text = this._text || (percent | 0) + '%' - , w = ctx.measureText(text).width; - - ctx.fillText( - text - , x - w / 2 + 1 - , y + fontSize / 2 - 1); - - return this; -}; - -}); // module: browser/progress.js - -require.register("browser/tty.js", function(module, exports, require){ - -exports.isatty = function(){ - return true; -}; - -exports.getWindowSize = function(){ - return [window.innerHeight, window.innerWidth]; -}; -}); // module: browser/tty.js - -require.register("context.js", function(module, exports, require){ - -/** - * Expose `Context`. - */ - -module.exports = Context; - -/** - * Initialize a new `Context`. - * - * @api private - */ - -function Context(){} - -/** - * Set or get the context `Runnable` to `runnable`. - * - * @param {Runnable} runnable - * @return {Context} - * @api private - */ - -Context.prototype.runnable = function(runnable){ - if (0 == arguments.length) return this._runnable; - this.test = this._runnable = runnable; - return this; -}; - -/** - * Set test timeout `ms`. - * - * @param {Number} ms - * @return {Context} self - * @api private - */ - -Context.prototype.timeout = function(ms){ - this.runnable().timeout(ms); - return this; -}; - -/** - * Set test slowness threshold `ms`. - * - * @param {Number} ms - * @return {Context} self - * @api private - */ - -Context.prototype.slow = function(ms){ - this.runnable().slow(ms); - return this; -}; - -/** - * Inspect the context void of `._runnable`. - * - * @return {String} - * @api private - */ - -Context.prototype.inspect = function(){ - return JSON.stringify(this, function(key, val){ - if ('_runnable' == key) return; - if ('test' == key) return; - return val; - }, 2); -}; - -}); // module: context.js - -require.register("hook.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); - -/** - * Expose `Hook`. - */ - -module.exports = Hook; - -/** - * Initialize a new `Hook` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Hook(title, fn) { - Runnable.call(this, title, fn); - this.type = 'hook'; -} - -/** - * Inherit from `Runnable.prototype`. - */ - -Hook.prototype = new Runnable; -Hook.prototype.constructor = Hook; - - -/** - * Get or set the test `err`. - * - * @param {Error} err - * @return {Error} - * @api public - */ - -Hook.prototype.error = function(err){ - if (0 == arguments.length) { - var err = this._error; - this._error = null; - return err; - } - - this._error = err; -}; - - -}); // module: hook.js - -require.register("interfaces/bdd.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test'); - -/** - * BDD-style interface: - * - * describe('Array', function(){ - * describe('#indexOf()', function(){ - * it('should return -1 when not present', function(){ - * - * }); - * - * it('should return the index when present', function(){ - * - * }); - * }); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha){ - - /** - * Execute before running tests. - */ - - context.before = function(fn){ - suites[0].beforeAll(fn); - }; - - /** - * Execute after running tests. - */ - - context.after = function(fn){ - suites[0].afterAll(fn); - }; - - /** - * Execute before each test case. - */ - - context.beforeEach = function(fn){ - suites[0].beforeEach(fn); - }; - - /** - * Execute after each test case. - */ - - context.afterEach = function(fn){ - suites[0].afterEach(fn); - }; - - /** - * Describe a "suite" with the given `title` - * and callback `fn` containing nested suites - * and/or tests. - */ - - context.describe = context.context = function(title, fn){ - var suite = Suite.create(suites[0], title); - suites.unshift(suite); - fn.call(suite); - suites.shift(); - return suite; - }; - - /** - * Pending describe. - */ - - context.xdescribe = - context.xcontext = - context.describe.skip = function(title, fn){ - var suite = Suite.create(suites[0], title); - suite.pending = true; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - }; - - /** - * Exclusive suite. - */ - - context.describe.only = function(title, fn){ - var suite = context.describe(title, fn); - mocha.grep(suite.fullTitle()); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.it = context.specify = function(title, fn){ - var suite = suites[0]; - if (suite.pending) var fn = null; - var test = new Test(title, fn); - suite.addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.it.only = function(title, fn){ - var test = context.it(title, fn); - mocha.grep(test.fullTitle()); - }; - - /** - * Pending test case. - */ - - context.xit = - context.xspecify = - context.it.skip = function(title){ - context.it(title); - }; - }); -}; - -}); // module: interfaces/bdd.js - -require.register("interfaces/exports.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test'); - -/** - * TDD-style interface: - * - * exports.Array = { - * '#indexOf()': { - * 'should return -1 when the value is not present': function(){ - * - * }, - * - * 'should return the correct index when the value is present': function(){ - * - * } - * } - * }; - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('require', visit); - - function visit(obj) { - var suite; - for (var key in obj) { - if ('function' == typeof obj[key]) { - var fn = obj[key]; - switch (key) { - case 'before': - suites[0].beforeAll(fn); - break; - case 'after': - suites[0].afterAll(fn); - break; - case 'beforeEach': - suites[0].beforeEach(fn); - break; - case 'afterEach': - suites[0].afterEach(fn); - break; - default: - suites[0].addTest(new Test(key, fn)); - } - } else { - var suite = Suite.create(suites[0], key); - suites.unshift(suite); - visit(obj[key]); - suites.shift(); - } - } - } -}; -}); // module: interfaces/exports.js - -require.register("interfaces/index.js", function(module, exports, require){ - -exports.bdd = require('./bdd'); -exports.tdd = require('./tdd'); -exports.qunit = require('./qunit'); -exports.exports = require('./exports'); - -}); // module: interfaces/index.js - -require.register("interfaces/qunit.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test'); - -/** - * QUnit-style interface: - * - * suite('Array'); - * - * test('#length', function(){ - * var arr = [1,2,3]; - * ok(arr.length == 3); - * }); - * - * test('#indexOf()', function(){ - * var arr = [1,2,3]; - * ok(arr.indexOf(1) == 0); - * ok(arr.indexOf(2) == 1); - * ok(arr.indexOf(3) == 2); - * }); - * - * suite('String'); - * - * test('#length', function(){ - * ok('foo'.length == 3); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context){ - - /** - * Execute before running tests. - */ - - context.before = function(fn){ - suites[0].beforeAll(fn); - }; - - /** - * Execute after running tests. - */ - - context.after = function(fn){ - suites[0].afterAll(fn); - }; - - /** - * Execute before each test case. - */ - - context.beforeEach = function(fn){ - suites[0].beforeEach(fn); - }; - - /** - * Execute after each test case. - */ - - context.afterEach = function(fn){ - suites[0].afterEach(fn); - }; - - /** - * Describe a "suite" with the given `title`. - */ - - context.suite = function(title){ - if (suites.length > 1) suites.shift(); - var suite = Suite.create(suites[0], title); - suites.unshift(suite); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.test = function(title, fn){ - suites[0].addTest(new Test(title, fn)); - }; - }); -}; - -}); // module: interfaces/qunit.js - -require.register("interfaces/tdd.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test'); - -/** - * TDD-style interface: - * - * suite('Array', function(){ - * suite('#indexOf()', function(){ - * suiteSetup(function(){ - * - * }); - * - * test('should return -1 when not present', function(){ - * - * }); - * - * test('should return the index when present', function(){ - * - * }); - * - * suiteTeardown(function(){ - * - * }); - * }); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha){ - - /** - * Execute before each test case. - */ - - context.setup = function(fn){ - suites[0].beforeEach(fn); - }; - - /** - * Execute after each test case. - */ - - context.teardown = function(fn){ - suites[0].afterEach(fn); - }; - - /** - * Execute before the suite. - */ - - context.suiteSetup = function(fn){ - suites[0].beforeAll(fn); - }; - - /** - * Execute after the suite. - */ - - context.suiteTeardown = function(fn){ - suites[0].afterAll(fn); - }; - - /** - * Describe a "suite" with the given `title` - * and callback `fn` containing nested suites - * and/or tests. - */ - - context.suite = function(title, fn){ - var suite = Suite.create(suites[0], title); - suites.unshift(suite); - fn.call(suite); - suites.shift(); - return suite; - }; - - /** - * Exclusive test-case. - */ - - context.suite.only = function(title, fn){ - var suite = context.suite(title, fn); - mocha.grep(suite.fullTitle()); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.test = function(title, fn){ - var test = new Test(title, fn); - suites[0].addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.test.only = function(title, fn){ - var test = context.test(title, fn); - mocha.grep(test.fullTitle()); - }; - - /** - * Pending test case. - */ - - context.test.skip = function(title){ - context.test(title); - }; - }); -}; - -}); // module: interfaces/tdd.js - -require.register("mocha.js", function(module, exports, require){ -/*! - * mocha - * Copyright(c) 2011 TJ Holowaychuk - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var path = require('browser/path') - , utils = require('./utils'); - -/** - * Expose `Mocha`. - */ - -exports = module.exports = Mocha; - -/** - * Expose internals. - */ - -exports.utils = utils; -exports.interfaces = require('./interfaces'); -exports.reporters = require('./reporters'); -exports.Runnable = require('./runnable'); -exports.Context = require('./context'); -exports.Runner = require('./runner'); -exports.Suite = require('./suite'); -exports.Hook = require('./hook'); -exports.Test = require('./test'); - -/** - * Return image `name` path. - * - * @param {String} name - * @return {String} - * @api private - */ - -function image(name) { - return __dirname + '/../images/' + name + '.png'; -} - -/** - * Setup mocha with `options`. - * - * Options: - * - * - `ui` name "bdd", "tdd", "exports" etc - * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` - * - `globals` array of accepted globals - * - `timeout` timeout in milliseconds - * - `slow` milliseconds to wait before considering a test slow - * - `ignoreLeaks` ignore global leaks - * - `grep` string or regexp to filter tests with - * - * @param {Object} options - * @api public - */ - -function Mocha(options) { - options = options || {}; - this.files = []; - this.options = options; - this.grep(options.grep); - this.suite = new exports.Suite('', new exports.Context); - this.ui(options.ui); - this.reporter(options.reporter); - if (options.timeout) this.timeout(options.timeout); - if (options.slow) this.slow(options.slow); -} - -/** - * Add test `file`. - * - * @param {String} file - * @api public - */ - -Mocha.prototype.addFile = function(file){ - this.files.push(file); - return this; -}; - -/** - * Set reporter to `reporter`, defaults to "dot". - * - * @param {String|Function} reporter name of a reporter or a reporter constructor - * @api public - */ - -Mocha.prototype.reporter = function(reporter){ - if ('function' == typeof reporter) { - this._reporter = reporter; - } else { - reporter = reporter || 'dot'; - try { - this._reporter = require('./reporters/' + reporter); - } catch (err) { - this._reporter = require(reporter); - } - if (!this._reporter) throw new Error('invalid reporter "' + reporter + '"'); - } - return this; -}; - -/** - * Set test UI `name`, defaults to "bdd". - * - * @param {String} bdd - * @api public - */ - -Mocha.prototype.ui = function(name){ - name = name || 'bdd'; - this._ui = exports.interfaces[name]; - if (!this._ui) throw new Error('invalid interface "' + name + '"'); - this._ui = this._ui(this.suite); - return this; -}; - -/** - * Load registered files. - * - * @api private - */ - -Mocha.prototype.loadFiles = function(fn){ - var self = this; - var suite = this.suite; - var pending = this.files.length; - this.files.forEach(function(file){ - file = path.resolve(file); - suite.emit('pre-require', global, file, self); - suite.emit('require', require(file), file, self); - suite.emit('post-require', global, file, self); - --pending || (fn && fn()); - }); -}; - -/** - * Enable growl support. - * - * @api private - */ - -Mocha.prototype._growl = function(runner, reporter) { - var notify = require('growl'); - - runner.on('end', function(){ - var stats = reporter.stats; - if (stats.failures) { - var msg = stats.failures + ' of ' + runner.total + ' tests failed'; - notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); - } else { - notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { - name: 'mocha' - , title: 'Passed' - , image: image('ok') - }); - } - }); -}; - -/** - * Add regexp to grep, if `re` is a string it is escaped. - * - * @param {RegExp|String} re - * @return {Mocha} - * @api public - */ - -Mocha.prototype.grep = function(re){ - this.options.grep = 'string' == typeof re - ? new RegExp(utils.escapeRegexp(re)) - : re; - return this; -}; - -/** - * Invert `.grep()` matches. - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.invert = function(){ - this.options.invert = true; - return this; -}; - -/** - * Ignore global leaks. - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.ignoreLeaks = function(){ - this.options.ignoreLeaks = true; - return this; -}; - -/** - * Enable global leak checking. - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.checkLeaks = function(){ - this.options.ignoreLeaks = false; - return this; -}; - -/** - * Enable growl support. - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.growl = function(){ - this.options.growl = true; - return this; -}; - -/** - * Ignore `globals` array or string. - * - * @param {Array|String} globals - * @return {Mocha} - * @api public - */ - -Mocha.prototype.globals = function(globals){ - this.options.globals = (this.options.globals || []).concat(globals); - return this; -}; - -/** - * Set the timeout in milliseconds. - * - * @param {Number} timeout - * @return {Mocha} - * @api public - */ - -Mocha.prototype.timeout = function(timeout){ - this.suite.timeout(timeout); - return this; -}; - -/** - * Set slowness threshold in milliseconds. - * - * @param {Number} slow - * @return {Mocha} - * @api public - */ - -Mocha.prototype.slow = function(slow){ - this.suite.slow(slow); - return this; -}; - -/** - * Makes all tests async (accepting a callback) - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.asyncOnly = function(){ - this.options.asyncOnly = true; - return this; -}; - -/** - * Run tests and invoke `fn()` when complete. - * - * @param {Function} fn - * @return {Runner} - * @api public - */ - -Mocha.prototype.run = function(fn){ - if (this.files.length) this.loadFiles(); - var suite = this.suite; - var options = this.options; - var runner = new exports.Runner(suite); - var reporter = new this._reporter(runner); - runner.ignoreLeaks = options.ignoreLeaks; - runner.asyncOnly = options.asyncOnly; - if (options.grep) runner.grep(options.grep, options.invert); - if (options.globals) runner.globals(options.globals); - if (options.growl) this._growl(runner, reporter); - return runner.run(fn); -}; - -}); // module: mocha.js - -require.register("ms.js", function(module, exports, require){ - -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; - -/** - * Parse or format the given `val`. - * - * @param {String|Number} val - * @return {String|Number} - * @api public - */ - -module.exports = function(val){ - if ('string' == typeof val) return parse(val); - return format(val); -} - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse(str) { - var m = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); - if (!m) return; - var n = parseFloat(m[1]); - var type = (m[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'y': - return n * 31557600000; - case 'days': - case 'day': - case 'd': - return n * 86400000; - case 'hours': - case 'hour': - case 'h': - return n * 3600000; - case 'minutes': - case 'minute': - case 'm': - return n * 60000; - case 'seconds': - case 'second': - case 's': - return n * 1000; - case 'ms': - return n; - } -} - -/** - * Format the given `ms`. - * - * @param {Number} ms - * @return {String} - * @api public - */ - -function format(ms) { - if (ms == d) return Math.round(ms / d) + ' day'; - if (ms > d) return Math.round(ms / d) + ' days'; - if (ms == h) return Math.round(ms / h) + ' hour'; - if (ms > h) return Math.round(ms / h) + ' hours'; - if (ms == m) return Math.round(ms / m) + ' minute'; - if (ms > m) return Math.round(ms / m) + ' minutes'; - if (ms == s) return Math.round(ms / s) + ' second'; - if (ms > s) return Math.round(ms / s) + ' seconds'; - return ms + ' ms'; -} -}); // module: ms.js - -require.register("reporters/base.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var tty = require('browser/tty') - , diff = require('browser/diff') - , ms = require('../ms'); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Check if both stdio streams are associated with a tty. - */ - -var isatty = tty.isatty(1) && tty.isatty(2); - -/** - * Expose `Base`. - */ - -exports = module.exports = Base; - -/** - * Enable coloring by default. - */ - -exports.useColors = isatty; - -/** - * Default color map. - */ - -exports.colors = { - 'pass': 90 - , 'fail': 31 - , 'bright pass': 92 - , 'bright fail': 91 - , 'bright yellow': 93 - , 'pending': 36 - , 'suite': 0 - , 'error title': 0 - , 'error message': 31 - , 'error stack': 90 - , 'checkmark': 32 - , 'fast': 90 - , 'medium': 33 - , 'slow': 31 - , 'green': 32 - , 'light': 90 - , 'diff gutter': 90 - , 'diff added': 42 - , 'diff removed': 41 -}; - -/** - * Default symbol map. - */ - -exports.symbols = { - ok: '✓', - err: '✖', - dot: '․' -}; - -// With node.js on Windows: use symbols available in terminal default fonts -if ('win32' == process.platform) { - exports.symbols.ok = '\u221A'; - exports.symbols.err = '\u00D7'; - exports.symbols.dot = '.'; -} - -/** - * Color `str` with the given `type`, - * allowing colors to be disabled, - * as well as user-defined color - * schemes. - * - * @param {String} type - * @param {String} str - * @return {String} - * @api private - */ - -var color = exports.color = function(type, str) { - if (!exports.useColors) return str; - return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; -}; - -/** - * Expose term window size, with some - * defaults for when stderr is not a tty. - */ - -exports.window = { - width: isatty - ? process.stdout.getWindowSize - ? process.stdout.getWindowSize(1)[0] - : tty.getWindowSize()[1] - : 75 -}; - -/** - * Expose some basic cursor interactions - * that are common among reporters. - */ - -exports.cursor = { - hide: function(){ - process.stdout.write('\u001b[?25l'); - }, - - show: function(){ - process.stdout.write('\u001b[?25h'); - }, - - deleteLine: function(){ - process.stdout.write('\u001b[2K'); - }, - - beginningOfLine: function(){ - process.stdout.write('\u001b[0G'); - }, - - CR: function(){ - exports.cursor.deleteLine(); - exports.cursor.beginningOfLine(); - } -}; - -/** - * Outut the given `failures` as a list. - * - * @param {Array} failures - * @api public - */ - -exports.list = function(failures){ - console.error(); - failures.forEach(function(test, i){ - // format - var fmt = color('error title', ' %s) %s:\n') - + color('error message', ' %s') - + color('error stack', '\n%s\n'); - - // msg - var err = test.err - , message = err.message || '' - , stack = err.stack || message - , index = stack.indexOf(message) + message.length - , msg = stack.slice(0, index) - , actual = err.actual - , expected = err.expected - , escape = true; - - // explicitly show diff - if (err.showDiff) { - escape = false; - err.actual = actual = JSON.stringify(actual, null, 2); - err.expected = expected = JSON.stringify(expected, null, 2); - } - - // actual / expected diff - if ('string' == typeof actual && 'string' == typeof expected) { - var len = Math.max(actual.length, expected.length); - - if (len < 20) msg = errorDiff(err, 'Chars', escape); - else msg = errorDiff(err, 'Words', escape); - - // linenos - var lines = msg.split('\n'); - if (lines.length > 4) { - var width = String(lines.length).length; - msg = lines.map(function(str, i){ - return pad(++i, width) + ' |' + ' ' + str; - }).join('\n'); - } - - // legend - msg = '\n' - + color('diff removed', 'actual') - + ' ' - + color('diff added', 'expected') - + '\n\n' - + msg - + '\n'; - - // indent - msg = msg.replace(/^/gm, ' '); - - fmt = color('error title', ' %s) %s:\n%s') - + color('error stack', '\n%s\n'); - } - - // indent stack trace without msg - stack = stack.slice(index ? index + 1 : index) - .replace(/^/gm, ' '); - - console.error(fmt, (i + 1), test.fullTitle(), msg, stack); - }); -}; - -/** - * Initialize a new `Base` reporter. - * - * All other reporters generally - * inherit from this reporter, providing - * stats such as test duration, number - * of tests passed / failed etc. - * - * @param {Runner} runner - * @api public - */ - -function Base(runner) { - var self = this - , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } - , failures = this.failures = []; - - if (!runner) return; - this.runner = runner; - - runner.stats = stats; - - runner.on('start', function(){ - stats.start = new Date; - }); - - runner.on('suite', function(suite){ - stats.suites = stats.suites || 0; - suite.root || stats.suites++; - }); - - runner.on('test end', function(test){ - stats.tests = stats.tests || 0; - stats.tests++; - }); - - runner.on('pass', function(test){ - stats.passes = stats.passes || 0; - - var medium = test.slow() / 2; - test.speed = test.duration > test.slow() - ? 'slow' - : test.duration > medium - ? 'medium' - : 'fast'; - - stats.passes++; - }); - - runner.on('fail', function(test, err){ - stats.failures = stats.failures || 0; - stats.failures++; - test.err = err; - failures.push(test); - }); - - runner.on('end', function(){ - stats.end = new Date; - stats.duration = new Date - stats.start; - }); - - runner.on('pending', function(){ - stats.pending++; - }); -} - -/** - * Output common epilogue used by many of - * the bundled reporters. - * - * @api public - */ - -Base.prototype.epilogue = function(){ - var stats = this.stats - , fmt - , tests; - - console.log(); - - function pluralize(n) { - return 1 == n ? 'test' : 'tests'; - } - - // failure - if (stats.failures) { - fmt = color('bright fail', ' ' + exports.symbols.err) - + color('fail', ' %d of %d %s failed') - + color('light', ':') - - console.error(fmt, - stats.failures, - this.runner.total, - pluralize(this.runner.total)); - - Base.list(this.failures); - console.error(); - return; - } - - // pass - fmt = color('bright pass', ' ') - + color('green', ' %d %s complete') - + color('light', ' (%s)'); - - console.log(fmt, - stats.tests || 0, - pluralize(stats.tests), - ms(stats.duration)); - - // pending - if (stats.pending) { - fmt = color('pending', ' ') - + color('pending', ' %d %s pending'); - - console.log(fmt, stats.pending, pluralize(stats.pending)); - } - - console.log(); -}; - -/** - * Pad the given `str` to `len`. - * - * @param {String} str - * @param {String} len - * @return {String} - * @api private - */ - -function pad(str, len) { - str = String(str); - return Array(len - str.length + 1).join(' ') + str; -} - -/** - * Return a character diff for `err`. - * - * @param {Error} err - * @return {String} - * @api private - */ - -function errorDiff(err, type, escape) { - return diff['diff' + type](err.actual, err.expected).map(function(str){ - if (escape) { - str.value = str.value - .replace(/\t/g, '') - .replace(/\r/g, '') - .replace(/\n/g, '\n'); - } - if (str.added) return colorLines('diff added', str.value); - if (str.removed) return colorLines('diff removed', str.value); - return str.value; - }).join(''); -} - -/** - * Color lines for `str`, using the color `name`. - * - * @param {String} name - * @param {String} str - * @return {String} - * @api private - */ - -function colorLines(name, str) { - return str.split('\n').map(function(str){ - return color(name, str); - }).join('\n'); -} - -}); // module: reporters/base.js - -require.register("reporters/doc.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils'); - -/** - * Expose `Doc`. - */ - -exports = module.exports = Doc; - -/** - * Initialize a new `Doc` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Doc(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total - , indents = 2; - - function indent() { - return Array(indents).join(' '); - } - - runner.on('suite', function(suite){ - if (suite.root) return; - ++indents; - console.log('%s
', indent()); - ++indents; - console.log('%s

%s

', indent(), utils.escape(suite.title)); - console.log('%s
', indent()); - }); - - runner.on('suite end', function(suite){ - if (suite.root) return; - console.log('%s
', indent()); - --indents; - console.log('%s
', indent()); - --indents; - }); - - runner.on('pass', function(test){ - console.log('%s
%s
', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.fn.toString())); - console.log('%s
%s
', indent(), code); - }); -} - -}); // module: reporters/doc.js - -require.register("reporters/dot.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `Dot`. - */ - -exports = module.exports = Dot; - -/** - * Initialize a new `Dot` matrix test reporter. - * - * @param {Runner} runner - * @api public - */ - -function Dot(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , n = 0; - - runner.on('start', function(){ - process.stdout.write('\n '); - }); - - runner.on('pending', function(test){ - process.stdout.write(color('pending', Base.symbols.dot)); - }); - - runner.on('pass', function(test){ - if (++n % width == 0) process.stdout.write('\n '); - if ('slow' == test.speed) { - process.stdout.write(color('bright yellow', Base.symbols.dot)); - } else { - process.stdout.write(color(test.speed, Base.symbols.dot)); - } - }); - - runner.on('fail', function(test, err){ - if (++n % width == 0) process.stdout.write('\n '); - process.stdout.write(color('fail', Base.symbols.dot)); - }); - - runner.on('end', function(){ - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -Dot.prototype = new Base; -Dot.prototype.constructor = Dot; - -}); // module: reporters/dot.js - -require.register("reporters/html-cov.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var JSONCov = require('./json-cov') - , fs = require('browser/fs'); - -/** - * Expose `HTMLCov`. - */ - -exports = module.exports = HTMLCov; - -/** - * Initialize a new `JsCoverage` reporter. - * - * @param {Runner} runner - * @api public - */ - -function HTMLCov(runner) { - var jade = require('jade') - , file = __dirname + '/templates/coverage.jade' - , str = fs.readFileSync(file, 'utf8') - , fn = jade.compile(str, { filename: file }) - , self = this; - - JSONCov.call(this, runner, false); - - runner.on('end', function(){ - process.stdout.write(fn({ - cov: self.cov - , coverageClass: coverageClass - })); - }); -} - -/** - * Return coverage class for `n`. - * - * @return {String} - * @api private - */ - -function coverageClass(n) { - if (n >= 75) return 'high'; - if (n >= 50) return 'medium'; - if (n >= 25) return 'low'; - return 'terrible'; -} -}); // module: reporters/html-cov.js - -require.register("reporters/html.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils') - , Progress = require('../browser/progress') - , escape = utils.escape; - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Expose `Doc`. - */ - -exports = module.exports = HTML; - -/** - * Stats template. - */ - -var statsTemplate = '
'; - -/** - * Initialize a new `Doc` reporter. - * - * @param {Runner} runner - * @api public - */ - -function HTML(runner, root) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total - , stat = fragment(statsTemplate) - , items = stat.getElementsByTagName('li') - , passes = items[1].getElementsByTagName('em')[0] - , passesLink = items[1].getElementsByTagName('a')[0] - , failures = items[2].getElementsByTagName('em')[0] - , failuresLink = items[2].getElementsByTagName('a')[0] - , duration = items[3].getElementsByTagName('em')[0] - , canvas = stat.getElementsByTagName('canvas')[0] - , report = fragment('
    ') - , stack = [report] - , progress - , ctx - - root = root || document.getElementById('mocha'); - - if (canvas.getContext) { - var ratio = window.devicePixelRatio || 1; - canvas.style.width = canvas.width; - canvas.style.height = canvas.height; - canvas.width *= ratio; - canvas.height *= ratio; - ctx = canvas.getContext('2d'); - ctx.scale(ratio, ratio); - progress = new Progress; - } - - if (!root) return error('#mocha div missing, add it to your document'); - - // pass toggle - on(passesLink, 'click', function(){ - unhide(); - var name = /pass/.test(report.className) ? '' : ' pass'; - report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) hideSuitesWithout('test pass'); - }); - - // failure toggle - on(failuresLink, 'click', function(){ - unhide(); - var name = /fail/.test(report.className) ? '' : ' fail'; - report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) hideSuitesWithout('test fail'); - }); - - root.appendChild(stat); - root.appendChild(report); - - if (progress) progress.size(40); - - runner.on('suite', function(suite){ - if (suite.root) return; - - // suite - var url = '?grep=' + encodeURIComponent(suite.fullTitle()); - var el = fragment('
  • %s

  • ', url, escape(suite.title)); - - // container - stack[0].appendChild(el); - stack.unshift(document.createElement('ul')); - el.appendChild(stack[0]); - }); - - runner.on('suite end', function(suite){ - if (suite.root) return; - stack.shift(); - }); - - runner.on('fail', function(test, err){ - if ('hook' == test.type) runner.emit('test end', test); - }); - - runner.on('test end', function(test){ - window.scrollTo(0, document.body.scrollHeight); - - // TODO: add to stats - var percent = stats.tests / this.total * 100 | 0; - if (progress) progress.update(percent).draw(ctx); - - // update stats - var ms = new Date - stats.start; - text(passes, stats.passes); - text(failures, stats.failures); - text(duration, (ms / 1000).toFixed(2)); - - // test - if ('passed' == test.state) { - var el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration, encodeURIComponent(test.fullTitle())); - } else if (test.pending) { - var el = fragment('
  • %e

  • ', test.title); - } else { - var el = fragment('
  • %e

  • ', test.title, encodeURIComponent(test.fullTitle())); - var str = test.err.stack || test.err.toString(); - - // FF / Opera do not add the message - if (!~str.indexOf(test.err.message)) { - str = test.err.message + '\n' + str; - } - - // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we - // check for the result of the stringifying. - if ('[object Error]' == str) str = test.err.message; - - // Safari doesn't give you a stack. Let's at least provide a source line. - if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { - str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; - } - - el.appendChild(fragment('
    %e
    ', str)); - } - - // toggle code - // TODO: defer - if (!test.pending) { - var h2 = el.getElementsByTagName('h2')[0]; - - on(h2, 'click', function(){ - pre.style.display = 'none' == pre.style.display - ? 'inline-block' - : 'none'; - }); - - var pre = fragment('
    %e
    ', utils.clean(test.fn.toString())); - el.appendChild(pre); - pre.style.display = 'none'; - } - - // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. - if (stack[0]) stack[0].appendChild(el); - }); -} - -/** - * Display error `msg`. - */ - -function error(msg) { - document.body.appendChild(fragment('
    %s
    ', msg)); -} - -/** - * Return a DOM fragment from `html`. - */ - -function fragment(html) { - var args = arguments - , div = document.createElement('div') - , i = 1; - - div.innerHTML = html.replace(/%([se])/g, function(_, type){ - switch (type) { - case 's': return String(args[i++]); - case 'e': return escape(args[i++]); - } - }); - - return div.firstChild; -} - -/** - * Check for suites that do not have elements - * with `classname`, and hide them. - */ - -function hideSuitesWithout(classname) { - var suites = document.getElementsByClassName('suite'); - for (var i = 0; i < suites.length; i++) { - var els = suites[i].getElementsByClassName(classname); - if (0 == els.length) suites[i].className += ' hidden'; - } -} - -/** - * Unhide .hidden suites. - */ - -function unhide() { - var els = document.getElementsByClassName('suite hidden'); - for (var i = 0; i < els.length; ++i) { - els[i].className = els[i].className.replace('suite hidden', 'suite'); - } -} - -/** - * Set `el` text to `str`. - */ - -function text(el, str) { - if (el.textContent) { - el.textContent = str; - } else { - el.innerText = str; - } -} - -/** - * Listen on `event` with callback `fn`. - */ - -function on(el, event, fn) { - if (el.addEventListener) { - el.addEventListener(event, fn, false); - } else { - el.attachEvent('on' + event, fn); - } -} - -}); // module: reporters/html.js - -require.register("reporters/index.js", function(module, exports, require){ - -exports.Base = require('./base'); -exports.Dot = require('./dot'); -exports.Doc = require('./doc'); -exports.TAP = require('./tap'); -exports.JSON = require('./json'); -exports.HTML = require('./html'); -exports.List = require('./list'); -exports.Min = require('./min'); -exports.Spec = require('./spec'); -exports.Nyan = require('./nyan'); -exports.XUnit = require('./xunit'); -exports.Markdown = require('./markdown'); -exports.Progress = require('./progress'); -exports.Landing = require('./landing'); -exports.JSONCov = require('./json-cov'); -exports.HTMLCov = require('./html-cov'); -exports.JSONStream = require('./json-stream'); -exports.Teamcity = require('./teamcity'); - -}); // module: reporters/index.js - -require.register("reporters/json-cov.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `JSONCov`. - */ - -exports = module.exports = JSONCov; - -/** - * Initialize a new `JsCoverage` reporter. - * - * @param {Runner} runner - * @param {Boolean} output - * @api public - */ - -function JSONCov(runner, output) { - var self = this - , output = 1 == arguments.length ? true : output; - - Base.call(this, runner); - - var tests = [] - , failures = [] - , passes = []; - - runner.on('test end', function(test){ - tests.push(test); - }); - - runner.on('pass', function(test){ - passes.push(test); - }); - - runner.on('fail', function(test){ - failures.push(test); - }); - - runner.on('end', function(){ - var cov = global._$jscoverage || {}; - var result = self.cov = map(cov); - result.stats = self.stats; - result.tests = tests.map(clean); - result.failures = failures.map(clean); - result.passes = passes.map(clean); - if (!output) return; - process.stdout.write(JSON.stringify(result, null, 2 )); - }); -} - -/** - * Map jscoverage data to a JSON structure - * suitable for reporting. - * - * @param {Object} cov - * @return {Object} - * @api private - */ - -function map(cov) { - var ret = { - instrumentation: 'node-jscoverage' - , sloc: 0 - , hits: 0 - , misses: 0 - , coverage: 0 - , files: [] - }; - - for (var filename in cov) { - var data = coverage(filename, cov[filename]); - ret.files.push(data); - ret.hits += data.hits; - ret.misses += data.misses; - ret.sloc += data.sloc; - } - - ret.files.sort(function(a, b) { - return a.filename.localeCompare(b.filename); - }); - - if (ret.sloc > 0) { - ret.coverage = (ret.hits / ret.sloc) * 100; - } - - return ret; -}; - -/** - * Map jscoverage data for a single source file - * to a JSON structure suitable for reporting. - * - * @param {String} filename name of the source file - * @param {Object} data jscoverage coverage data - * @return {Object} - * @api private - */ - -function coverage(filename, data) { - var ret = { - filename: filename, - coverage: 0, - hits: 0, - misses: 0, - sloc: 0, - source: {} - }; - - data.source.forEach(function(line, num){ - num++; - - if (data[num] === 0) { - ret.misses++; - ret.sloc++; - } else if (data[num] !== undefined) { - ret.hits++; - ret.sloc++; - } - - ret.source[num] = { - source: line - , coverage: data[num] === undefined - ? '' - : data[num] - }; - }); - - ret.coverage = ret.hits / ret.sloc * 100; - - return ret; -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} - -}); // module: reporters/json-cov.js - -require.register("reporters/json-stream.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `List`. - */ - -exports = module.exports = List; - -/** - * Initialize a new `List` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function List(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total; - - runner.on('start', function(){ - console.log(JSON.stringify(['start', { total: total }])); - }); - - runner.on('pass', function(test){ - console.log(JSON.stringify(['pass', clean(test)])); - }); - - runner.on('fail', function(test, err){ - console.log(JSON.stringify(['fail', clean(test)])); - }); - - runner.on('end', function(){ - process.stdout.write(JSON.stringify(['end', self.stats])); - }); -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} -}); // module: reporters/json-stream.js - -require.register("reporters/json.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `JSON`. - */ - -exports = module.exports = JSONReporter; - -/** - * Initialize a new `JSON` reporter. - * - * @param {Runner} runner - * @api public - */ - -function JSONReporter(runner) { - var self = this; - Base.call(this, runner); - - var tests = [] - , failures = [] - , passes = []; - - runner.on('test end', function(test){ - tests.push(test); - }); - - runner.on('pass', function(test){ - passes.push(test); - }); - - runner.on('fail', function(test){ - failures.push(test); - }); - - runner.on('end', function(){ - var obj = { - stats: self.stats - , tests: tests.map(clean) - , failures: failures.map(clean) - , passes: passes.map(clean) - }; - - process.stdout.write(JSON.stringify(obj, null, 2)); - }); -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} -}); // module: reporters/json.js - -require.register("reporters/landing.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Landing`. - */ - -exports = module.exports = Landing; - -/** - * Airplane color. - */ - -Base.colors.plane = 0; - -/** - * Airplane crash color. - */ - -Base.colors['plane crash'] = 31; - -/** - * Runway color. - */ - -Base.colors.runway = 90; - -/** - * Initialize a new `Landing` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Landing(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , total = runner.total - , stream = process.stdout - , plane = color('plane', '✈') - , crashed = -1 - , n = 0; - - function runway() { - var buf = Array(width).join('-'); - return ' ' + color('runway', buf); - } - - runner.on('start', function(){ - stream.write('\n '); - cursor.hide(); - }); - - runner.on('test end', function(test){ - // check if the plane crashed - var col = -1 == crashed - ? width * ++n / total | 0 - : crashed; - - // show the crash - if ('failed' == test.state) { - plane = color('plane crash', '✈'); - crashed = col; - } - - // render landing strip - stream.write('\u001b[4F\n\n'); - stream.write(runway()); - stream.write('\n '); - stream.write(color('runway', Array(col).join('⋅'))); - stream.write(plane) - stream.write(color('runway', Array(width - col).join('⋅') + '\n')); - stream.write(runway()); - stream.write('\u001b[0m'); - }); - - runner.on('end', function(){ - cursor.show(); - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -Landing.prototype = new Base; -Landing.prototype.constructor = Landing; - -}); // module: reporters/landing.js - -require.register("reporters/list.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `List`. - */ - -exports = module.exports = List; - -/** - * Initialize a new `List` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function List(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , n = 0; - - runner.on('start', function(){ - console.log(); - }); - - runner.on('test', function(test){ - process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); - }); - - runner.on('pending', function(test){ - var fmt = color('checkmark', ' -') - + color('pending', ' %s'); - console.log(fmt, test.fullTitle()); - }); - - runner.on('pass', function(test){ - var fmt = color('checkmark', ' '+Base.symbols.dot) - + color('pass', ' %s: ') - + color(test.speed, '%dms'); - cursor.CR(); - console.log(fmt, test.fullTitle(), test.duration); - }); - - runner.on('fail', function(test, err){ - cursor.CR(); - console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); - }); - - runner.on('end', self.epilogue.bind(self)); -} - -/** - * Inherit from `Base.prototype`. - */ - -List.prototype = new Base; -List.prototype.constructor = List; - - -}); // module: reporters/list.js - -require.register("reporters/markdown.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils'); - -/** - * Expose `Markdown`. - */ - -exports = module.exports = Markdown; - -/** - * Initialize a new `Markdown` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Markdown(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , level = 0 - , buf = ''; - - function title(str) { - return Array(level).join('#') + ' ' + str; - } - - function indent() { - return Array(level).join(' '); - } - - function mapTOC(suite, obj) { - var ret = obj; - obj = obj[suite.title] = obj[suite.title] || { suite: suite }; - suite.suites.forEach(function(suite){ - mapTOC(suite, obj); - }); - return ret; - } - - function stringifyTOC(obj, level) { - ++level; - var buf = ''; - var link; - for (var key in obj) { - if ('suite' == key) continue; - if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; - if (key) buf += Array(level).join(' ') + link; - buf += stringifyTOC(obj[key], level); - } - --level; - return buf; - } - - function generateTOC(suite) { - var obj = mapTOC(suite, {}); - return stringifyTOC(obj, 0); - } - - generateTOC(runner.suite); - - runner.on('suite', function(suite){ - ++level; - var slug = utils.slug(suite.fullTitle()); - buf += '' + '\n'; - buf += title(suite.title) + '\n'; - }); - - runner.on('suite end', function(suite){ - --level; - }); - - runner.on('pass', function(test){ - var code = utils.clean(test.fn.toString()); - buf += test.title + '.\n'; - buf += '\n```js\n'; - buf += code + '\n'; - buf += '```\n\n'; - }); - - runner.on('end', function(){ - process.stdout.write('# TOC\n'); - process.stdout.write(generateTOC(runner.suite)); - process.stdout.write(buf); - }); -} -}); // module: reporters/markdown.js - -require.register("reporters/min.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `Min`. - */ - -exports = module.exports = Min; - -/** - * Initialize a new `Min` minimal test reporter (best used with --watch). - * - * @param {Runner} runner - * @api public - */ - -function Min(runner) { - Base.call(this, runner); - - runner.on('start', function(){ - // clear screen - process.stdout.write('\u001b[2J'); - // set cursor position - process.stdout.write('\u001b[1;3H'); - }); - - runner.on('end', this.epilogue.bind(this)); -} - -/** - * Inherit from `Base.prototype`. - */ - -Min.prototype = new Base; -Min.prototype.constructor = Min; - -}); // module: reporters/min.js - -require.register("reporters/nyan.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `Dot`. - */ - -exports = module.exports = NyanCat; - -/** - * Initialize a new `Dot` matrix test reporter. - * - * @param {Runner} runner - * @api public - */ - -function NyanCat(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , rainbowColors = this.rainbowColors = self.generateColors() - , colorIndex = this.colorIndex = 0 - , numerOfLines = this.numberOfLines = 4 - , trajectories = this.trajectories = [[], [], [], []] - , nyanCatWidth = this.nyanCatWidth = 11 - , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) - , scoreboardWidth = this.scoreboardWidth = 5 - , tick = this.tick = 0 - , n = 0; - - runner.on('start', function(){ - Base.cursor.hide(); - self.draw('start'); - }); - - runner.on('pending', function(test){ - self.draw('pending'); - }); - - runner.on('pass', function(test){ - self.draw('pass'); - }); - - runner.on('fail', function(test, err){ - self.draw('fail'); - }); - - runner.on('end', function(){ - Base.cursor.show(); - for (var i = 0; i < self.numberOfLines; i++) write('\n'); - self.epilogue(); - }); -} - -/** - * Draw the nyan cat with runner `status`. - * - * @param {String} status - * @api private - */ - -NyanCat.prototype.draw = function(status){ - this.appendRainbow(); - this.drawScoreboard(); - this.drawRainbow(); - this.drawNyanCat(status); - this.tick = !this.tick; -}; - -/** - * Draw the "scoreboard" showing the number - * of passes, failures and pending tests. - * - * @api private - */ - -NyanCat.prototype.drawScoreboard = function(){ - var stats = this.stats; - var colors = Base.colors; - - function draw(color, n) { - write(' '); - write('\u001b[' + color + 'm' + n + '\u001b[0m'); - write('\n'); - } - - draw(colors.green, stats.passes); - draw(colors.fail, stats.failures); - draw(colors.pending, stats.pending); - write('\n'); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Append the rainbow. - * - * @api private - */ - -NyanCat.prototype.appendRainbow = function(){ - var segment = this.tick ? '_' : '-'; - var rainbowified = this.rainbowify(segment); - - for (var index = 0; index < this.numberOfLines; index++) { - var trajectory = this.trajectories[index]; - if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); - trajectory.push(rainbowified); - } -}; - -/** - * Draw the rainbow. - * - * @api private - */ - -NyanCat.prototype.drawRainbow = function(){ - var self = this; - - this.trajectories.forEach(function(line, index) { - write('\u001b[' + self.scoreboardWidth + 'C'); - write(line.join('')); - write('\n'); - }); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Draw the nyan cat with `status`. - * - * @param {String} status - * @api private - */ - -NyanCat.prototype.drawNyanCat = function(status) { - var self = this; - var startWidth = this.scoreboardWidth + this.trajectories[0].length; - - [0, 1, 2, 3].forEach(function(index) { - write('\u001b[' + startWidth + 'C'); - - switch (index) { - case 0: - write('_,------,'); - write('\n'); - break; - case 1: - var padding = self.tick ? ' ' : ' '; - write('_|' + padding + '/\\_/\\ '); - write('\n'); - break; - case 2: - var padding = self.tick ? '_' : '__'; - var tail = self.tick ? '~' : '^'; - var face; - switch (status) { - case 'pass': - face = '( ^ .^)'; - break; - case 'fail': - face = '( o .o)'; - break; - default: - face = '( - .-)'; - } - write(tail + '|' + padding + face + ' '); - write('\n'); - break; - case 3: - var padding = self.tick ? ' ' : ' '; - write(padding + '"" "" '); - write('\n'); - break; - } - }); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Move cursor up `n`. - * - * @param {Number} n - * @api private - */ - -NyanCat.prototype.cursorUp = function(n) { - write('\u001b[' + n + 'A'); -}; - -/** - * Move cursor down `n`. - * - * @param {Number} n - * @api private - */ - -NyanCat.prototype.cursorDown = function(n) { - write('\u001b[' + n + 'B'); -}; - -/** - * Generate rainbow colors. - * - * @return {Array} - * @api private - */ - -NyanCat.prototype.generateColors = function(){ - var colors = []; - - for (var i = 0; i < (6 * 7); i++) { - var pi3 = Math.floor(Math.PI / 3); - var n = (i * (1.0 / 6)); - var r = Math.floor(3 * Math.sin(n) + 3); - var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); - var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); - colors.push(36 * r + 6 * g + b + 16); - } - - return colors; -}; - -/** - * Apply rainbow to the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -NyanCat.prototype.rainbowify = function(str){ - var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; - this.colorIndex += 1; - return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; -}; - -/** - * Stdout helper. - */ - -function write(string) { - process.stdout.write(string); -} - -/** - * Inherit from `Base.prototype`. - */ - -NyanCat.prototype = new Base; -NyanCat.prototype.constructor = NyanCat; - - -}); // module: reporters/nyan.js - -require.register("reporters/progress.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Progress`. - */ - -exports = module.exports = Progress; - -/** - * General progress bar color. - */ - -Base.colors.progress = 90; - -/** - * Initialize a new `Progress` bar test reporter. - * - * @param {Runner} runner - * @param {Object} options - * @api public - */ - -function Progress(runner, options) { - Base.call(this, runner); - - var self = this - , options = options || {} - , stats = this.stats - , width = Base.window.width * .50 | 0 - , total = runner.total - , complete = 0 - , max = Math.max; - - // default chars - options.open = options.open || '['; - options.complete = options.complete || '▬'; - options.incomplete = options.incomplete || Base.symbols.dot; - options.close = options.close || ']'; - options.verbose = false; - - // tests started - runner.on('start', function(){ - console.log(); - cursor.hide(); - }); - - // tests complete - runner.on('test end', function(){ - complete++; - var incomplete = total - complete - , percent = complete / total - , n = width * percent | 0 - , i = width - n; - - cursor.CR(); - process.stdout.write('\u001b[J'); - process.stdout.write(color('progress', ' ' + options.open)); - process.stdout.write(Array(n).join(options.complete)); - process.stdout.write(Array(i).join(options.incomplete)); - process.stdout.write(color('progress', options.close)); - if (options.verbose) { - process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); - } - }); - - // tests are complete, output some stats - // and the failures if any - runner.on('end', function(){ - cursor.show(); - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -Progress.prototype = new Base; -Progress.prototype.constructor = Progress; - - -}); // module: reporters/progress.js - -require.register("reporters/spec.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Spec`. - */ - -exports = module.exports = Spec; - -/** - * Initialize a new `Spec` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function Spec(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , indents = 0 - , n = 0; - - function indent() { - return Array(indents).join(' ') - } - - runner.on('start', function(){ - console.log(); - }); - - runner.on('suite', function(suite){ - ++indents; - console.log(color('suite', '%s%s'), indent(), suite.title); - }); - - runner.on('suite end', function(suite){ - --indents; - if (1 == indents) console.log(); - }); - - runner.on('test', function(test){ - process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': ')); - }); - - runner.on('pending', function(test){ - var fmt = indent() + color('pending', ' - %s'); - console.log(fmt, test.title); - }); - - runner.on('pass', function(test){ - if ('fast' == test.speed) { - var fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s '); - cursor.CR(); - console.log(fmt, test.title); - } else { - var fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s ') - + color(test.speed, '(%dms)'); - cursor.CR(); - console.log(fmt, test.title, test.duration); - } - }); - - runner.on('fail', function(test, err){ - cursor.CR(); - console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); - }); - - runner.on('end', self.epilogue.bind(self)); -} - -/** - * Inherit from `Base.prototype`. - */ - -Spec.prototype = new Base; -Spec.prototype.constructor = Spec; - - -}); // module: reporters/spec.js - -require.register("reporters/tap.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `TAP`. - */ - -exports = module.exports = TAP; - -/** - * Initialize a new `TAP` reporter. - * - * @param {Runner} runner - * @api public - */ - -function TAP(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , n = 1 - , passes = 0 - , failures = 0; - - runner.on('start', function(){ - var total = runner.grepTotal(runner.suite); - console.log('%d..%d', 1, total); - }); - - runner.on('test end', function(){ - ++n; - }); - - runner.on('pending', function(test){ - console.log('ok %d %s # SKIP -', n, title(test)); - }); - - runner.on('pass', function(test){ - passes++; - console.log('ok %d %s', n, title(test)); - }); - - runner.on('fail', function(test, err){ - failures++; - console.log('not ok %d %s', n, title(test)); - if (err.stack) console.log(err.stack.replace(/^/gm, ' ')); - }); - - runner.on('end', function(){ - console.log('# tests ' + (passes + failures)); - console.log('# pass ' + passes); - console.log('# fail ' + failures); - }); -} - -/** - * Return a TAP-safe title of `test` - * - * @param {Object} test - * @return {String} - * @api private - */ - -function title(test) { - return test.fullTitle().replace(/#/g, ''); -} - -}); // module: reporters/tap.js - -require.register("reporters/teamcity.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `Teamcity`. - */ - -exports = module.exports = Teamcity; - -/** - * Initialize a new `Teamcity` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Teamcity(runner) { - Base.call(this, runner); - var stats = this.stats; - - runner.on('start', function() { - console.log("##teamcity[testSuiteStarted name='mocha.suite']"); - }); - - runner.on('test', function(test) { - console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']"); - }); - - runner.on('fail', function(test, err) { - console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']"); - }); - - runner.on('pending', function(test) { - console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']"); - }); - - runner.on('test end', function(test) { - console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']"); - }); - - runner.on('end', function() { - console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']"); - }); -} - -/** - * Escape the given `str`. - */ - -function escape(str) { - return str - .replace(/\|/g, "||") - .replace(/\n/g, "|n") - .replace(/\r/g, "|r") - .replace(/\[/g, "|[") - .replace(/\]/g, "|]") - .replace(/\u0085/g, "|x") - .replace(/\u2028/g, "|l") - .replace(/\u2029/g, "|p") - .replace(/'/g, "|'"); -} - -}); // module: reporters/teamcity.js - -require.register("reporters/xunit.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils') - , escape = utils.escape; - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Expose `XUnit`. - */ - -exports = module.exports = XUnit; - -/** - * Initialize a new `XUnit` reporter. - * - * @param {Runner} runner - * @api public - */ - -function XUnit(runner) { - Base.call(this, runner); - var stats = this.stats - , tests = [] - , self = this; - - runner.on('pass', function(test){ - tests.push(test); - }); - - runner.on('fail', function(test){ - tests.push(test); - }); - - runner.on('end', function(){ - console.log(tag('testsuite', { - name: 'Mocha Tests' - , tests: stats.tests - , failures: stats.failures - , errors: stats.failures - , skip: stats.tests - stats.failures - stats.passes - , timestamp: (new Date).toUTCString() - , time: stats.duration / 1000 - }, false)); - - tests.forEach(test); - console.log(''); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -XUnit.prototype = new Base; -XUnit.prototype.constructor = XUnit; - - -/** - * Output tag for the given `test.` - */ - -function test(test) { - var attrs = { - classname: test.parent.fullTitle() - , name: test.title - , time: test.duration / 1000 - }; - - if ('failed' == test.state) { - var err = test.err; - attrs.message = escape(err.message); - console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); - } else if (test.pending) { - console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); - } else { - console.log(tag('testcase', attrs, true) ); - } -} - -/** - * HTML tag helper. - */ - -function tag(name, attrs, close, content) { - var end = close ? '/>' : '>' - , pairs = [] - , tag; - - for (var key in attrs) { - pairs.push(key + '="' + escape(attrs[key]) + '"'); - } - - tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; - if (content) tag += content + ''; -} - -}); // module: reporters/xunit.js - -require.register("runnable.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('mocha:runnable') - , milliseconds = require('./ms'); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Object#toString(). - */ - -var toString = Object.prototype.toString; - -/** - * Expose `Runnable`. - */ - -module.exports = Runnable; - -/** - * Initialize a new `Runnable` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Runnable(title, fn) { - this.title = title; - this.fn = fn; - this.async = fn && fn.length; - this.sync = ! this.async; - this._timeout = 2000; - this._slow = 75; - this.timedOut = false; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -Runnable.prototype = new EventEmitter; -Runnable.prototype.constructor = Runnable; - - -/** - * Set & get timeout `ms`. - * - * @param {Number|String} ms - * @return {Runnable|Number} ms or self - * @api private - */ - -Runnable.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._timeout = ms; - if (this.timer) this.resetTimeout(); - return this; -}; - -/** - * Set & get slow `ms`. - * - * @param {Number|String} ms - * @return {Runnable|Number} ms or self - * @api private - */ - -Runnable.prototype.slow = function(ms){ - if (0 === arguments.length) return this._slow; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._slow = ms; - return this; -}; - -/** - * Return the full title generated by recursively - * concatenating the parent's full title. - * - * @return {String} - * @api public - */ - -Runnable.prototype.fullTitle = function(){ - return this.parent.fullTitle() + ' ' + this.title; -}; - -/** - * Clear the timeout. - * - * @api private - */ - -Runnable.prototype.clearTimeout = function(){ - clearTimeout(this.timer); -}; - -/** - * Inspect the runnable void of private properties. - * - * @return {String} - * @api private - */ - -Runnable.prototype.inspect = function(){ - return JSON.stringify(this, function(key, val){ - if ('_' == key[0]) return; - if ('parent' == key) return '#'; - if ('ctx' == key) return '#'; - return val; - }, 2); -}; - -/** - * Reset the timeout. - * - * @api private - */ - -Runnable.prototype.resetTimeout = function(){ - var self = this - , ms = this.timeout(); - - this.clearTimeout(); - if (ms) { - this.timer = setTimeout(function(){ - self.callback(new Error('timeout of ' + ms + 'ms exceeded')); - self.timedOut = true; - }, ms); - } -}; - -/** - * Run the test and invoke `fn(err)`. - * - * @param {Function} fn - * @api private - */ - -Runnable.prototype.run = function(fn){ - var self = this - , ms = this.timeout() - , start = new Date - , ctx = this.ctx - , finished - , emitted; - - if (ctx) ctx.runnable(this); - - // timeout - if (this.async) { - if (ms) { - this.timer = setTimeout(function(){ - done(new Error('timeout of ' + ms + 'ms exceeded')); - self.timedOut = true; - }, ms); - } - } - - // called multiple times - function multiple(err) { - if (emitted) return; - emitted = true; - self.emit('error', err || new Error('done() called multiple times')); - } - - // finished - function done(err) { - if (self.timedOut) return; - if (finished) return multiple(err); - self.clearTimeout(); - self.duration = new Date - start; - finished = true; - fn(err); - } - - // for .resetTimeout() - this.callback = done; - - // async - if (this.async) { - try { - this.fn.call(ctx, function(err){ - if (toString.call(err) === "[object Error]") return done(err); - if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); - done(); - }); - } catch (err) { - done(err); - } - return; - } - - if (this.asyncOnly) { - return done(new Error('--async-only option in use without declaring `done()`')); - } - - // sync - try { - if (!this.pending) this.fn.call(ctx); - this.duration = new Date - start; - fn(); - } catch (err) { - fn(err); - } -}; - -}); // module: runnable.js - -require.register("runner.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('mocha:runner') - , Test = require('./test') - , utils = require('./utils') - , filter = utils.filter - , keys = utils.keys - , noop = function(){}; - -/** - * Non-enumerable globals. - */ - -var globals = [ - 'setTimeout', - 'clearTimeout', - 'setInterval', - 'clearInterval', - 'XMLHttpRequest', - 'Date' -]; - -/** - * Expose `Runner`. - */ - -module.exports = Runner; - -/** - * Initialize a `Runner` for the given `suite`. - * - * Events: - * - * - `start` execution started - * - `end` execution complete - * - `suite` (suite) test suite execution started - * - `suite end` (suite) all tests (and sub-suites) have finished - * - `test` (test) test execution started - * - `test end` (test) test completed - * - `hook` (hook) hook execution started - * - `hook end` (hook) hook complete - * - `pass` (test) test passed - * - `fail` (test, err) test failed - * - * @api public - */ - -function Runner(suite) { - var self = this; - this._globals = []; - this.suite = suite; - this.total = suite.total(); - this.failures = 0; - this.on('test end', function(test){ self.checkGlobals(test); }); - this.on('hook end', function(hook){ self.checkGlobals(hook); }); - this.grep(/.*/); - this.globals(this.globalProps().concat(['errno'])); -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -Runner.prototype = new EventEmitter; -Runner.prototype.constructor = Runner; - - -/** - * Run tests with full titles matching `re`. Updates runner.total - * with number of tests matched. - * - * @param {RegExp} re - * @param {Boolean} invert - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.grep = function(re, invert){ - debug('grep %s', re); - this._grep = re; - this._invert = invert; - this.total = this.grepTotal(this.suite); - return this; -}; - -/** - * Returns the number of tests matching the grep search for the - * given suite. - * - * @param {Suite} suite - * @return {Number} - * @api public - */ - -Runner.prototype.grepTotal = function(suite) { - var self = this; - var total = 0; - - suite.eachTest(function(test){ - var match = self._grep.test(test.fullTitle()); - if (self._invert) match = !match; - if (match) total++; - }); - - return total; -}; - -/** - * Return a list of global properties. - * - * @return {Array} - * @api private - */ - -Runner.prototype.globalProps = function() { - var props = utils.keys(global); - - // non-enumerables - for (var i = 0; i < globals.length; ++i) { - if (~utils.indexOf(props, globals[i])) continue; - props.push(globals[i]); - } - - return props; -}; - -/** - * Allow the given `arr` of globals. - * - * @param {Array} arr - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.globals = function(arr){ - if (0 == arguments.length) return this._globals; - debug('globals %j', arr); - utils.forEach(arr, function(arr){ - this._globals.push(arr); - }, this); - return this; -}; - -/** - * Check for global variable leaks. - * - * @api private - */ - -Runner.prototype.checkGlobals = function(test){ - if (this.ignoreLeaks) return; - var ok = this._globals; - var globals = this.globalProps(); - var isNode = process.kill; - var leaks; - - // check length - 2 ('errno' and 'location' globals) - if (isNode && 1 == ok.length - globals.length) return - else if (2 == ok.length - globals.length) return; - - leaks = filterLeaks(ok, globals); - this._globals = this._globals.concat(leaks); - - if (leaks.length > 1) { - this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); - } else if (leaks.length) { - this.fail(test, new Error('global leak detected: ' + leaks[0])); - } -}; - -/** - * Fail the given `test`. - * - * @param {Test} test - * @param {Error} err - * @api private - */ - -Runner.prototype.fail = function(test, err){ - ++this.failures; - test.state = 'failed'; - - if ('string' == typeof err) { - err = new Error('the string "' + err + '" was thrown, throw an Error :)'); - } - - this.emit('fail', test, err); -}; - -/** - * Fail the given `hook` with `err`. - * - * Hook failures (currently) hard-end due - * to that fact that a failing hook will - * surely cause subsequent tests to fail, - * causing jumbled reporting. - * - * @param {Hook} hook - * @param {Error} err - * @api private - */ - -Runner.prototype.failHook = function(hook, err){ - this.fail(hook, err); - this.emit('end'); -}; - -/** - * Run hook `name` callbacks and then invoke `fn()`. - * - * @param {String} name - * @param {Function} function - * @api private - */ - -Runner.prototype.hook = function(name, fn){ - var suite = this.suite - , hooks = suite['_' + name] - , self = this - , timer; - - function next(i) { - var hook = hooks[i]; - if (!hook) return fn(); - self.currentRunnable = hook; - - self.emit('hook', hook); - - hook.on('error', function(err){ - self.failHook(hook, err); - }); - - hook.run(function(err){ - hook.removeAllListeners('error'); - var testError = hook.error(); - if (testError) self.fail(self.test, testError); - if (err) return self.failHook(hook, err); - self.emit('hook end', hook); - next(++i); - }); - } - - process.nextTick(function(){ - next(0); - }); -}; - -/** - * Run hook `name` for the given array of `suites` - * in order, and callback `fn(err)`. - * - * @param {String} name - * @param {Array} suites - * @param {Function} fn - * @api private - */ - -Runner.prototype.hooks = function(name, suites, fn){ - var self = this - , orig = this.suite; - - function next(suite) { - self.suite = suite; - - if (!suite) { - self.suite = orig; - return fn(); - } - - self.hook(name, function(err){ - if (err) { - self.suite = orig; - return fn(err); - } - - next(suites.pop()); - }); - } - - next(suites.pop()); -}; - -/** - * Run hooks from the top level down. - * - * @param {String} name - * @param {Function} fn - * @api private - */ - -Runner.prototype.hookUp = function(name, fn){ - var suites = [this.suite].concat(this.parents()).reverse(); - this.hooks(name, suites, fn); -}; - -/** - * Run hooks from the bottom up. - * - * @param {String} name - * @param {Function} fn - * @api private - */ - -Runner.prototype.hookDown = function(name, fn){ - var suites = [this.suite].concat(this.parents()); - this.hooks(name, suites, fn); -}; - -/** - * Return an array of parent Suites from - * closest to furthest. - * - * @return {Array} - * @api private - */ - -Runner.prototype.parents = function(){ - var suite = this.suite - , suites = []; - while (suite = suite.parent) suites.push(suite); - return suites; -}; - -/** - * Run the current test and callback `fn(err)`. - * - * @param {Function} fn - * @api private - */ - -Runner.prototype.runTest = function(fn){ - var test = this.test - , self = this; - - if (this.asyncOnly) test.asyncOnly = true; - - try { - test.on('error', function(err){ - self.fail(test, err); - }); - test.run(fn); - } catch (err) { - fn(err); - } -}; - -/** - * Run tests in the given `suite` and invoke - * the callback `fn()` when complete. - * - * @param {Suite} suite - * @param {Function} fn - * @api private - */ - -Runner.prototype.runTests = function(suite, fn){ - var self = this - , tests = suite.tests.slice() - , test; - - function next(err) { - // if we bail after first err - if (self.failures && suite._bail) return fn(); - - // next test - test = tests.shift(); - - // all done - if (!test) return fn(); - - // grep - var match = self._grep.test(test.fullTitle()); - if (self._invert) match = !match; - if (!match) return next(); - - // pending - if (test.pending) { - self.emit('pending', test); - self.emit('test end', test); - return next(); - } - - // execute test and hook(s) - self.emit('test', self.test = test); - self.hookDown('beforeEach', function(){ - self.currentRunnable = self.test; - self.runTest(function(err){ - test = self.test; - - if (err) { - self.fail(test, err); - self.emit('test end', test); - return self.hookUp('afterEach', next); - } - - test.state = 'passed'; - self.emit('pass', test); - self.emit('test end', test); - self.hookUp('afterEach', next); - }); - }); - } - - this.next = next; - next(); -}; - -/** - * Run the given `suite` and invoke the - * callback `fn()` when complete. - * - * @param {Suite} suite - * @param {Function} fn - * @api private - */ - -Runner.prototype.runSuite = function(suite, fn){ - var total = this.grepTotal(suite) - , self = this - , i = 0; - - debug('run suite %s', suite.fullTitle()); - - if (!total) return fn(); - - this.emit('suite', this.suite = suite); - - function next() { - var curr = suite.suites[i++]; - if (!curr) return done(); - self.runSuite(curr, next); - } - - function done() { - self.suite = suite; - self.hook('afterAll', function(){ - self.emit('suite end', suite); - fn(); - }); - } - - this.hook('beforeAll', function(){ - self.runTests(suite, next); - }); -}; - -/** - * Handle uncaught exceptions. - * - * @param {Error} err - * @api private - */ - -Runner.prototype.uncaught = function(err){ - debug('uncaught exception %s', err.message); - var runnable = this.currentRunnable; - if (!runnable || 'failed' == runnable.state) return; - runnable.clearTimeout(); - err.uncaught = true; - this.fail(runnable, err); - - // recover from test - if ('test' == runnable.type) { - this.emit('test end', runnable); - this.hookUp('afterEach', this.next); - return; - } - - // bail on hooks - this.emit('end'); -}; - -/** - * Run the root suite and invoke `fn(failures)` - * on completion. - * - * @param {Function} fn - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.run = function(fn){ - var self = this - , fn = fn || function(){}; - - debug('start'); - - // callback - this.on('end', function(){ - debug('end'); - process.removeListener('uncaughtException', function(err){ - self.uncaught(err); - }); - fn(self.failures); - }); - - // run suites - this.emit('start'); - this.runSuite(this.suite, function(){ - debug('finished running'); - self.emit('end'); - }); - - // uncaught exception - process.on('uncaughtException', function(err){ - self.uncaught(err); - }); - - return this; -}; - -/** - * Filter leaks with the given globals flagged as `ok`. - * - * @param {Array} ok - * @param {Array} globals - * @return {Array} - * @api private - */ - -function filterLeaks(ok, globals) { - return filter(globals, function(key){ - var matched = filter(ok, function(ok){ - if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); - // Opera and IE expose global variables for HTML element IDs (issue #243) - if (/^mocha-/.test(key)) return true; - return key == ok; - }); - return matched.length == 0 && (!global.navigator || 'onerror' !== key); - }); -} - -}); // module: runner.js - -require.register("suite.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('mocha:suite') - , milliseconds = require('./ms') - , utils = require('./utils') - , Hook = require('./hook'); - -/** - * Expose `Suite`. - */ - -exports = module.exports = Suite; - -/** - * Create a new `Suite` with the given `title` - * and parent `Suite`. When a suite with the - * same title is already present, that suite - * is returned to provide nicer reporter - * and more flexible meta-testing. - * - * @param {Suite} parent - * @param {String} title - * @return {Suite} - * @api public - */ - -exports.create = function(parent, title){ - var suite = new Suite(title, parent.ctx); - suite.parent = parent; - if (parent.pending) suite.pending = true; - title = suite.fullTitle(); - parent.addSuite(suite); - return suite; -}; - -/** - * Initialize a new `Suite` with the given - * `title` and `ctx`. - * - * @param {String} title - * @param {Context} ctx - * @api private - */ - -function Suite(title, ctx) { - this.title = title; - this.ctx = ctx; - this.suites = []; - this.tests = []; - this.pending = false; - this._beforeEach = []; - this._beforeAll = []; - this._afterEach = []; - this._afterAll = []; - this.root = !title; - this._timeout = 2000; - this._slow = 75; - this._bail = false; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -Suite.prototype = new EventEmitter; -Suite.prototype.constructor = Suite; - - -/** - * Return a clone of this `Suite`. - * - * @return {Suite} - * @api private - */ - -Suite.prototype.clone = function(){ - var suite = new Suite(this.title); - debug('clone'); - suite.ctx = this.ctx; - suite.timeout(this.timeout()); - suite.slow(this.slow()); - suite.bail(this.bail()); - return suite; -}; - -/** - * Set timeout `ms` or short-hand such as "2s". - * - * @param {Number|String} ms - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._timeout = parseInt(ms, 10); - return this; -}; - -/** - * Set slow `ms` or short-hand such as "2s". - * - * @param {Number|String} ms - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.slow = function(ms){ - if (0 === arguments.length) return this._slow; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('slow %d', ms); - this._slow = ms; - return this; -}; - -/** - * Sets whether to bail after first error. - * - * @parma {Boolean} bail - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.bail = function(bail){ - if (0 == arguments.length) return this._bail; - debug('bail %s', bail); - this._bail = bail; - return this; -}; - -/** - * Run `fn(test[, done])` before running tests. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.beforeAll = function(fn){ - if (this.pending) return this; - var hook = new Hook('"before all" hook', fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeAll.push(hook); - this.emit('beforeAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after running tests. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.afterAll = function(fn){ - if (this.pending) return this; - var hook = new Hook('"after all" hook', fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterAll.push(hook); - this.emit('afterAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` before each test case. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.beforeEach = function(fn){ - if (this.pending) return this; - var hook = new Hook('"before each" hook', fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeEach.push(hook); - this.emit('beforeEach', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after each test case. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.afterEach = function(fn){ - if (this.pending) return this; - var hook = new Hook('"after each" hook', fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterEach.push(hook); - this.emit('afterEach', hook); - return this; -}; - -/** - * Add a test `suite`. - * - * @param {Suite} suite - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.addSuite = function(suite){ - suite.parent = this; - suite.timeout(this.timeout()); - suite.slow(this.slow()); - suite.bail(this.bail()); - this.suites.push(suite); - this.emit('suite', suite); - return this; -}; - -/** - * Add a `test` to this suite. - * - * @param {Test} test - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.addTest = function(test){ - test.parent = this; - test.timeout(this.timeout()); - test.slow(this.slow()); - test.ctx = this.ctx; - this.tests.push(test); - this.emit('test', test); - return this; -}; - -/** - * Return the full title generated by recursively - * concatenating the parent's full title. - * - * @return {String} - * @api public - */ - -Suite.prototype.fullTitle = function(){ - if (this.parent) { - var full = this.parent.fullTitle(); - if (full) return full + ' ' + this.title; - } - return this.title; -}; - -/** - * Return the total number of tests. - * - * @return {Number} - * @api public - */ - -Suite.prototype.total = function(){ - return utils.reduce(this.suites, function(sum, suite){ - return sum + suite.total(); - }, 0) + this.tests.length; -}; - -/** - * Iterates through each suite recursively to find - * all tests. Applies a function in the format - * `fn(test)`. - * - * @param {Function} fn - * @return {Suite} - * @api private - */ - -Suite.prototype.eachTest = function(fn){ - utils.forEach(this.tests, fn); - utils.forEach(this.suites, function(suite){ - suite.eachTest(fn); - }); - return this; -}; - -}); // module: suite.js - -require.register("test.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); - -/** - * Expose `Test`. - */ - -module.exports = Test; - -/** - * Initialize a new `Test` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Test(title, fn) { - Runnable.call(this, title, fn); - this.pending = !fn; - this.type = 'test'; -} - -/** - * Inherit from `Runnable.prototype`. - */ - -Test.prototype = new Runnable; -Test.prototype.constructor = Test; - - -}); // module: test.js - -require.register("utils.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var fs = require('browser/fs') - , path = require('browser/path') - , join = path.join - , debug = require('browser/debug')('mocha:watch'); - -/** - * Ignored directories. - */ - -var ignore = ['node_modules', '.git']; - -/** - * Escape special characters in the given string of html. - * - * @param {String} html - * @return {String} - * @api private - */ - -exports.escape = function(html){ - return String(html) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(//g, '>'); -}; - -/** - * Array#forEach (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} scope - * @api private - */ - -exports.forEach = function(arr, fn, scope){ - for (var i = 0, l = arr.length; i < l; i++) - fn.call(scope, arr[i], i); -}; - -/** - * Array#indexOf (<=IE8) - * - * @parma {Array} arr - * @param {Object} obj to find index of - * @param {Number} start - * @api private - */ - -exports.indexOf = function(arr, obj, start){ - for (var i = start || 0, l = arr.length; i < l; i++) { - if (arr[i] === obj) - return i; - } - return -1; -}; - -/** - * Array#reduce (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} initial value - * @api private - */ - -exports.reduce = function(arr, fn, val){ - var rval = val; - - for (var i = 0, l = arr.length; i < l; i++) { - rval = fn(rval, arr[i], i, arr); - } - - return rval; -}; - -/** - * Array#filter (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @api private - */ - -exports.filter = function(arr, fn){ - var ret = []; - - for (var i = 0, l = arr.length; i < l; i++) { - var val = arr[i]; - if (fn(val, i, arr)) ret.push(val); - } - - return ret; -}; - -/** - * Object.keys (<=IE8) - * - * @param {Object} obj - * @return {Array} keys - * @api private - */ - -exports.keys = Object.keys || function(obj) { - var keys = [] - , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 - - for (var key in obj) { - if (has.call(obj, key)) { - keys.push(key); - } - } - - return keys; -}; - -/** - * Watch the given `files` for changes - * and invoke `fn(file)` on modification. - * - * @param {Array} files - * @param {Function} fn - * @api private - */ - -exports.watch = function(files, fn){ - var options = { interval: 100 }; - files.forEach(function(file){ - debug('file %s', file); - fs.watchFile(file, options, function(curr, prev){ - if (prev.mtime < curr.mtime) fn(file); - }); - }); -}; - -/** - * Ignored files. - */ - -function ignored(path){ - return !~ignore.indexOf(path); -} - -/** - * Lookup files in the given `dir`. - * - * @return {Array} - * @api private - */ - -exports.files = function(dir, ret){ - ret = ret || []; - - fs.readdirSync(dir) - .filter(ignored) - .forEach(function(path){ - path = join(dir, path); - if (fs.statSync(path).isDirectory()) { - exports.files(path, ret); - } else if (path.match(/\.(js|coffee)$/)) { - ret.push(path); - } - }); - - return ret; -}; - -/** - * Compute a slug from the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.slug = function(str){ - return str - .toLowerCase() - .replace(/ +/g, '-') - .replace(/[^-\w]/g, ''); -}; - -/** - * Strip the function definition from `str`, - * and re-indent for pre whitespace. - */ - -exports.clean = function(str) { - str = str - .replace(/^function *\(.*\) *{/, '') - .replace(/\s+\}$/, ''); - - var spaces = str.match(/^\n?( *)/)[1].length - , re = new RegExp('^ {' + spaces + '}', 'gm'); - - str = str.replace(re, ''); - - return exports.trim(str); -}; - -/** - * Escape regular expression characters in `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.escapeRegexp = function(str){ - return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); -}; - -/** - * Trim the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.trim = function(str){ - return str.replace(/^\s+|\s+$/g, ''); -}; - -/** - * Parse the given `qs`. - * - * @param {String} qs - * @return {Object} - * @api private - */ - -exports.parseQuery = function(qs){ - return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ - var i = pair.indexOf('=') - , key = pair.slice(0, i) - , val = pair.slice(++i); - - obj[key] = decodeURIComponent(val); - return obj; - }, {}); -}; - -/** - * Highlight the given string of `js`. - * - * @param {String} js - * @return {String} - * @api private - */ - -function highlight(js) { - return js - .replace(//g, '>') - .replace(/\/\/(.*)/gm, '//$1') - .replace(/('.*?')/gm, '$1') - .replace(/(\d+\.\d+)/gm, '$1') - .replace(/(\d+)/gm, '$1') - .replace(/\bnew *(\w+)/gm, 'new $1') - .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') -} - -/** - * Highlight the contents of tag `name`. - * - * @param {String} name - * @api private - */ - -exports.highlightTags = function(name) { - var code = document.getElementsByTagName(name); - for (var i = 0, len = code.length; i < len; ++i) { - code[i].innerHTML = highlight(code[i].innerHTML); - } -}; - -}); // module: utils.js -/** - * Node shims. - * - * These are meant only to allow - * mocha.js to run untouched, not - * to allow running node code in - * the browser. - */ - -process = {}; -process.exit = function(status){}; -process.stdout = {}; -global = window; - -/** - * next tick implementation. - */ - -process.nextTick = (function(){ - // postMessage behaves badly on IE8 - if (window.ActiveXObject || !window.postMessage) { - return function(fn){ fn() }; - } - - // based on setZeroTimeout by David Baron - // - http://dbaron.org/log/20100309-faster-timeouts - var timeouts = [] - , name = 'mocha-zero-timeout' - - window.addEventListener('message', function(e){ - if (e.source == window && e.data == name) { - if (e.stopPropagation) e.stopPropagation(); - if (timeouts.length) timeouts.shift()(); - } - }, true); - - return function(fn){ - timeouts.push(fn); - window.postMessage(name, '*'); - } -})(); - -/** - * Remove uncaughtException listener. - */ - -process.removeListener = function(e){ - if ('uncaughtException' == e) { - window.onerror = null; - } -}; - -/** - * Implements uncaughtException listener. - */ - -process.on = function(e, fn){ - if ('uncaughtException' == e) { - window.onerror = function(err, url, line){ - fn(new Error(err + ' (' + url + ':' + line + ')')); - }; - } -}; - -// boot -;(function(){ - - /** - * Expose mocha. - */ - - var Mocha = window.Mocha = require('mocha'), - mocha = window.mocha = new Mocha({ reporter: 'html' }); - - /** - * Override ui to ensure that the ui functions are initialized. - * Normally this would happen in Mocha.prototype.loadFiles. - */ - - mocha.ui = function(ui){ - Mocha.prototype.ui.call(this, ui); - this.suite.emit('pre-require', window, null, this); - return this; - }; - - /** - * Setup mocha with the given setting options. - */ - - mocha.setup = function(opts){ - if ('string' == typeof opts) opts = { ui: opts }; - for (var opt in opts) this[opt](opts[opt]); - return this; - }; - - /** - * Run mocha, returning the Runner. - */ - - mocha.run = function(fn){ - var options = mocha.options; - mocha.globals('location'); - - var query = Mocha.utils.parseQuery(window.location.search || ''); - if (query.grep) mocha.grep(query.grep); - if (query.invert) mocha.invert(); - - return Mocha.prototype.run.call(mocha, function(){ - Mocha.utils.highlightTags('code'); - if (fn) fn(); - }); - }; -})(); -})(); \ No newline at end of file From f3caa77057527dc5339acbdc792f71649cc60638 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 4 Apr 2013 10:48:13 -0700 Subject: [PATCH 14/14] Manage rest of test libs with npm --- package.json | 4 + test/index.html | 8 +- test/index_packaged.html | 8 +- test/lib/chai.js | 3767 ---------------------------------- test/lib/happen.js | 123 -- test/lib/sinon-chai.js | 106 - test/lib/sinon.js | 4153 -------------------------------------- 7 files changed, 12 insertions(+), 8157 deletions(-) delete mode 100644 test/lib/chai.js delete mode 100644 test/lib/happen.js delete mode 100644 test/lib/sinon-chai.js delete mode 100644 test/lib/sinon.js diff --git a/package.json b/package.json index dffb50136..1faa62877 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,10 @@ "uglify-js": "~2.2.5", "mocha": "~1.9", "mocha-phantomjs": "~1.1.1", + "chai": "~1.4", + "sinon": "~1.6", + "sinon-chai": "~2.3.1", + "happen": "~0.1.2", "glob": "~3.1.21", "js-yaml": "~2.0.3", "request": "~2.16.2", diff --git a/test/index.html b/test/index.html index 280b7c00a..f2d4d6bfc 100644 --- a/test/index.html +++ b/test/index.html @@ -9,11 +9,11 @@
    - - - + + + + - diff --git a/test/index_packaged.html b/test/index_packaged.html index 913af83fa..420043c91 100644 --- a/test/index_packaged.html +++ b/test/index_packaged.html @@ -9,11 +9,11 @@
    - - - + + + + - diff --git a/test/lib/chai.js b/test/lib/chai.js deleted file mode 100644 index 9294faaef..000000000 --- a/test/lib/chai.js +++ /dev/null @@ -1,3767 +0,0 @@ -!function (name, context, definition) { - if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { - module.exports = definition(); - } else if (typeof define === 'function' && typeof define.amd === 'object') { - define(function () { - return definition(); - }); - } else { - context[name] = definition(); - } -}('chai', this, function () { - - function require(p) { - var path = require.resolve(p) - , mod = require.modules[path]; - if (!mod) throw new Error('failed to require "' + p + '"'); - if (!mod.exports) { - mod.exports = {}; - mod.call(mod.exports, mod, mod.exports, require.relative(path)); - } - return mod.exports; - } - - require.modules = {}; - - require.resolve = function (path) { - var orig = path - , reg = path + '.js' - , index = path + '/index.js'; - return require.modules[reg] && reg - || require.modules[index] && index - || orig; - }; - - require.register = function (path, fn) { - require.modules[path] = fn; - }; - - require.relative = function (parent) { - return function(p){ - if ('.' != p.charAt(0)) return require(p); - - var path = parent.split('/') - , segs = p.split('/'); - path.pop(); - - for (var i = 0; i < segs.length; i++) { - var seg = segs[i]; - if ('..' == seg) path.pop(); - else if ('.' != seg) path.push(seg); - } - - return require(path.join('/')); - }; - }; - - require.alias = function (from, to) { - var fn = require.modules[from]; - require.modules[to] = fn; - }; - - - require.register("chai.js", function(module, exports, require){ - /*! - * chai - * Copyright(c) 2011-2012 Jake Luer - * MIT Licensed - */ - - var used = [] - , exports = module.exports = {}; - - /*! - * Chai version - */ - - exports.version = '1.4.0'; - - /*! - * Primary `Assertion` prototype - */ - - exports.Assertion = require('./chai/assertion'); - - /*! - * Assertion Error - */ - - exports.AssertionError = require('./chai/browser/error'); - - /*! - * Utils for plugins (not exported) - */ - - var util = require('./chai/utils'); - - /** - * # .use(function) - * - * Provides a way to extend the internals of Chai - * - * @param {Function} - * @returns {this} for chaining - * @api public - */ - - exports.use = function (fn) { - if (!~used.indexOf(fn)) { - fn(this, util); - used.push(fn); - } - - return this; - }; - - /*! - * Core Assertions - */ - - var core = require('./chai/core/assertions'); - exports.use(core); - - /*! - * Expect interface - */ - - var expect = require('./chai/interface/expect'); - exports.use(expect); - - /*! - * Should interface - */ - - var should = require('./chai/interface/should'); - exports.use(should); - - /*! - * Assert interface - */ - - var assert = require('./chai/interface/assert'); - exports.use(assert); - - }); // module: chai.js - - require.register("chai/assertion.js", function(module, exports, require){ - /*! - * chai - * http://chaijs.com - * Copyright(c) 2011-2012 Jake Luer - * MIT Licensed - */ - - /*! - * Module dependencies. - */ - - var AssertionError = require('./browser/error') - , util = require('./utils') - , flag = util.flag; - - /*! - * Module export. - */ - - module.exports = Assertion; - - - /*! - * Assertion Constructor - * - * Creates object for chaining. - * - * @api private - */ - - function Assertion (obj, msg, stack) { - flag(this, 'ssfi', stack || arguments.callee); - flag(this, 'object', obj); - flag(this, 'message', msg); - } - - /*! - * ### Assertion.includeStack - * - * User configurable property, influences whether stack trace - * is included in Assertion error message. Default of false - * suppresses stack trace in the error message - * - * Assertion.includeStack = true; // enable stack on error - * - * @api public - */ - - Assertion.includeStack = false; - - Assertion.addProperty = function (name, fn) { - util.addProperty(this.prototype, name, fn); - }; - - Assertion.addMethod = function (name, fn) { - util.addMethod(this.prototype, name, fn); - }; - - Assertion.addChainableMethod = function (name, fn, chainingBehavior) { - util.addChainableMethod(this.prototype, name, fn, chainingBehavior); - }; - - Assertion.overwriteProperty = function (name, fn) { - util.overwriteProperty(this.prototype, name, fn); - }; - - Assertion.overwriteMethod = function (name, fn) { - util.overwriteMethod(this.prototype, name, fn); - }; - - /*! - * ### .assert(expression, message, negateMessage, expected, actual) - * - * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. - * - * @name assert - * @param {Philosophical} expression to be tested - * @param {String} message to display if fails - * @param {String} negatedMessage to display if negated expression fails - * @param {Mixed} expected value (remember to check for negation) - * @param {Mixed} actual (optional) will default to `this.obj` - * @api private - */ - - Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual) { - var ok = util.test(this, arguments); - - if (!ok) { - var msg = util.getMessage(this, arguments) - , actual = util.getActual(this, arguments); - throw new AssertionError({ - message: msg - , actual: actual - , expected: expected - , stackStartFunction: (Assertion.includeStack) ? this.assert : flag(this, 'ssfi') - }); - } - }; - - /*! - * ### ._obj - * - * Quick reference to stored `actual` value for plugin developers. - * - * @api private - */ - - Object.defineProperty(Assertion.prototype, '_obj', - { get: function () { - return flag(this, 'object'); - } - , set: function (val) { - flag(this, 'object', val); - } - }); - - }); // module: chai/assertion.js - - require.register("chai/browser/error.js", function(module, exports, require){ - /*! - * chai - * Copyright(c) 2011-2012 Jake Luer - * MIT Licensed - */ - - module.exports = AssertionError; - - function AssertionError (options) { - options = options || {}; - this.message = options.message; - this.actual = options.actual; - this.expected = options.expected; - this.operator = options.operator; - - if (options.stackStartFunction && Error.captureStackTrace) { - var stackStartFunction = options.stackStartFunction; - Error.captureStackTrace(this, stackStartFunction); - } - } - - AssertionError.prototype = Object.create(Error.prototype); - AssertionError.prototype.name = 'AssertionError'; - AssertionError.prototype.constructor = AssertionError; - - AssertionError.prototype.toString = function() { - return this.message; - }; - - }); // module: chai/browser/error.js - - require.register("chai/core/assertions.js", function(module, exports, require){ - /*! - * chai - * http://chaijs.com - * Copyright(c) 2011-2012 Jake Luer - * MIT Licensed - */ - - module.exports = function (chai, _) { - var Assertion = chai.Assertion - , toString = Object.prototype.toString - , flag = _.flag; - - /** - * ### Language Chains - * - * The following are provide as chainable getters to - * improve the readability of your assertions. They - * do not provide an testing capability unless they - * have been overwritten by a plugin. - * - * **Chains** - * - * - to - * - be - * - been - * - is - * - that - * - and - * - have - * - with - * - at - * - of - * - * @name language chains - * @api public - */ - - [ 'to', 'be', 'been' - , 'is', 'and', 'have' - , 'with', 'that', 'at' - , 'of' ].forEach(function (chain) { - Assertion.addProperty(chain, function () { - return this; - }); - }); - - /** - * ### .not - * - * Negates any of assertions following in the chain. - * - * expect(foo).to.not.equal('bar'); - * expect(goodFn).to.not.throw(Error); - * expect({ foo: 'baz' }).to.have.property('foo') - * .and.not.equal('bar'); - * - * @name not - * @api public - */ - - Assertion.addProperty('not', function () { - flag(this, 'negate', true); - }); - - /** - * ### .deep - * - * Sets the `deep` flag, later used by the `equal` and - * `property` assertions. - * - * expect(foo).to.deep.equal({ bar: 'baz' }); - * expect({ foo: { bar: { baz: 'quux' } } }) - * .to.have.deep.property('foo.bar.baz', 'quux'); - * - * @name deep - * @api public - */ - - Assertion.addProperty('deep', function () { - flag(this, 'deep', true); - }); - - /** - * ### .a(type) - * - * The `a` and `an` assertions are aliases that can be - * used either as language chains or to assert a value's - * type (as revealed by `Object.prototype.toString`). - * - * // typeof - * expect('test').to.be.a('string'); - * expect({ foo: 'bar' }).to.be.an('object'); - * expect(null).to.be.a('null'); - * expect(undefined).to.be.an('undefined'); - * - * // language chain - * expect(foo).to.be.an.instanceof(Foo); - * - * @name a - * @alias an - * @param {String} type - * @param {String} message _optional_ - * @api public - */ - - function an(type, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , klassStart = type.charAt(0).toUpperCase() - , klass = klassStart + type.slice(1) - , article = ~[ 'A', 'E', 'I', 'O', 'U' ].indexOf(klassStart) ? 'an ' : 'a '; - - this.assert( - '[object ' + klass + ']' === toString.call(obj) - , 'expected #{this} to be ' + article + type - , 'expected #{this} not to be ' + article + type - ); - } - - Assertion.addChainableMethod('an', an); - Assertion.addChainableMethod('a', an); - - /** - * ### .include(value) - * - * The `include` and `contain` assertions can be used as either property - * based language chains or as methods to assert the inclusion of an object - * in an array or a substring in a string. When used as language chains, - * they toggle the `contain` flag for the `keys` assertion. - * - * expect([1,2,3]).to.include(2); - * expect('foobar').to.contain('foo'); - * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); - * - * @name include - * @alias contain - * @param {Object|String|Number} obj - * @param {String} message _optional_ - * @api public - */ - - function includeChainingBehavior () { - flag(this, 'contains', true); - } - - function include (val, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - this.assert( - ~obj.indexOf(val) - , 'expected #{this} to include ' + _.inspect(val) - , 'expected #{this} to not include ' + _.inspect(val)); - } - - Assertion.addChainableMethod('include', include, includeChainingBehavior); - Assertion.addChainableMethod('contain', include, includeChainingBehavior); - - /** - * ### .ok - * - * Asserts that the target is truthy. - * - * expect('everthing').to.be.ok; - * expect(1).to.be.ok; - * expect(false).to.not.be.ok; - * expect(undefined).to.not.be.ok; - * expect(null).to.not.be.ok; - * - * @name ok - * @api public - */ - - Assertion.addProperty('ok', function () { - this.assert( - flag(this, 'object') - , 'expected #{this} to be truthy' - , 'expected #{this} to be falsy'); - }); - - /** - * ### .true - * - * Asserts that the target is `true`. - * - * expect(true).to.be.true; - * expect(1).to.not.be.true; - * - * @name true - * @api public - */ - - Assertion.addProperty('true', function () { - this.assert( - true === flag(this, 'object') - , 'expected #{this} to be true' - , 'expected #{this} to be false' - , this.negate ? false : true - ); - }); - - /** - * ### .false - * - * Asserts that the target is `false`. - * - * expect(false).to.be.false; - * expect(0).to.not.be.false; - * - * @name false - * @api public - */ - - Assertion.addProperty('false', function () { - this.assert( - false === flag(this, 'object') - , 'expected #{this} to be false' - , 'expected #{this} to be true' - , this.negate ? true : false - ); - }); - - /** - * ### .null - * - * Asserts that the target is `null`. - * - * expect(null).to.be.null; - * expect(undefined).not.to.be.null; - * - * @name null - * @api public - */ - - Assertion.addProperty('null', function () { - this.assert( - null === flag(this, 'object') - , 'expected #{this} to be null' - , 'expected #{this} not to be null' - ); - }); - - /** - * ### .undefined - * - * Asserts that the target is `undefined`. - * - * expect(undefined).to.be.undefined; - * expect(null).to.not.be.undefined; - * - * @name undefined - * @api public - */ - - Assertion.addProperty('undefined', function () { - this.assert( - undefined === flag(this, 'object') - , 'expected #{this} to be undefined' - , 'expected #{this} not to be undefined' - ); - }); - - /** - * ### .exist - * - * Asserts that the target is neither `null` nor `undefined`. - * - * var foo = 'hi' - * , bar = null - * , baz; - * - * expect(foo).to.exist; - * expect(bar).to.not.exist; - * expect(baz).to.not.exist; - * - * @name exist - * @api public - */ - - Assertion.addProperty('exist', function () { - this.assert( - null != flag(this, 'object') - , 'expected #{this} to exist' - , 'expected #{this} to not exist' - ); - }); - - - /** - * ### .empty - * - * Asserts that the target's length is `0`. For arrays, it checks - * the `length` property. For objects, it gets the count of - * enumerable keys. - * - * expect([]).to.be.empty; - * expect('').to.be.empty; - * expect({}).to.be.empty; - * - * @name empty - * @api public - */ - - Assertion.addProperty('empty', function () { - var obj = flag(this, 'object') - , expected = obj; - - if (Array.isArray(obj) || 'string' === typeof object) { - expected = obj.length; - } else if (typeof obj === 'object') { - expected = Object.keys(obj).length; - } - - this.assert( - !expected - , 'expected #{this} to be empty' - , 'expected #{this} not to be empty' - ); - }); - - /** - * ### .arguments - * - * Asserts that the target is an arguments object. - * - * function test () { - * expect(arguments).to.be.arguments; - * } - * - * @name arguments - * @alias Arguments - * @api public - */ - - function checkArguments () { - var obj = flag(this, 'object') - , type = Object.prototype.toString.call(obj); - this.assert( - '[object Arguments]' === type - , 'expected #{this} to be arguments but got ' + type - , 'expected #{this} to not be arguments' - ); - } - - Assertion.addProperty('arguments', checkArguments); - Assertion.addProperty('Arguments', checkArguments); - - /** - * ### .equal(value) - * - * Asserts that the target is strictly equal (`===`) to `value`. - * Alternately, if the `deep` flag is set, asserts that - * the target is deeply equal to `value`. - * - * expect('hello').to.equal('hello'); - * expect(42).to.equal(42); - * expect(1).to.not.equal(true); - * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); - * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); - * - * @name equal - * @alias equals - * @alias eq - * @alias deep.equal - * @param {Mixed} value - * @param {String} message _optional_ - * @api public - */ - - function assertEqual (val, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'deep')) { - return this.eql(val); - } else { - this.assert( - val === obj - , 'expected #{this} to equal #{exp}' - , 'expected #{this} to not equal #{exp}' - , val - ); - } - } - - Assertion.addMethod('equal', assertEqual); - Assertion.addMethod('equals', assertEqual); - Assertion.addMethod('eq', assertEqual); - - /** - * ### .eql(value) - * - * Asserts that the target is deeply equal to `value`. - * - * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); - * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); - * - * @name eql - * @param {Mixed} value - * @param {String} message _optional_ - * @api public - */ - - Assertion.addMethod('eql', function (obj, msg) { - if (msg) flag(this, 'message', msg); - this.assert( - _.eql(obj, flag(this, 'object')) - , 'expected #{this} to deeply equal #{exp}' - , 'expected #{this} to not deeply equal #{exp}' - , obj - ); - }); - - /** - * ### .above(value) - * - * Asserts that the target is greater than `value`. - * - * expect(10).to.be.above(5); - * - * Can also be used in conjunction with `length` to - * assert a minimum length. The benefit being a - * more informative error message than if the length - * was supplied directly. - * - * expect('foo').to.have.length.above(2); - * expect([ 1, 2, 3 ]).to.have.length.above(2); - * - * @name above - * @alias gt - * @alias greaterThan - * @param {Number} value - * @param {String} message _optional_ - * @api public - */ - - function assertAbove (n, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; - this.assert( - len > n - , 'expected #{this} to have a length above #{exp} but got #{act}' - , 'expected #{this} to not have a length above #{exp}' - , n - , len - ); - } else { - this.assert( - obj > n - , 'expected #{this} to be above ' + n - , 'expected #{this} to be at most ' + n - ); - } - } - - Assertion.addMethod('above', assertAbove); - Assertion.addMethod('gt', assertAbove); - Assertion.addMethod('greaterThan', assertAbove); - - /** - * ### .least(value) - * - * Asserts that the target is greater than or equal to `value`. - * - * expect(10).to.be.at.least(10); - * - * Can also be used in conjunction with `length` to - * assert a minimum length. The benefit being a - * more informative error message than if the length - * was supplied directly. - * - * expect('foo').to.have.length.of.at.least(2); - * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); - * - * @name least - * @alias gte - * @param {Number} value - * @param {String} message _optional_ - * @api public - */ - - function assertLeast (n, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; - this.assert( - len >= n - , 'expected #{this} to have a length at least #{exp} but got #{act}' - , 'expected #{this} to not have a length below #{exp}' - , n - , len - ); - } else { - this.assert( - obj >= n - , 'expected #{this} to be at least ' + n - , 'expected #{this} to be below ' + n - ); - } - } - - Assertion.addMethod('least', assertLeast); - Assertion.addMethod('gte', assertLeast); - - /** - * ### .below(value) - * - * Asserts that the target is less than `value`. - * - * expect(5).to.be.below(10); - * - * Can also be used in conjunction with `length` to - * assert a maximum length. The benefit being a - * more informative error message than if the length - * was supplied directly. - * - * expect('foo').to.have.length.below(4); - * expect([ 1, 2, 3 ]).to.have.length.below(4); - * - * @name below - * @alias lt - * @alias lessThan - * @param {Number} value - * @param {String} message _optional_ - * @api public - */ - - function assertBelow (n, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; - this.assert( - len < n - , 'expected #{this} to have a length below #{exp} but got #{act}' - , 'expected #{this} to not have a length below #{exp}' - , n - , len - ); - } else { - this.assert( - obj < n - , 'expected #{this} to be below ' + n - , 'expected #{this} to be at least ' + n - ); - } - } - - Assertion.addMethod('below', assertBelow); - Assertion.addMethod('lt', assertBelow); - Assertion.addMethod('lessThan', assertBelow); - - /** - * ### .most(value) - * - * Asserts that the target is less than or equal to `value`. - * - * expect(5).to.be.at.most(5); - * - * Can also be used in conjunction with `length` to - * assert a maximum length. The benefit being a - * more informative error message than if the length - * was supplied directly. - * - * expect('foo').to.have.length.of.at.most(4); - * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); - * - * @name most - * @alias lte - * @param {Number} value - * @param {String} message _optional_ - * @api public - */ - - function assertMost (n, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; - this.assert( - len <= n - , 'expected #{this} to have a length at most #{exp} but got #{act}' - , 'expected #{this} to not have a length above #{exp}' - , n - , len - ); - } else { - this.assert( - obj <= n - , 'expected #{this} to be at most ' + n - , 'expected #{this} to be above ' + n - ); - } - } - - Assertion.addMethod('most', assertMost); - Assertion.addMethod('lte', assertMost); - - /** - * ### .within(start, finish) - * - * Asserts that the target is within a range. - * - * expect(7).to.be.within(5,10); - * - * Can also be used in conjunction with `length` to - * assert a length range. The benefit being a - * more informative error message than if the length - * was supplied directly. - * - * expect('foo').to.have.length.within(2,4); - * expect([ 1, 2, 3 ]).to.have.length.within(2,4); - * - * @name within - * @param {Number} start lowerbound inclusive - * @param {Number} finish upperbound inclusive - * @param {String} message _optional_ - * @api public - */ - - Assertion.addMethod('within', function (start, finish, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , range = start + '..' + finish; - if (flag(this, 'doLength')) { - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; - this.assert( - len >= start && len <= finish - , 'expected #{this} to have a length within ' + range - , 'expected #{this} to not have a length within ' + range - ); - } else { - this.assert( - obj >= start && obj <= finish - , 'expected #{this} to be within ' + range - , 'expected #{this} to not be within ' + range - ); - } - }); - - /** - * ### .instanceof(constructor) - * - * Asserts that the target is an instance of `constructor`. - * - * var Tea = function (name) { this.name = name; } - * , Chai = new Tea('chai'); - * - * expect(Chai).to.be.an.instanceof(Tea); - * expect([ 1, 2, 3 ]).to.be.instanceof(Array); - * - * @name instanceof - * @param {Constructor} constructor - * @param {String} message _optional_ - * @alias instanceOf - * @api public - */ - - function assertInstanceOf (constructor, msg) { - if (msg) flag(this, 'message', msg); - var name = _.getName(constructor); - this.assert( - flag(this, 'object') instanceof constructor - , 'expected #{this} to be an instance of ' + name - , 'expected #{this} to not be an instance of ' + name - ); - }; - - Assertion.addMethod('instanceof', assertInstanceOf); - Assertion.addMethod('instanceOf', assertInstanceOf); - - /** - * ### .property(name, [value]) - * - * Asserts that the target has a property `name`, optionally asserting that - * the value of that property is strictly equal to `value`. - * If the `deep` flag is set, you can use dot- and bracket-notation for deep - * references into objects and arrays. - * - * // simple referencing - * var obj = { foo: 'bar' }; - * expect(obj).to.have.property('foo'); - * expect(obj).to.have.property('foo', 'bar'); - * - * // deep referencing - * var deepObj = { - * green: { tea: 'matcha' } - * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] - * }; - - * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); - * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); - * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); - * - * You can also use an array as the starting point of a `deep.property` - * assertion, or traverse nested arrays. - * - * var arr = [ - * [ 'chai', 'matcha', 'konacha' ] - * , [ { tea: 'chai' } - * , { tea: 'matcha' } - * , { tea: 'konacha' } ] - * ]; - * - * expect(arr).to.have.deep.property('[0][1]', 'matcha'); - * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); - * - * Furthermore, `property` changes the subject of the assertion - * to be the value of that property from the original object. This - * permits for further chainable assertions on that property. - * - * expect(obj).to.have.property('foo') - * .that.is.a('string'); - * expect(deepObj).to.have.property('green') - * .that.is.an('object') - * .that.deep.equals({ tea: 'matcha' }); - * expect(deepObj).to.have.property('teas') - * .that.is.an('array') - * .with.deep.property('[2]') - * .that.deep.equals({ tea: 'konacha' }); - * - * @name property - * @alias deep.property - * @param {String} name - * @param {Mixed} value (optional) - * @param {String} message _optional_ - * @returns value of property for chaining - * @api public - */ - - Assertion.addMethod('property', function (name, val, msg) { - if (msg) flag(this, 'message', msg); - - var descriptor = flag(this, 'deep') ? 'deep property ' : 'property ' - , negate = flag(this, 'negate') - , obj = flag(this, 'object') - , value = flag(this, 'deep') - ? _.getPathValue(name, obj) - : obj[name]; - - if (negate && undefined !== val) { - if (undefined === value) { - msg = (msg != null) ? msg + ': ' : ''; - throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); - } - } else { - this.assert( - undefined !== value - , 'expected #{this} to have a ' + descriptor + _.inspect(name) - , 'expected #{this} to not have ' + descriptor + _.inspect(name)); - } - - if (undefined !== val) { - this.assert( - val === value - , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' - , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' - , val - , value - ); - } - - flag(this, 'object', value); - }); - - - /** - * ### .ownProperty(name) - * - * Asserts that the target has an own property `name`. - * - * expect('test').to.have.ownProperty('length'); - * - * @name ownProperty - * @alias haveOwnProperty - * @param {String} name - * @param {String} message _optional_ - * @api public - */ - - function assertOwnProperty (name, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - this.assert( - obj.hasOwnProperty(name) - , 'expected #{this} to have own property ' + _.inspect(name) - , 'expected #{this} to not have own property ' + _.inspect(name) - ); - } - - Assertion.addMethod('ownProperty', assertOwnProperty); - Assertion.addMethod('haveOwnProperty', assertOwnProperty); - - /** - * ### .length(value) - * - * Asserts that the target's `length` property has - * the expected value. - * - * expect([ 1, 2, 3]).to.have.length(3); - * expect('foobar').to.have.length(6); - * - * Can also be used as a chain precursor to a value - * comparison for the length property. - * - * expect('foo').to.have.length.above(2); - * expect([ 1, 2, 3 ]).to.have.length.above(2); - * expect('foo').to.have.length.below(4); - * expect([ 1, 2, 3 ]).to.have.length.below(4); - * expect('foo').to.have.length.within(2,4); - * expect([ 1, 2, 3 ]).to.have.length.within(2,4); - * - * @name length - * @alias lengthOf - * @param {Number} length - * @param {String} message _optional_ - * @api public - */ - - function assertLengthChain () { - flag(this, 'doLength', true); - } - - function assertLength (n, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; - - this.assert( - len == n - , 'expected #{this} to have a length of #{exp} but got #{act}' - , 'expected #{this} to not have a length of #{act}' - , n - , len - ); - } - - Assertion.addChainableMethod('length', assertLength, assertLengthChain); - Assertion.addMethod('lengthOf', assertLength, assertLengthChain); - - /** - * ### .match(regexp) - * - * Asserts that the target matches a regular expression. - * - * expect('foobar').to.match(/^foo/); - * - * @name match - * @param {RegExp} RegularExpression - * @param {String} message _optional_ - * @api public - */ - - Assertion.addMethod('match', function (re, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - this.assert( - re.exec(obj) - , 'expected #{this} to match ' + re - , 'expected #{this} not to match ' + re - ); - }); - - /** - * ### .string(string) - * - * Asserts that the string target contains another string. - * - * expect('foobar').to.have.string('bar'); - * - * @name string - * @param {String} string - * @param {String} message _optional_ - * @api public - */ - - Assertion.addMethod('string', function (str, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - new Assertion(obj, msg).is.a('string'); - - this.assert( - ~obj.indexOf(str) - , 'expected #{this} to contain ' + _.inspect(str) - , 'expected #{this} to not contain ' + _.inspect(str) - ); - }); - - - /** - * ### .keys(key1, [key2], [...]) - * - * Asserts that the target has exactly the given keys, or - * asserts the inclusion of some keys when using the - * `include` or `contain` modifiers. - * - * expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']); - * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar'); - * - * @name keys - * @alias key - * @param {String...|Array} keys - * @api public - */ - - function assertKeys (keys) { - var obj = flag(this, 'object') - , str - , ok = true; - - keys = keys instanceof Array - ? keys - : Array.prototype.slice.call(arguments); - - if (!keys.length) throw new Error('keys required'); - - var actual = Object.keys(obj) - , len = keys.length; - - // Inclusion - ok = keys.every(function(key){ - return ~actual.indexOf(key); - }); - - // Strict - if (!flag(this, 'negate') && !flag(this, 'contains')) { - ok = ok && keys.length == actual.length; - } - - // Key string - if (len > 1) { - keys = keys.map(function(key){ - return _.inspect(key); - }); - var last = keys.pop(); - str = keys.join(', ') + ', and ' + last; - } else { - str = _.inspect(keys[0]); - } - - // Form - str = (len > 1 ? 'keys ' : 'key ') + str; - - // Have / include - str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; - - // Assertion - this.assert( - ok - , 'expected #{this} to ' + str - , 'expected #{this} to not ' + str - ); - } - - Assertion.addMethod('keys', assertKeys); - Assertion.addMethod('key', assertKeys); - - /** - * ### .throw(constructor) - * - * Asserts that the function target will throw a specific error, or specific type of error - * (as determined using `instanceof`), optionally with a RegExp or string inclusion test - * for the error's message. - * - * var err = new ReferenceError('This is a bad function.'); - * var fn = function () { throw err; } - * expect(fn).to.throw(ReferenceError); - * expect(fn).to.throw(Error); - * expect(fn).to.throw(/bad function/); - * expect(fn).to.not.throw('good function'); - * expect(fn).to.throw(ReferenceError, /bad function/); - * expect(fn).to.throw(err); - * expect(fn).to.not.throw(new RangeError('Out of range.')); - * - * Please note that when a throw expectation is negated, it will check each - * parameter independently, starting with error constructor type. The appropriate way - * to check for the existence of a type of error but for a message that does not match - * is to use `and`. - * - * expect(fn).to.throw(ReferenceError) - * .and.not.throw(/good function/); - * - * @name throw - * @alias throws - * @alias Throw - * @param {ErrorConstructor} constructor - * @param {String|RegExp} expected error message - * @param {String} message _optional_ - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types - * @api public - */ - - function assertThrows (constructor, errMsg, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - new Assertion(obj, msg).is.a('function'); - - var thrown = false - , desiredError = null - , name = null - , thrownError = null; - - if (arguments.length === 0) { - errMsg = null; - constructor = null; - } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { - errMsg = constructor; - constructor = null; - } else if (constructor && constructor instanceof Error) { - desiredError = constructor; - constructor = null; - errMsg = null; - } else if (typeof constructor === 'function') { - name = (new constructor()).name; - } else { - constructor = null; - } - - try { - obj(); - } catch (err) { - // first, check desired error - if (desiredError) { - this.assert( - err === desiredError - , 'expected #{this} to throw ' + _.inspect(desiredError) + ' but ' + _.inspect(err) + ' was thrown' - , 'expected #{this} to not throw ' + _.inspect(desiredError) - ); - return this; - } - // next, check constructor - if (constructor) { - this.assert( - err instanceof constructor - , 'expected #{this} to throw ' + name + ' but ' + _.inspect(err) + ' was thrown' - , 'expected #{this} to not throw ' + name + ' but ' + _.inspect(err) + ' was thrown'); - if (!errMsg) return this; - } - // next, check message - if (err.message && errMsg && errMsg instanceof RegExp) { - this.assert( - errMsg.exec(err.message) - , 'expected #{this} to throw error matching ' + errMsg + ' but got ' + _.inspect(err.message) - , 'expected #{this} to throw error not matching ' + errMsg - ); - return this; - } else if (err.message && errMsg && 'string' === typeof errMsg) { - this.assert( - ~err.message.indexOf(errMsg) - , 'expected #{this} to throw error including #{exp} but got #{act}' - , 'expected #{this} to throw error not including #{act}' - , errMsg - , err.message - ); - return this; - } else { - thrown = true; - thrownError = err; - } - } - - var expectedThrown = name ? name : desiredError ? _.inspect(desiredError) : 'an error'; - var actuallyGot = '' - if (thrown) { - actuallyGot = ' but ' + _.inspect(thrownError) + ' was thrown' - } - - this.assert( - thrown === true - , 'expected #{this} to throw ' + expectedThrown + actuallyGot - , 'expected #{this} to not throw ' + expectedThrown + actuallyGot - ); - }; - - Assertion.addMethod('throw', assertThrows); - Assertion.addMethod('throws', assertThrows); - Assertion.addMethod('Throw', assertThrows); - - /** - * ### .respondTo(method) - * - * Asserts that the object or class target will respond to a method. - * - * Klass.prototype.bar = function(){}; - * expect(Klass).to.respondTo('bar'); - * expect(obj).to.respondTo('bar'); - * - * To check if a constructor will respond to a static function, - * set the `itself` flag. - * - * Klass.baz = function(){}; - * expect(Klass).itself.to.respondTo('baz'); - * - * @name respondTo - * @param {String} method - * @param {String} message _optional_ - * @api public - */ - - Assertion.addMethod('respondTo', function (method, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , itself = flag(this, 'itself') - , context = ('function' === typeof obj && !itself) - ? obj.prototype[method] - : obj[method]; - - this.assert( - 'function' === typeof context - , 'expected #{this} to respond to ' + _.inspect(method) - , 'expected #{this} to not respond to ' + _.inspect(method) - ); - }); - - /** - * ### .itself - * - * Sets the `itself` flag, later used by the `respondTo` assertion. - * - * function Foo() {} - * Foo.bar = function() {} - * Foo.prototype.baz = function() {} - * - * expect(Foo).itself.to.respondTo('bar'); - * expect(Foo).itself.not.to.respondTo('baz'); - * - * @name itself - * @api public - */ - - Assertion.addProperty('itself', function () { - flag(this, 'itself', true); - }); - - /** - * ### .satisfy(method) - * - * Asserts that the target passes a given truth test. - * - * expect(1).to.satisfy(function(num) { return num > 0; }); - * - * @name satisfy - * @param {Function} matcher - * @param {String} message _optional_ - * @api public - */ - - Assertion.addMethod('satisfy', function (matcher, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - this.assert( - matcher(obj) - , 'expected #{this} to satisfy ' + _.inspect(matcher) - , 'expected #{this} to not satisfy' + _.inspect(matcher) - , this.negate ? false : true - , matcher(obj) - ); - }); - - /** - * ### .closeTo(expected, delta) - * - * Asserts that the target is equal `expected`, to within a +/- `delta` range. - * - * expect(1.5).to.be.closeTo(1, 0.5); - * - * @name closeTo - * @param {Number} expected - * @param {Number} delta - * @param {String} message _optional_ - * @api public - */ - - Assertion.addMethod('closeTo', function (expected, delta, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - this.assert( - Math.abs(obj - expected) <= delta - , 'expected #{this} to be close to ' + expected + ' +/- ' + delta - , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta - ); - }); - - }; - - }); // module: chai/core/assertions.js - - require.register("chai/interface/assert.js", function(module, exports, require){ - /*! - * chai - * Copyright(c) 2011-2012 Jake Luer - * MIT Licensed - */ - - - module.exports = function (chai, util) { - - /*! - * Chai dependencies. - */ - - var Assertion = chai.Assertion - , flag = util.flag; - - /*! - * Module export. - */ - - /** - * ### assert(expression, message) - * - * Write your own test expressions. - * - * assert('foo' !== 'bar', 'foo is not bar'); - * assert(Array.isArray([]), 'empty arrays are arrays'); - * - * @param {Mixed} expression to test for truthiness - * @param {String} message to display on error - * @name assert - * @api public - */ - - var assert = chai.assert = function (express, errmsg) { - var test = new Assertion(null); - test.assert( - express - , errmsg - , '[ negation message unavailable ]' - ); - }; - - /** - * ### .fail(actual, expected, [message], [operator]) - * - * Throw a failure. Node.js `assert` module-compatible. - * - * @name fail - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @param {String} operator - * @api public - */ - - assert.fail = function (actual, expected, message, operator) { - throw new chai.AssertionError({ - actual: actual - , expected: expected - , message: message - , operator: operator - , stackStartFunction: assert.fail - }); - }; - - /** - * ### .ok(object, [message]) - * - * Asserts that `object` is truthy. - * - * assert.ok('everything', 'everything is ok'); - * assert.ok(false, 'this will fail'); - * - * @name ok - * @param {Mixed} object to test - * @param {String} message - * @api public - */ - - assert.ok = function (val, msg) { - new Assertion(val, msg).is.ok; - }; - - /** - * ### .equal(actual, expected, [message]) - * - * Asserts non-strict equality (`==`) of `actual` and `expected`. - * - * assert.equal(3, '3', '== coerces values to strings'); - * - * @name equal - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @api public - */ - - assert.equal = function (act, exp, msg) { - var test = new Assertion(act, msg); - - test.assert( - exp == flag(test, 'object') - , 'expected #{this} to equal #{exp}' - , 'expected #{this} to not equal #{act}' - , exp - , act - ); - }; - - /** - * ### .notEqual(actual, expected, [message]) - * - * Asserts non-strict inequality (`!=`) of `actual` and `expected`. - * - * assert.notEqual(3, 4, 'these numbers are not equal'); - * - * @name notEqual - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @api public - */ - - assert.notEqual = function (act, exp, msg) { - var test = new Assertion(act, msg); - - test.assert( - exp != flag(test, 'object') - , 'expected #{this} to not equal #{exp}' - , 'expected #{this} to equal #{act}' - , exp - , act - ); - }; - - /** - * ### .strictEqual(actual, expected, [message]) - * - * Asserts strict equality (`===`) of `actual` and `expected`. - * - * assert.strictEqual(true, true, 'these booleans are strictly equal'); - * - * @name strictEqual - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @api public - */ - - assert.strictEqual = function (act, exp, msg) { - new Assertion(act, msg).to.equal(exp); - }; - - /** - * ### .notStrictEqual(actual, expected, [message]) - * - * Asserts strict inequality (`!==`) of `actual` and `expected`. - * - * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); - * - * @name notStrictEqual - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @api public - */ - - assert.notStrictEqual = function (act, exp, msg) { - new Assertion(act, msg).to.not.equal(exp); - }; - - /** - * ### .deepEqual(actual, expected, [message]) - * - * Asserts that `actual` is deeply equal to `expected`. - * - * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); - * - * @name deepEqual - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @api public - */ - - assert.deepEqual = function (act, exp, msg) { - new Assertion(act, msg).to.eql(exp); - }; - - /** - * ### .notDeepEqual(actual, expected, [message]) - * - * Assert that `actual` is not deeply equal to `expected`. - * - * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); - * - * @name notDeepEqual - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @api public - */ - - assert.notDeepEqual = function (act, exp, msg) { - new Assertion(act, msg).to.not.eql(exp); - }; - - /** - * ### .isTrue(value, [message]) - * - * Asserts that `value` is true. - * - * var teaServed = true; - * assert.isTrue(teaServed, 'the tea has been served'); - * - * @name isTrue - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isTrue = function (val, msg) { - new Assertion(val, msg).is['true']; - }; - - /** - * ### .isFalse(value, [message]) - * - * Asserts that `value` is false. - * - * var teaServed = false; - * assert.isFalse(teaServed, 'no tea yet? hmm...'); - * - * @name isFalse - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isFalse = function (val, msg) { - new Assertion(val, msg).is['false']; - }; - - /** - * ### .isNull(value, [message]) - * - * Asserts that `value` is null. - * - * assert.isNull(err, 'there was no error'); - * - * @name isNull - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isNull = function (val, msg) { - new Assertion(val, msg).to.equal(null); - }; - - /** - * ### .isNotNull(value, [message]) - * - * Asserts that `value` is not null. - * - * var tea = 'tasty chai'; - * assert.isNotNull(tea, 'great, time for tea!'); - * - * @name isNotNull - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isNotNull = function (val, msg) { - new Assertion(val, msg).to.not.equal(null); - }; - - /** - * ### .isUndefined(value, [message]) - * - * Asserts that `value` is `undefined`. - * - * var tea; - * assert.isUndefined(tea, 'no tea defined'); - * - * @name isUndefined - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isUndefined = function (val, msg) { - new Assertion(val, msg).to.equal(undefined); - }; - - /** - * ### .isDefined(value, [message]) - * - * Asserts that `value` is not `undefined`. - * - * var tea = 'cup of chai'; - * assert.isDefined(tea, 'tea has been defined'); - * - * @name isUndefined - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isDefined = function (val, msg) { - new Assertion(val, msg).to.not.equal(undefined); - }; - - /** - * ### .isFunction(value, [message]) - * - * Asserts that `value` is a function. - * - * function serveTea() { return 'cup of tea'; }; - * assert.isFunction(serveTea, 'great, we can have tea now'); - * - * @name isFunction - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isFunction = function (val, msg) { - new Assertion(val, msg).to.be.a('function'); - }; - - /** - * ### .isNotFunction(value, [message]) - * - * Asserts that `value` is _not_ a function. - * - * var serveTea = [ 'heat', 'pour', 'sip' ]; - * assert.isNotFunction(serveTea, 'great, we have listed the steps'); - * - * @name isNotFunction - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isNotFunction = function (val, msg) { - new Assertion(val, msg).to.not.be.a('function'); - }; - - /** - * ### .isObject(value, [message]) - * - * Asserts that `value` is an object (as revealed by - * `Object.prototype.toString`). - * - * var selection = { name: 'Chai', serve: 'with spices' }; - * assert.isObject(selection, 'tea selection is an object'); - * - * @name isObject - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isObject = function (val, msg) { - new Assertion(val, msg).to.be.a('object'); - }; - - /** - * ### .isNotObject(value, [message]) - * - * Asserts that `value` is _not_ an object. - * - * var selection = 'chai' - * assert.isObject(selection, 'tea selection is not an object'); - * assert.isObject(null, 'null is not an object'); - * - * @name isNotObject - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isNotObject = function (val, msg) { - new Assertion(val, msg).to.not.be.a('object'); - }; - - /** - * ### .isArray(value, [message]) - * - * Asserts that `value` is an array. - * - * var menu = [ 'green', 'chai', 'oolong' ]; - * assert.isArray(menu, 'what kind of tea do we want?'); - * - * @name isArray - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isArray = function (val, msg) { - new Assertion(val, msg).to.be.an('array'); - }; - - /** - * ### .isNotArray(value, [message]) - * - * Asserts that `value` is _not_ an array. - * - * var menu = 'green|chai|oolong'; - * assert.isNotArray(menu, 'what kind of tea do we want?'); - * - * @name isNotArray - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isNotArray = function (val, msg) { - new Assertion(val, msg).to.not.be.an('array'); - }; - - /** - * ### .isString(value, [message]) - * - * Asserts that `value` is a string. - * - * var teaOrder = 'chai'; - * assert.isString(teaOrder, 'order placed'); - * - * @name isString - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isString = function (val, msg) { - new Assertion(val, msg).to.be.a('string'); - }; - - /** - * ### .isNotString(value, [message]) - * - * Asserts that `value` is _not_ a string. - * - * var teaOrder = 4; - * assert.isNotString(teaOrder, 'order placed'); - * - * @name isNotString - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isNotString = function (val, msg) { - new Assertion(val, msg).to.not.be.a('string'); - }; - - /** - * ### .isNumber(value, [message]) - * - * Asserts that `value` is a number. - * - * var cups = 2; - * assert.isNumber(cups, 'how many cups'); - * - * @name isNumber - * @param {Number} value - * @param {String} message - * @api public - */ - - assert.isNumber = function (val, msg) { - new Assertion(val, msg).to.be.a('number'); - }; - - /** - * ### .isNotNumber(value, [message]) - * - * Asserts that `value` is _not_ a number. - * - * var cups = '2 cups please'; - * assert.isNotNumber(cups, 'how many cups'); - * - * @name isNotNumber - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isNotNumber = function (val, msg) { - new Assertion(val, msg).to.not.be.a('number'); - }; - - /** - * ### .isBoolean(value, [message]) - * - * Asserts that `value` is a boolean. - * - * var teaReady = true - * , teaServed = false; - * - * assert.isBoolean(teaReady, 'is the tea ready'); - * assert.isBoolean(teaServed, 'has tea been served'); - * - * @name isBoolean - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isBoolean = function (val, msg) { - new Assertion(val, msg).to.be.a('boolean'); - }; - - /** - * ### .isNotBoolean(value, [message]) - * - * Asserts that `value` is _not_ a boolean. - * - * var teaReady = 'yep' - * , teaServed = 'nope'; - * - * assert.isNotBoolean(teaReady, 'is the tea ready'); - * assert.isNotBoolean(teaServed, 'has tea been served'); - * - * @name isNotBoolean - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.isNotBoolean = function (val, msg) { - new Assertion(val, msg).to.not.be.a('boolean'); - }; - - /** - * ### .typeOf(value, name, [message]) - * - * Asserts that `value`'s type is `name`, as determined by - * `Object.prototype.toString`. - * - * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); - * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); - * assert.typeOf('tea', 'string', 'we have a string'); - * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); - * assert.typeOf(null, 'null', 'we have a null'); - * assert.typeOf(undefined, 'undefined', 'we have an undefined'); - * - * @name typeOf - * @param {Mixed} value - * @param {String} name - * @param {String} message - * @api public - */ - - assert.typeOf = function (val, type, msg) { - new Assertion(val, msg).to.be.a(type); - }; - - /** - * ### .notTypeOf(value, name, [message]) - * - * Asserts that `value`'s type is _not_ `name`, as determined by - * `Object.prototype.toString`. - * - * assert.notTypeOf('tea', 'number', 'strings are not numbers'); - * - * @name notTypeOf - * @param {Mixed} value - * @param {String} typeof name - * @param {String} message - * @api public - */ - - assert.notTypeOf = function (val, type, msg) { - new Assertion(val, msg).to.not.be.a(type); - }; - - /** - * ### .instanceOf(object, constructor, [message]) - * - * Asserts that `value` is an instance of `constructor`. - * - * var Tea = function (name) { this.name = name; } - * , chai = new Tea('chai'); - * - * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); - * - * @name instanceOf - * @param {Object} object - * @param {Constructor} constructor - * @param {String} message - * @api public - */ - - assert.instanceOf = function (val, type, msg) { - new Assertion(val, msg).to.be.instanceOf(type); - }; - - /** - * ### .notInstanceOf(object, constructor, [message]) - * - * Asserts `value` is not an instance of `constructor`. - * - * var Tea = function (name) { this.name = name; } - * , chai = new String('chai'); - * - * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); - * - * @name notInstanceOf - * @param {Object} object - * @param {Constructor} constructor - * @param {String} message - * @api public - */ - - assert.notInstanceOf = function (val, type, msg) { - new Assertion(val, msg).to.not.be.instanceOf(type); - }; - - /** - * ### .include(haystack, needle, [message]) - * - * Asserts that `haystack` includes `needle`. Works - * for strings and arrays. - * - * assert.include('foobar', 'bar', 'foobar contains string "bar"'); - * assert.include([ 1, 2, 3 ], 3, 'array contains value'); - * - * @name include - * @param {Array|String} haystack - * @param {Mixed} needle - * @param {String} message - * @api public - */ - - assert.include = function (exp, inc, msg) { - var obj = new Assertion(exp, msg); - - if (Array.isArray(exp)) { - obj.to.include(inc); - } else if ('string' === typeof exp) { - obj.to.contain.string(inc); - } - }; - - /** - * ### .match(value, regexp, [message]) - * - * Asserts that `value` matches the regular expression `regexp`. - * - * assert.match('foobar', /^foo/, 'regexp matches'); - * - * @name match - * @param {Mixed} value - * @param {RegExp} regexp - * @param {String} message - * @api public - */ - - assert.match = function (exp, re, msg) { - new Assertion(exp, msg).to.match(re); - }; - - /** - * ### .notMatch(value, regexp, [message]) - * - * Asserts that `value` does not match the regular expression `regexp`. - * - * assert.notMatch('foobar', /^foo/, 'regexp does not match'); - * - * @name notMatch - * @param {Mixed} value - * @param {RegExp} regexp - * @param {String} message - * @api public - */ - - assert.notMatch = function (exp, re, msg) { - new Assertion(exp, msg).to.not.match(re); - }; - - /** - * ### .property(object, property, [message]) - * - * Asserts that `object` has a property named by `property`. - * - * assert.property({ tea: { green: 'matcha' }}, 'tea'); - * - * @name property - * @param {Object} object - * @param {String} property - * @param {String} message - * @api public - */ - - assert.property = function (obj, prop, msg) { - new Assertion(obj, msg).to.have.property(prop); - }; - - /** - * ### .notProperty(object, property, [message]) - * - * Asserts that `object` does _not_ have a property named by `property`. - * - * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); - * - * @name notProperty - * @param {Object} object - * @param {String} property - * @param {String} message - * @api public - */ - - assert.notProperty = function (obj, prop, msg) { - new Assertion(obj, msg).to.not.have.property(prop); - }; - - /** - * ### .deepProperty(object, property, [message]) - * - * Asserts that `object` has a property named by `property`, which can be a - * string using dot- and bracket-notation for deep reference. - * - * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); - * - * @name deepProperty - * @param {Object} object - * @param {String} property - * @param {String} message - * @api public - */ - - assert.deepProperty = function (obj, prop, msg) { - new Assertion(obj, msg).to.have.deep.property(prop); - }; - - /** - * ### .notDeepProperty(object, property, [message]) - * - * Asserts that `object` does _not_ have a property named by `property`, which - * can be a string using dot- and bracket-notation for deep reference. - * - * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); - * - * @name notDeepProperty - * @param {Object} object - * @param {String} property - * @param {String} message - * @api public - */ - - assert.notDeepProperty = function (obj, prop, msg) { - new Assertion(obj, msg).to.not.have.deep.property(prop); - }; - - /** - * ### .propertyVal(object, property, value, [message]) - * - * Asserts that `object` has a property named by `property` with value given - * by `value`. - * - * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); - * - * @name propertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.propertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg).to.have.property(prop, val); - }; - - /** - * ### .propertyNotVal(object, property, value, [message]) - * - * Asserts that `object` has a property named by `property`, but with a value - * different from that given by `value`. - * - * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); - * - * @name propertyNotVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.propertyNotVal = function (obj, prop, val, msg) { - new Assertion(obj, msg).to.not.have.property(prop, val); - }; - - /** - * ### .deepPropertyVal(object, property, value, [message]) - * - * Asserts that `object` has a property named by `property` with value given - * by `value`. `property` can use dot- and bracket-notation for deep - * reference. - * - * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); - * - * @name deepPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.deepPropertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg).to.have.deep.property(prop, val); - }; - - /** - * ### .deepPropertyNotVal(object, property, value, [message]) - * - * Asserts that `object` has a property named by `property`, but with a value - * different from that given by `value`. `property` can use dot- and - * bracket-notation for deep reference. - * - * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); - * - * @name deepPropertyNotVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.deepPropertyNotVal = function (obj, prop, val, msg) { - new Assertion(obj, msg).to.not.have.deep.property(prop, val); - }; - - /** - * ### .lengthOf(object, length, [message]) - * - * Asserts that `object` has a `length` property with the expected value. - * - * assert.lengthOf([1,2,3], 3, 'array has length of 3'); - * assert.lengthOf('foobar', 5, 'string has length of 6'); - * - * @name lengthOf - * @param {Mixed} object - * @param {Number} length - * @param {String} message - * @api public - */ - - assert.lengthOf = function (exp, len, msg) { - new Assertion(exp, msg).to.have.length(len); - }; - - /** - * ### .throws(function, [constructor/regexp], [message]) - * - * Asserts that `function` will throw an error that is an instance of - * `constructor`, or alternately that it will throw an error with message - * matching `regexp`. - * - * assert.throw(fn, ReferenceError, 'function throws a reference error'); - * - * @name throws - * @alias throw - * @alias Throw - * @param {Function} function - * @param {ErrorConstructor} constructor - * @param {RegExp} regexp - * @param {String} message - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types - * @api public - */ - - assert.Throw = function (fn, type, msg) { - if ('string' === typeof type) { - msg = type; - type = null; - } - - new Assertion(fn, msg).to.Throw(type); - }; - - /** - * ### .doesNotThrow(function, [constructor/regexp], [message]) - * - * Asserts that `function` will _not_ throw an error that is an instance of - * `constructor`, or alternately that it will not throw an error with message - * matching `regexp`. - * - * assert.doesNotThrow(fn, Error, 'function does not throw'); - * - * @name doesNotThrow - * @param {Function} function - * @param {ErrorConstructor} constructor - * @param {RegExp} regexp - * @param {String} message - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types - * @api public - */ - - assert.doesNotThrow = function (fn, type, msg) { - if ('string' === typeof type) { - msg = type; - type = null; - } - - new Assertion(fn, msg).to.not.Throw(type); - }; - - /** - * ### .operator(val1, operator, val2, [message]) - * - * Compares two values using `operator`. - * - * assert.operator(1, '<', 2, 'everything is ok'); - * assert.operator(1, '>', 2, 'this will fail'); - * - * @name operator - * @param {Mixed} val1 - * @param {String} operator - * @param {Mixed} val2 - * @param {String} message - * @api public - */ - - assert.operator = function (val, operator, val2, msg) { - if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) { - throw new Error('Invalid operator "' + operator + '"'); - } - var test = new Assertion(eval(val + operator + val2), msg); - test.assert( - true === flag(test, 'object') - , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) - , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); - }; - - /** - * ### .closeTo(actual, expected, delta, [message]) - * - * Asserts that the target is equal `expected`, to within a +/- `delta` range. - * - * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); - * - * @name closeTo - * @param {Number} actual - * @param {Number} expected - * @param {Number} delta - * @param {String} message - * @api public - */ - - assert.closeTo = function (act, exp, delta, msg) { - new Assertion(act, msg).to.be.closeTo(exp, delta); - }; - - /*! - * Undocumented / untested - */ - - assert.ifError = function (val, msg) { - new Assertion(val, msg).to.not.be.ok; - }; - - /*! - * Aliases. - */ - - (function alias(name, as){ - assert[as] = assert[name]; - return alias; - }) - ('Throw', 'throw') - ('Throw', 'throws'); - }; - - }); // module: chai/interface/assert.js - - require.register("chai/interface/expect.js", function(module, exports, require){ - /*! - * chai - * Copyright(c) 2011-2012 Jake Luer - * MIT Licensed - */ - - module.exports = function (chai, util) { - chai.expect = function (val, message) { - return new chai.Assertion(val, message); - }; - }; - - - }); // module: chai/interface/expect.js - - require.register("chai/interface/should.js", function(module, exports, require){ - /*! - * chai - * Copyright(c) 2011-2012 Jake Luer - * MIT Licensed - */ - - module.exports = function (chai, util) { - var Assertion = chai.Assertion; - - function loadShould () { - // modify Object.prototype to have `should` - Object.defineProperty(Object.prototype, 'should', - { - set: function (value) { - // See https://github.com/chaijs/chai/issues/86: this makes - // `whatever.should = someValue` actually set `someValue`, which is - // especially useful for `global.should = require('chai').should()`. - // - // Note that we have to use [[DefineProperty]] instead of [[Put]] - // since otherwise we would trigger this very setter! - Object.defineProperty(this, 'should', { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } - , get: function(){ - if (this instanceof String || this instanceof Number) { - return new Assertion(this.constructor(this)); - } else if (this instanceof Boolean) { - return new Assertion(this == true); - } - return new Assertion(this); - } - , configurable: true - }); - - var should = {}; - - should.equal = function (val1, val2, msg) { - new Assertion(val1, msg).to.equal(val2); - }; - - should.Throw = function (fn, errt, errs, msg) { - new Assertion(fn, msg).to.Throw(errt, errs); - }; - - should.exist = function (val, msg) { - new Assertion(val, msg).to.exist; - } - - // negation - should.not = {} - - should.not.equal = function (val1, val2, msg) { - new Assertion(val1, msg).to.not.equal(val2); - }; - - should.not.Throw = function (fn, errt, errs, msg) { - new Assertion(fn, msg).to.not.Throw(errt, errs); - }; - - should.not.exist = function (val, msg) { - new Assertion(val, msg).to.not.exist; - } - - should['throw'] = should['Throw']; - should.not['throw'] = should.not['Throw']; - - return should; - }; - - chai.should = loadShould; - chai.Should = loadShould; - }; - - }); // module: chai/interface/should.js - - require.register("chai/utils/addChainableMethod.js", function(module, exports, require){ - /*! - * Chai - addChainingMethod utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /*! - * Module dependencies - */ - - var transferFlags = require('./transferFlags'); - - /** - * ### addChainableMethod (ctx, name, method, chainingBehavior) - * - * Adds a method to an object, such that the method can also be chained. - * - * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { - * var obj = utils.flag(this, 'object'); - * new chai.Assertion(obj).to.be.equal(str); - * }); - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); - * - * The result can then be used as both a method assertion, executing both `method` and - * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. - * - * expect(fooStr).to.be.foo('bar'); - * expect(fooStr).to.be.foo.equal('foo'); - * - * @param {Object} ctx object to which the method is added - * @param {String} name of method to add - * @param {Function} method function to be used for `name`, when called - * @param {Function} chainingBehavior function to be called every time the property is accessed - * @name addChainableMethod - * @api public - */ - - module.exports = function (ctx, name, method, chainingBehavior) { - if (typeof chainingBehavior !== 'function') - chainingBehavior = function () { }; - - Object.defineProperty(ctx, name, - { get: function () { - chainingBehavior.call(this); - - var assert = function () { - var result = method.apply(this, arguments); - return result === undefined ? this : result; - }; - - // Re-enumerate every time to better accomodate plugins. - var asserterNames = Object.getOwnPropertyNames(ctx); - asserterNames.forEach(function (asserterName) { - var pd = Object.getOwnPropertyDescriptor(ctx, asserterName) - , functionProtoPD = Object.getOwnPropertyDescriptor(Function.prototype, asserterName); - // Avoid trying to overwrite things that we can't, like `length` and `arguments`. - if (functionProtoPD && !functionProtoPD.configurable) return; - if (asserterName === 'arguments') return; // @see chaijs/chai/issues/69 - Object.defineProperty(assert, asserterName, pd); - }); - - transferFlags(this, assert); - return assert; - } - , configurable: true - }); - }; - - }); // module: chai/utils/addChainableMethod.js - - require.register("chai/utils/addMethod.js", function(module, exports, require){ - /*! - * Chai - addMethod utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /** - * ### .addMethod (ctx, name, method) - * - * Adds a method to the prototype of an object. - * - * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { - * var obj = utils.flag(this, 'object'); - * new chai.Assertion(obj).to.be.equal(str); - * }); - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.addMethod('foo', fn); - * - * Then can be used as any other assertion. - * - * expect(fooStr).to.be.foo('bar'); - * - * @param {Object} ctx object to which the method is added - * @param {String} name of method to add - * @param {Function} method function to be used for name - * @name addMethod - * @api public - */ - - module.exports = function (ctx, name, method) { - ctx[name] = function () { - var result = method.apply(this, arguments); - return result === undefined ? this : result; - }; - }; - - }); // module: chai/utils/addMethod.js - - require.register("chai/utils/addProperty.js", function(module, exports, require){ - /*! - * Chai - addProperty utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /** - * ### addProperty (ctx, name, getter) - * - * Adds a property to the prototype of an object. - * - * utils.addProperty(chai.Assertion.prototype, 'foo', function () { - * var obj = utils.flag(this, 'object'); - * new chai.Assertion(obj).to.be.instanceof(Foo); - * }); - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.addProperty('foo', fn); - * - * Then can be used as any other assertion. - * - * expect(myFoo).to.be.foo; - * - * @param {Object} ctx object to which the property is added - * @param {String} name of property to add - * @param {Function} getter function to be used for name - * @name addProperty - * @api public - */ - - module.exports = function (ctx, name, getter) { - Object.defineProperty(ctx, name, - { get: function () { - var result = getter.call(this); - return result === undefined ? this : result; - } - , configurable: true - }); - }; - - }); // module: chai/utils/addProperty.js - - require.register("chai/utils/eql.js", function(module, exports, require){ - // This is (almost) directly from Node.js assert - // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/assert.js - - module.exports = _deepEqual; - - // for the browser - var Buffer; - try { - Buffer = require('buffer').Buffer; - } catch (ex) { - Buffer = { - isBuffer: function () { return false; } - }; - } - - function _deepEqual(actual, expected, memos) { - - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - - } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { - if (actual.length != expected.length) return false; - - for (var i = 0; i < actual.length; i++) { - if (actual[i] !== expected[i]) return false; - } - - return true; - - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - } else if (actual instanceof Date && expected instanceof Date) { - return actual.getTime() === expected.getTime(); - - // 7.3. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if (typeof actual != 'object' && typeof expected != 'object') { - return actual === expected; - - // 7.4. For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else { - return objEquiv(actual, expected, memos); - } - } - - function isUndefinedOrNull(value) { - return value === null || value === undefined; - } - - function isArguments(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; - } - - function objEquiv(a, b, memos) { - if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) - return false; - - // an identical 'prototype' property. - if (a.prototype !== b.prototype) return false; - - // check if we have already compared a and b - var i; - if (memos) { - for(i = 0; i < memos.length; i++) { - if ((memos[i][0] === a && memos[i][1] === b) || - (memos[i][0] === b && memos[i][1] === a)) - return true; - } - } else { - memos = []; - } - - //~~~I've managed to break Object.keys through screwy arguments passing. - // Converting to array solves the problem. - if (isArguments(a)) { - if (!isArguments(b)) { - return false; - } - a = pSlice.call(a); - b = pSlice.call(b); - return _deepEqual(a, b, memos); - } - try { - var ka = Object.keys(a), - kb = Object.keys(b), - key; - } catch (e) {//happens when one is a string literal and the other isn't - return false; - } - - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length != kb.length) - return false; - - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] != kb[i]) - return false; - } - - // remember objects we have compared to guard against circular references - memos.push([ a, b ]); - - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!_deepEqual(a[key], b[key], memos)) return false; - } - - return true; - } - - }); // module: chai/utils/eql.js - - require.register("chai/utils/flag.js", function(module, exports, require){ - /*! - * Chai - flag utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /** - * ### flag(object ,key, [value]) - * - * Get or set a flag value on an object. If a - * value is provided it will be set, else it will - * return the currently set value or `undefined` if - * the value is not set. - * - * utils.flag(this, 'foo', 'bar'); // setter - * utils.flag(this, 'foo'); // getter, returns `bar` - * - * @param {Object} object (constructed Assertion - * @param {String} key - * @param {Mixed} value (optional) - * @name flag - * @api private - */ - - module.exports = function (obj, key, value) { - var flags = obj.__flags || (obj.__flags = Object.create(null)); - if (arguments.length === 3) { - flags[key] = value; - } else { - return flags[key]; - } - }; - - }); // module: chai/utils/flag.js - - require.register("chai/utils/getActual.js", function(module, exports, require){ - /*! - * Chai - getActual utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /** - * # getActual(object, [actual]) - * - * Returns the `actual` value for an Assertion - * - * @param {Object} object (constructed Assertion) - * @param {Arguments} chai.Assertion.prototype.assert arguments - */ - - module.exports = function (obj, args) { - var actual = args[4]; - return 'undefined' !== typeof actual ? actual : obj._obj; - }; - - }); // module: chai/utils/getActual.js - - require.register("chai/utils/getMessage.js", function(module, exports, require){ - /*! - * Chai - message composition utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /*! - * Module dependancies - */ - - var flag = require('./flag') - , getActual = require('./getActual') - , inspect = require('./inspect') - , objDisplay = require('./objDisplay'); - - /** - * ### .getMessage(object, message, negateMessage) - * - * Construct the error message based on flags - * and template tags. Template tags will return - * a stringified inspection of the object referenced. - * - * Messsage template tags: - * - `#{this}` current asserted object - * - `#{act}` actual value - * - `#{exp}` expected value - * - * @param {Object} object (constructed Assertion) - * @param {Arguments} chai.Assertion.prototype.assert arguments - * @name getMessage - * @api public - */ - - module.exports = function (obj, args) { - var negate = flag(obj, 'negate') - , val = flag(obj, 'object') - , expected = args[3] - , actual = getActual(obj, args) - , msg = negate ? args[2] : args[1] - , flagMsg = flag(obj, 'message'); - - msg = msg || ''; - msg = msg - .replace(/#{this}/g, objDisplay(val)) - .replace(/#{act}/g, objDisplay(actual)) - .replace(/#{exp}/g, objDisplay(expected)); - - return flagMsg ? flagMsg + ': ' + msg : msg; - }; - - }); // module: chai/utils/getMessage.js - - require.register("chai/utils/getName.js", function(module, exports, require){ - /*! - * Chai - getName utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /** - * # getName(func) - * - * Gets the name of a function, in a cross-browser way. - * - * @param {Function} a function (usually a constructor) - */ - - module.exports = function (func) { - if (func.name) return func.name; - - var match = /^\s?function ([^(]*)\(/.exec(func); - return match && match[1] ? match[1] : ""; - }; - - }); // module: chai/utils/getName.js - - require.register("chai/utils/getPathValue.js", function(module, exports, require){ - /*! - * Chai - getPathValue utility - * Copyright(c) 2012 Jake Luer - * @see https://github.com/logicalparadox/filtr - * MIT Licensed - */ - - /** - * ### .getPathValue(path, object) - * - * This allows the retrieval of values in an - * object given a string path. - * - * var obj = { - * prop1: { - * arr: ['a', 'b', 'c'] - * , str: 'Hello' - * } - * , prop2: { - * arr: [ { nested: 'Universe' } ] - * , str: 'Hello again!' - * } - * } - * - * The following would be the results. - * - * getPathValue('prop1.str', obj); // Hello - * getPathValue('prop1.att[2]', obj); // b - * getPathValue('prop2.arr[0].nested', obj); // Universe - * - * @param {String} path - * @param {Object} object - * @returns {Object} value or `undefined` - * @name getPathValue - * @api public - */ - - var getPathValue = module.exports = function (path, obj) { - var parsed = parsePath(path); - return _getPathValue(parsed, obj); - }; - - /*! - * ## parsePath(path) - * - * Helper function used to parse string object - * paths. Use in conjunction with `_getPathValue`. - * - * var parsed = parsePath('myobject.property.subprop'); - * - * ### Paths: - * - * * Can be as near infinitely deep and nested - * * Arrays are also valid using the formal `myobject.document[3].property`. - * - * @param {String} path - * @returns {Object} parsed - * @api private - */ - - function parsePath (path) { - var str = path.replace(/\[/g, '.[') - , parts = str.match(/(\\\.|[^.]+?)+/g); - return parts.map(function (value) { - var re = /\[(\d+)\]$/ - , mArr = re.exec(value) - if (mArr) return { i: parseFloat(mArr[1]) }; - else return { p: value }; - }); - }; - - /*! - * ## _getPathValue(parsed, obj) - * - * Helper companion function for `.parsePath` that returns - * the value located at the parsed address. - * - * var value = getPathValue(parsed, obj); - * - * @param {Object} parsed definition from `parsePath`. - * @param {Object} object to search against - * @returns {Object|Undefined} value - * @api private - */ - - function _getPathValue (parsed, obj) { - var tmp = obj - , res; - for (var i = 0, l = parsed.length; i < l; i++) { - var part = parsed[i]; - if (tmp) { - if ('undefined' !== typeof part.p) - tmp = tmp[part.p]; - else if ('undefined' !== typeof part.i) - tmp = tmp[part.i]; - if (i == (l - 1)) res = tmp; - } else { - res = undefined; - } - } - return res; - }; - - }); // module: chai/utils/getPathValue.js - - require.register("chai/utils/index.js", function(module, exports, require){ - /*! - * chai - * Copyright(c) 2011 Jake Luer - * MIT Licensed - */ - - /*! - * Main exports - */ - - var exports = module.exports = {}; - - /*! - * test utility - */ - - exports.test = require('./test'); - - /*! - * message utility - */ - - exports.getMessage = require('./getMessage'); - - /*! - * actual utility - */ - - exports.getActual = require('./getActual'); - - /*! - * Inspect util - */ - - exports.inspect = require('./inspect'); - - /*! - * Object Display util - */ - - exports.objDisplay = require('./objDisplay'); - - /*! - * Flag utility - */ - - exports.flag = require('./flag'); - - /*! - * Flag transferring utility - */ - - exports.transferFlags = require('./transferFlags'); - - /*! - * Deep equal utility - */ - - exports.eql = require('./eql'); - - /*! - * Deep path value - */ - - exports.getPathValue = require('./getPathValue'); - - /*! - * Function name - */ - - exports.getName = require('./getName'); - - /*! - * add Property - */ - - exports.addProperty = require('./addProperty'); - - /*! - * add Method - */ - - exports.addMethod = require('./addMethod'); - - /*! - * overwrite Property - */ - - exports.overwriteProperty = require('./overwriteProperty'); - - /*! - * overwrite Method - */ - - exports.overwriteMethod = require('./overwriteMethod'); - - /*! - * Add a chainable method - */ - - exports.addChainableMethod = require('./addChainableMethod'); - - - }); // module: chai/utils/index.js - - require.register("chai/utils/inspect.js", function(module, exports, require){ - // This is (almost) directly from Node.js utils - // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js - - var getName = require('./getName'); - - module.exports = inspect; - - /** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Boolean} showHidden Flag that shows hidden (not enumerable) - * properties of objects. - * @param {Number} depth Depth in which to descend in object. Default is 2. - * @param {Boolean} colors Flag to turn on ANSI escape codes to color the - * output. Default is false (no coloring). - */ - function inspect(obj, showHidden, depth, colors) { - var ctx = { - showHidden: showHidden, - seen: [], - stylize: function (str) { return str; } - }; - return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); - } - - // https://gist.github.com/1044128/ - var getOuterHTML = function(element) { - if ('outerHTML' in element) return element.outerHTML; - var ns = "http://www.w3.org/1999/xhtml"; - var container = document.createElementNS(ns, '_'); - var elemProto = (window.HTMLElement || window.Element).prototype; - var xmlSerializer = new XMLSerializer(); - var html; - if (document.xmlVersion) { - return xmlSerializer.serializeToString(element); - } else { - container.appendChild(element.cloneNode(false)); - html = container.innerHTML.replace('><', '>' + element.innerHTML + '<'); - container.innerHTML = ''; - return html; - } - }; - - // Returns true if object is a DOM element. - var isDOMElement = function (object) { - if (typeof HTMLElement === 'object') { - return object instanceof HTMLElement; - } else { - return object && - typeof object === 'object' && - object.nodeType === 1 && - typeof object.nodeName === 'string'; - } - }; - - function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (value && typeof value.inspect === 'function' && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - return value.inspect(recurseTimes); - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // If it's DOM elem, get outer HTML. - if (isDOMElement(value)) { - return getOuterHTML(value); - } - - // Look up the keys of the object. - var visibleKeys = Object.keys(value); - var keys = ctx.showHidden ? Object.getOwnPropertyNames(value) : visibleKeys; - - // Some type of object without properties can be shortcutted. - // In IE, errors have a single `stack` property, or if they are vanilla `Error`, - // a `stack` plus `description` property; ignore those for consistency. - if (keys.length === 0 || (isError(value) && ( - (keys.length === 1 && keys[0] === 'stack') || - (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') - ))) { - if (typeof value === 'function') { - var name = getName(value); - var nameSuffix = name ? ': ' + name : ''; - return ctx.stylize('[Function' + nameSuffix + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (typeof value === 'function') { - var name = getName(value); - var nameSuffix = name ? ': ' + name : ''; - base = ' [Function' + nameSuffix + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - return formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); - } - - - function formatPrimitive(ctx, value) { - switch (typeof value) { - case 'undefined': - return ctx.stylize('undefined', 'undefined'); - - case 'string': - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - - case 'number': - return ctx.stylize('' + value, 'number'); - - case 'boolean': - return ctx.stylize('' + value, 'boolean'); - } - // For some reason typeof null is "object", so special case here. - if (value === null) { - return ctx.stylize('null', 'null'); - } - } - - - function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; - } - - - function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (Object.prototype.hasOwnProperty.call(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; - } - - - function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str; - if (value.__lookupGetter__) { - if (value.__lookupGetter__(key)) { - if (value.__lookupSetter__(key)) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (value.__lookupSetter__(key)) { - str = ctx.stylize('[Setter]', 'special'); - } - } - } - if (visibleKeys.indexOf(key) < 0) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(value[key]) < 0) { - if (recurseTimes === null) { - str = formatValue(ctx, value[key], null); - } else { - str = formatValue(ctx, value[key], recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (typeof name === 'undefined') { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; - } - - - function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; - } - - function isArray(ar) { - return Array.isArray(ar) || - (typeof ar === 'object' && objectToString(ar) === '[object Array]'); - } - - function isRegExp(re) { - return typeof re === 'object' && objectToString(re) === '[object RegExp]'; - } - - function isDate(d) { - return typeof d === 'object' && objectToString(d) === '[object Date]'; - } - - function isError(e) { - return typeof e === 'object' && objectToString(e) === '[object Error]'; - } - - function objectToString(o) { - return Object.prototype.toString.call(o); - } - - }); // module: chai/utils/inspect.js - - require.register("chai/utils/objDisplay.js", function(module, exports, require){ - /*! - * Chai - flag utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /*! - * Module dependancies - */ - - var inspect = require('./inspect'); - - /** - * ### .objDisplay (object) - * - * Determines if an object or an array matches - * criteria to be inspected in-line for error - * messages or should be truncated. - * - * @param {Mixed} javascript object to inspect - * @name objDisplay - * @api public - */ - - module.exports = function (obj) { - var str = inspect(obj) - , type = Object.prototype.toString.call(obj); - - if (str.length >= 40) { - if (type === '[object Array]') { - return '[ Array(' + obj.length + ') ]'; - } else if (type === '[object Object]') { - var keys = Object.keys(obj) - , kstr = keys.length > 2 - ? keys.splice(0, 2).join(', ') + ', ...' - : keys.join(', '); - return '{ Object (' + kstr + ') }'; - } else { - return str; - } - } else { - return str; - } - }; - - }); // module: chai/utils/objDisplay.js - - require.register("chai/utils/overwriteMethod.js", function(module, exports, require){ - /*! - * Chai - overwriteMethod utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /** - * ### overwriteMethod (ctx, name, fn) - * - * Overwites an already existing method and provides - * access to previous function. Must return function - * to be used for name. - * - * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { - * return function (str) { - * var obj = utils.flag(this, 'object'); - * if (obj instanceof Foo) { - * new chai.Assertion(obj.value).to.equal(str); - * } else { - * _super.apply(this, arguments); - * } - * } - * }); - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.overwriteMethod('foo', fn); - * - * Then can be used as any other assertion. - * - * expect(myFoo).to.equal('bar'); - * - * @param {Object} ctx object whose method is to be overwritten - * @param {String} name of method to overwrite - * @param {Function} method function that returns a function to be used for name - * @name overwriteMethod - * @api public - */ - - module.exports = function (ctx, name, method) { - var _method = ctx[name] - , _super = function () { return this; }; - - if (_method && 'function' === typeof _method) - _super = _method; - - ctx[name] = function () { - var result = method(_super).apply(this, arguments); - return result === undefined ? this : result; - } - }; - - }); // module: chai/utils/overwriteMethod.js - - require.register("chai/utils/overwriteProperty.js", function(module, exports, require){ - /*! - * Chai - overwriteProperty utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /** - * ### overwriteProperty (ctx, name, fn) - * - * Overwites an already existing property getter and provides - * access to previous value. Must return function to use as getter. - * - * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { - * return function () { - * var obj = utils.flag(this, 'object'); - * if (obj instanceof Foo) { - * new chai.Assertion(obj.name).to.equal('bar'); - * } else { - * _super.call(this); - * } - * } - * }); - * - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.overwriteProperty('foo', fn); - * - * Then can be used as any other assertion. - * - * expect(myFoo).to.be.ok; - * - * @param {Object} ctx object whose property is to be overwritten - * @param {String} name of property to overwrite - * @param {Function} getter function that returns a getter function to be used for name - * @name overwriteProperty - * @api public - */ - - module.exports = function (ctx, name, getter) { - var _get = Object.getOwnPropertyDescriptor(ctx, name) - , _super = function () {}; - - if (_get && 'function' === typeof _get.get) - _super = _get.get - - Object.defineProperty(ctx, name, - { get: function () { - var result = getter(_super).call(this); - return result === undefined ? this : result; - } - , configurable: true - }); - }; - - }); // module: chai/utils/overwriteProperty.js - - require.register("chai/utils/test.js", function(module, exports, require){ - /*! - * Chai - test utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /*! - * Module dependancies - */ - - var flag = require('./flag'); - - /** - * # test(object, expression) - * - * Test and object for expression. - * - * @param {Object} object (constructed Assertion) - * @param {Arguments} chai.Assertion.prototype.assert arguments - */ - - module.exports = function (obj, args) { - var negate = flag(obj, 'negate') - , expr = args[0]; - return negate ? !expr : expr; - }; - - }); // module: chai/utils/test.js - - require.register("chai/utils/transferFlags.js", function(module, exports, require){ - /*! - * Chai - transferFlags utility - * Copyright(c) 2012 Jake Luer - * MIT Licensed - */ - - /** - * ### transferFlags(assertion, object, includeAll = true) - * - * Transfer all the flags for `assertion` to `object`. If - * `includeAll` is set to `false`, then the base Chai - * assertion flags (namely `object`, `ssfi`, and `message`) - * will not be transferred. - * - * - * var newAssertion = new Assertion(); - * utils.transferFlags(assertion, newAssertion); - * - * var anotherAsseriton = new Assertion(myObj); - * utils.transferFlags(assertion, anotherAssertion, false); - * - * @param {Assertion} assertion the assertion to transfer the flags from - * @param {Object} object the object to transfer the flags too; usually a new assertion - * @param {Boolean} includeAll - * @name getAllFlags - * @api private - */ - - module.exports = function (assertion, object, includeAll) { - var flags = assertion.__flags || (assertion.__flags = Object.create(null)); - - if (!object.__flags) { - object.__flags = Object.create(null); - } - - includeAll = arguments.length === 3 ? includeAll : true; - - for (var flag in flags) { - if (includeAll || - (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { - object.__flags[flag] = flags[flag]; - } - } - }; - - }); // module: chai/utils/transferFlags.js - - require.alias("./chai.js", "chai"); - - return require('chai'); -}); \ No newline at end of file diff --git a/test/lib/happen.js b/test/lib/happen.js deleted file mode 100644 index 2f7f5e6cb..000000000 --- a/test/lib/happen.js +++ /dev/null @@ -1,123 +0,0 @@ -!(function(context, $) { - var h = {}; - - // Make inheritance bearable: clone one level of properties - function extend(child, parent) { - for (var property in parent) { - if (typeof child[property] == 'undefined') { - child[property] = parent[property]; - } - } - return child; - } - - h.once = function(x, o) { - var evt; - - if (o.type.slice(0, 3) === 'key') { - if (typeof Event === 'function') { - evt = new Event(o.type); - evt.keyCode = o.keyCode || 0; - evt.charCode = o.charCode || 0; - evt.shiftKey = o.shiftKey || false; - evt.metaKey = o.metaKey || false; - evt.ctrlKey = o.ctrlKey || false; - evt.altKey = o.altKey || false; - } else { - evt = document.createEvent('KeyboardEvent'); - // https://developer.mozilla.org/en/DOM/event.initKeyEvent - // https://developer.mozilla.org/en/DOM/KeyboardEvent - evt[(evt.initKeyEvent) ? 'initKeyEvent' - : 'initKeyboardEvent']( - o.type, // in DOMString typeArg, - true, // in boolean canBubbleArg, - true, // in boolean cancelableArg, - null, // in nsIDOMAbstractView viewArg, Specifies UIEvent.view. This value may be null. - o.ctrlKey || false, // in boolean ctrlKeyArg, - o.altKey || false, // in boolean altKeyArg, - o.shiftKey || false, // in boolean shiftKeyArg, - o.metaKey || false, // in boolean metaKeyArg, - o.keyCode || 0, // in unsigned long keyCodeArg, - o.charCode || 0 // in unsigned long charCodeArg); - ); - - // Workaround for https://bugs.webkit.org/show_bug.cgi?id=16735 - if (evt.ctrlKey != (o.ctrlKey || 0) || - evt.altKey != (o.altKey || 0) || - evt.shiftKey != (o.shiftKey || 0) || - evt.metaKey != (o.metaKey || 0) || - evt.keyCode != (o.keyCode || 0) || - evt.charCode != (o.charCode || 0)) { - evt = document.createEvent('Event'); - evt.initEvent(o.type, true, true); - evt.ctrlKey = o.ctrlKey || false; - evt.altKey = o.altKey || false; - evt.shiftKey = o.shiftKey || false; - evt.metaKey = o.metaKey || false; - evt.keyCode = o.keyCode || 0; - evt.charCode = o.charCode || 0; - } - } - } else { - evt = document.createEvent('MouseEvents'); - // https://developer.mozilla.org/en/DOM/event.initMouseEvent - evt.initMouseEvent(o.type, - true, // canBubble - true, // cancelable - window, // 'AbstractView' - o.clicks || 0, // click count - o.screenX || 0, // screenX - o.screenY || 0, // screenY - o.clientX || 0, // clientX - o.clientY || 0, // clientY - o.ctrlKey || 0, // ctrl - o.altKey || false, // alt - o.shiftKey || false, // shift - o.metaKey || false, // meta - o.button || false, // mouse button - null // relatedTarget - ); - } - - x.dispatchEvent(evt); - }; - - var shortcuts = ['click', 'mousedown', 'mouseup', 'mousemove', - 'mouseover', 'mouseout', 'keydown', 'keyup', 'keypress'], - s, i = 0; - - while (s = shortcuts[i++]) { - h[s] = (function(s) { - return function(x, o) { - h.once(x, extend(o || {}, { type: s })); - }; - })(s); - } - - h.dblclick = function(x, o) { - h.once(x, extend(o || {}, { - type: 'dblclick', - clicks: 2 - })); - }; - - this.happen = h; - - // Export for nodejs - if (typeof module !== 'undefined') { - module.exports = this.happen; - } - - // Provide jQuery plugin - if ($ && $.fn) { - $.fn.happen = function(o) { - if (typeof o === 'string') { - o = { type: o }; - } - for (var i = 0; i < this.length; i++) { - happen.once(this[i], o); - } - return this; - }; - } -})(this, (typeof jQuery !== 'undefined') ? jQuery : null); diff --git a/test/lib/sinon-chai.js b/test/lib/sinon-chai.js deleted file mode 100644 index eea5f1043..000000000 --- a/test/lib/sinon-chai.js +++ /dev/null @@ -1,106 +0,0 @@ -(function (sinonChai) { - "use strict"; - - // Module systems magic dance. - - if (typeof require === "function" && typeof exports === "object" && typeof module === "object") { - // NodeJS - module.exports = sinonChai; - } else if (typeof define === "function" && define.amd) { - // AMD - define(function () { - return sinonChai; - }); - } else { - // Other environment (usually