new BufferList([ callback ])
+ * bl.length
+ * bl.append(buffer)
+ * bl.get(index)
+ * bl.indexOf(value[, byteOffset][, encoding])
+ * bl.slice([ start[, end ] ])
+ * bl.shallowSlice([ start[, end ] ])
+ * bl.copy(dest, [ destStart, [ srcStart [, srcEnd ] ] ])
+ * bl.duplicate()
+ * bl.consume(bytes)
+ * bl.toString([encoding, [ start, [ end ]]])
+ * bl.readDoubleBE(), bl.readDoubleLE(), bl.readFloatBE(), bl.readFloatLE(), bl.readInt32BE(), bl.readInt32LE(), bl.readUInt32BE(), bl.readUInt32LE(), bl.readInt16BE(), bl.readInt16LE(), bl.readUInt16BE(), bl.readUInt16LE(), bl.readInt8(), bl.readUInt8()
+ * Streams
+
+--------------------------------------------------------
+
+### new BufferList([ callback | Buffer | Buffer array | BufferList | BufferList array | String ])
+The constructor takes an optional callback, if supplied, the callback will be called with an error argument followed by a reference to the **bl** instance, when `bl.end()` is called (i.e. from a piped stream). This is a convenient method of collecting the entire contents of a stream, particularly when the stream is *chunky*, such as a network stream.
+
+Normally, no arguments are required for the constructor, but you can initialise the list by passing in a single `Buffer` object or an array of `Buffer` object.
+
+`new` is not strictly required, if you don't instantiate a new object, it will be done automatically for you so you can create a new instance simply with:
+
+```js
+var bl = require('bl')
+var myinstance = bl()
+
+// equivalent to:
+
+var BufferList = require('bl')
+var myinstance = new BufferList()
+```
+
+--------------------------------------------------------
+
+### bl.length
+Get the length of the list in bytes. This is the sum of the lengths of all of the buffers contained in the list, minus any initial offset for a semi-consumed buffer at the beginning. Should accurately represent the total number of bytes that can be read from the list.
+
+--------------------------------------------------------
+
+### bl.append(Buffer | Buffer array | BufferList | BufferList array | String)
+`append(buffer)` adds an additional buffer or BufferList to the internal list. `this` is returned so it can be chained.
+
+--------------------------------------------------------
+
+### bl.get(index)
+`get()` will return the byte at the specified index.
+
+--------------------------------------------------------
+
+### bl.indexOf(value[, byteOffset][, encoding])
+`get()` will return the byte at the specified index.
+`indexOf()` method returns the first index at which a given element can be found in the BufferList, or -1 if it is not present.
+
+--------------------------------------------------------
+
+### bl.slice([ start, [ end ] ])
+`slice()` returns a new `Buffer` object containing the bytes within the range specified. Both `start` and `end` are optional and will default to the beginning and end of the list respectively.
+
+If the requested range spans a single internal buffer then a slice of that buffer will be returned which shares the original memory range of that Buffer. If the range spans multiple buffers then copy operations will likely occur to give you a uniform Buffer.
+
+--------------------------------------------------------
+
+### bl.shallowSlice([ start, [ end ] ])
+`shallowSlice()` returns a new `BufferList` object containing the bytes within the range specified. Both `start` and `end` are optional and will default to the beginning and end of the list respectively.
+
+No copies will be performed. All buffers in the result share memory with the original list.
+
+--------------------------------------------------------
+
+### bl.copy(dest, [ destStart, [ srcStart [, srcEnd ] ] ])
+`copy()` copies the content of the list in the `dest` buffer, starting from `destStart` and containing the bytes within the range specified with `srcStart` to `srcEnd`. `destStart`, `start` and `end` are optional and will default to the beginning of the `dest` buffer, and the beginning and end of the list respectively.
+
+--------------------------------------------------------
+
+### bl.duplicate()
+`duplicate()` performs a **shallow-copy** of the list. The internal Buffers remains the same, so if you change the underlying Buffers, the change will be reflected in both the original and the duplicate. This method is needed if you want to call `consume()` or `pipe()` and still keep the original list.Example:
+
+```js
+var bl = new BufferList()
+
+bl.append('hello')
+bl.append(' world')
+bl.append('\n')
+
+bl.duplicate().pipe(process.stdout, { end: false })
+
+console.log(bl.toString())
+```
+
+--------------------------------------------------------
+
+### bl.consume(bytes)
+`consume()` will shift bytes *off the start of the list*. The number of bytes consumed don't need to line up with the sizes of the internal Buffers—initial offsets will be calculated accordingly in order to give you a consistent view of the data.
+
+--------------------------------------------------------
+
+### bl.toString([encoding, [ start, [ end ]]])
+`toString()` will return a string representation of the buffer. The optional `start` and `end` arguments are passed on to `slice()`, while the `encoding` is passed on to `toString()` of the resulting Buffer. See the [Buffer#toString()](http://nodejs.org/docs/latest/api/buffer.html#buffer_buf_tostring_encoding_start_end) documentation for more information.
+
+--------------------------------------------------------
+
+### bl.readDoubleBE(), bl.readDoubleLE(), bl.readFloatBE(), bl.readFloatLE(), bl.readInt32BE(), bl.readInt32LE(), bl.readUInt32BE(), bl.readUInt32LE(), bl.readInt16BE(), bl.readInt16LE(), bl.readUInt16BE(), bl.readUInt16LE(), bl.readInt8(), bl.readUInt8()
+
+All of the standard byte-reading methods of the `Buffer` interface are implemented and will operate across internal Buffer boundaries transparently.
+
+See the [Buffer](http://nodejs.org/docs/latest/api/buffer.html) documentation for how these work.
+
+--------------------------------------------------------
+
+### Streams
+**bl** is a Node **[Duplex Stream](http://nodejs.org/docs/latest/api/stream.html#stream_class_stream_duplex)**, so it can be read from and written to like a standard Node stream. You can also `pipe()` to and from a **bl** instance.
+
+--------------------------------------------------------
+
+## Contributors
+
+**bl** is brought to you by the following hackers:
+
+ * [Rod Vagg](https://github.com/rvagg)
+ * [Matteo Collina](https://github.com/mcollina)
+ * [Jarett Cruger](https://github.com/jcrugzz)
+
+=======
+
+
+## License & copyright
+
+Copyright (c) 2013-2018 bl contributors (listed above).
+
+bl is licensed under the MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE.md file for more details.
diff --git a/node_modules/bl/bl.js b/node_modules/bl/bl.js
new file mode 100644
index 00000000..52c37405
--- /dev/null
+++ b/node_modules/bl/bl.js
@@ -0,0 +1,392 @@
+'use strict'
+var DuplexStream = require('readable-stream').Duplex
+ , util = require('util')
+ , Buffer = require('safe-buffer').Buffer
+
+function BufferList (callback) {
+ if (!(this instanceof BufferList))
+ return new BufferList(callback)
+
+ this._bufs = []
+ this.length = 0
+
+ if (typeof callback == 'function') {
+ this._callback = callback
+
+ var piper = function piper (err) {
+ if (this._callback) {
+ this._callback(err)
+ this._callback = null
+ }
+ }.bind(this)
+
+ this.on('pipe', function onPipe (src) {
+ src.on('error', piper)
+ })
+ this.on('unpipe', function onUnpipe (src) {
+ src.removeListener('error', piper)
+ })
+ } else {
+ this.append(callback)
+ }
+
+ DuplexStream.call(this)
+}
+
+
+util.inherits(BufferList, DuplexStream)
+
+
+BufferList.prototype._offset = function _offset (offset) {
+ var tot = 0, i = 0, _t
+ if (offset === 0) return [ 0, 0 ]
+ for (; i < this._bufs.length; i++) {
+ _t = tot + this._bufs[i].length
+ if (offset < _t || i == this._bufs.length - 1) {
+ return [ i, offset - tot ]
+ }
+ tot = _t
+ }
+}
+
+BufferList.prototype._reverseOffset = function (blOffset) {
+ var bufferId = blOffset[0]
+ var offset = blOffset[1]
+ for (var i = 0; i < bufferId; i++) {
+ offset += this._bufs[i].length
+ }
+ return offset
+}
+
+BufferList.prototype.append = function append (buf) {
+ var i = 0
+
+ if (Buffer.isBuffer(buf)) {
+ this._appendBuffer(buf)
+ } else if (Array.isArray(buf)) {
+ for (; i < buf.length; i++)
+ this.append(buf[i])
+ } else if (buf instanceof BufferList) {
+ // unwrap argument into individual BufferLists
+ for (; i < buf._bufs.length; i++)
+ this.append(buf._bufs[i])
+ } else if (buf != null) {
+ // coerce number arguments to strings, since Buffer(number) does
+ // uninitialized memory allocation
+ if (typeof buf == 'number')
+ buf = buf.toString()
+
+ this._appendBuffer(Buffer.from(buf))
+ }
+
+ return this
+}
+
+
+BufferList.prototype._appendBuffer = function appendBuffer (buf) {
+ this._bufs.push(buf)
+ this.length += buf.length
+}
+
+
+BufferList.prototype._write = function _write (buf, encoding, callback) {
+ this._appendBuffer(buf)
+
+ if (typeof callback == 'function')
+ callback()
+}
+
+
+BufferList.prototype._read = function _read (size) {
+ if (!this.length)
+ return this.push(null)
+
+ size = Math.min(size, this.length)
+ this.push(this.slice(0, size))
+ this.consume(size)
+}
+
+
+BufferList.prototype.end = function end (chunk) {
+ DuplexStream.prototype.end.call(this, chunk)
+
+ if (this._callback) {
+ this._callback(null, this.slice())
+ this._callback = null
+ }
+}
+
+
+BufferList.prototype.get = function get (index) {
+ if (index > this.length || index < 0) {
+ return undefined
+ }
+ var offset = this._offset(index)
+ return this._bufs[offset[0]][offset[1]]
+}
+
+
+BufferList.prototype.slice = function slice (start, end) {
+ if (typeof start == 'number' && start < 0)
+ start += this.length
+ if (typeof end == 'number' && end < 0)
+ end += this.length
+ return this.copy(null, 0, start, end)
+}
+
+
+BufferList.prototype.copy = function copy (dst, dstStart, srcStart, srcEnd) {
+ if (typeof srcStart != 'number' || srcStart < 0)
+ srcStart = 0
+ if (typeof srcEnd != 'number' || srcEnd > this.length)
+ srcEnd = this.length
+ if (srcStart >= this.length)
+ return dst || Buffer.alloc(0)
+ if (srcEnd <= 0)
+ return dst || Buffer.alloc(0)
+
+ var copy = !!dst
+ , off = this._offset(srcStart)
+ , len = srcEnd - srcStart
+ , bytes = len
+ , bufoff = (copy && dstStart) || 0
+ , start = off[1]
+ , l
+ , i
+
+ // copy/slice everything
+ if (srcStart === 0 && srcEnd == this.length) {
+ if (!copy) { // slice, but full concat if multiple buffers
+ return this._bufs.length === 1
+ ? this._bufs[0]
+ : Buffer.concat(this._bufs, this.length)
+ }
+
+ // copy, need to copy individual buffers
+ for (i = 0; i < this._bufs.length; i++) {
+ this._bufs[i].copy(dst, bufoff)
+ bufoff += this._bufs[i].length
+ }
+
+ return dst
+ }
+
+ // easy, cheap case where it's a subset of one of the buffers
+ if (bytes <= this._bufs[off[0]].length - start) {
+ return copy
+ ? this._bufs[off[0]].copy(dst, dstStart, start, start + bytes)
+ : this._bufs[off[0]].slice(start, start + bytes)
+ }
+
+ if (!copy) // a slice, we need something to copy in to
+ dst = Buffer.allocUnsafe(len)
+
+ for (i = off[0]; i < this._bufs.length; i++) {
+ l = this._bufs[i].length - start
+
+ if (bytes > l) {
+ this._bufs[i].copy(dst, bufoff, start)
+ bufoff += l
+ } else {
+ this._bufs[i].copy(dst, bufoff, start, start + bytes)
+ bufoff += l
+ break
+ }
+
+ bytes -= l
+
+ if (start)
+ start = 0
+ }
+
+ // safeguard so that we don't return uninitialized memory
+ if (dst.length > bufoff) return dst.slice(0, bufoff)
+
+ return dst
+}
+
+BufferList.prototype.shallowSlice = function shallowSlice (start, end) {
+ start = start || 0
+ end = typeof end !== 'number' ? this.length : end
+
+ if (start < 0)
+ start += this.length
+ if (end < 0)
+ end += this.length
+
+ if (start === end) {
+ return new BufferList()
+ }
+ var startOffset = this._offset(start)
+ , endOffset = this._offset(end)
+ , buffers = this._bufs.slice(startOffset[0], endOffset[0] + 1)
+
+ if (endOffset[1] == 0)
+ buffers.pop()
+ else
+ buffers[buffers.length-1] = buffers[buffers.length-1].slice(0, endOffset[1])
+
+ if (startOffset[1] != 0)
+ buffers[0] = buffers[0].slice(startOffset[1])
+
+ return new BufferList(buffers)
+}
+
+BufferList.prototype.toString = function toString (encoding, start, end) {
+ return this.slice(start, end).toString(encoding)
+}
+
+BufferList.prototype.consume = function consume (bytes) {
+ // first, normalize the argument, in accordance with how Buffer does it
+ bytes = Math.trunc(bytes)
+ // do nothing if not a positive number
+ if (Number.isNaN(bytes) || bytes <= 0) return this
+
+ while (this._bufs.length) {
+ if (bytes >= this._bufs[0].length) {
+ bytes -= this._bufs[0].length
+ this.length -= this._bufs[0].length
+ this._bufs.shift()
+ } else {
+ this._bufs[0] = this._bufs[0].slice(bytes)
+ this.length -= bytes
+ break
+ }
+ }
+ return this
+}
+
+
+BufferList.prototype.duplicate = function duplicate () {
+ var i = 0
+ , copy = new BufferList()
+
+ for (; i < this._bufs.length; i++)
+ copy.append(this._bufs[i])
+
+ return copy
+}
+
+
+BufferList.prototype.destroy = function destroy () {
+ this._bufs.length = 0
+ this.length = 0
+ this.push(null)
+}
+
+
+BufferList.prototype.indexOf = function (search, offset, encoding) {
+ if (encoding === undefined && typeof offset === 'string') {
+ encoding = offset
+ offset = undefined
+ }
+ if (typeof search === 'function' || Array.isArray(search)) {
+ throw new TypeError('The "value" argument must be one of type string, Buffer, BufferList, or Uint8Array.')
+ } else if (typeof search === 'number') {
+ search = Buffer.from([search])
+ } else if (typeof search === 'string') {
+ search = Buffer.from(search, encoding)
+ } else if (search instanceof BufferList) {
+ search = search.slice()
+ } else if (!Buffer.isBuffer(search)) {
+ search = Buffer.from(search)
+ }
+
+ offset = Number(offset || 0)
+ if (isNaN(offset)) {
+ offset = 0
+ }
+
+ if (offset < 0) {
+ offset = this.length + offset
+ }
+
+ if (offset < 0) {
+ offset = 0
+ }
+
+ if (search.length === 0) {
+ return offset > this.length ? this.length : offset
+ }
+
+ var blOffset = this._offset(offset)
+ var blIndex = blOffset[0] // index of which internal buffer we're working on
+ var buffOffset = blOffset[1] // offset of the internal buffer we're working on
+
+ // scan over each buffer
+ for (blIndex; blIndex < this._bufs.length; blIndex++) {
+ var buff = this._bufs[blIndex]
+ while(buffOffset < buff.length) {
+ var availableWindow = buff.length - buffOffset
+ if (availableWindow >= search.length) {
+ var nativeSearchResult = buff.indexOf(search, buffOffset)
+ if (nativeSearchResult !== -1) {
+ return this._reverseOffset([blIndex, nativeSearchResult])
+ }
+ buffOffset = buff.length - search.length + 1 // end of native search window
+ } else {
+ var revOffset = this._reverseOffset([blIndex, buffOffset])
+ if (this._match(revOffset, search)) {
+ return revOffset
+ }
+ buffOffset++
+ }
+ }
+ buffOffset = 0
+ }
+ return -1
+}
+
+BufferList.prototype._match = function(offset, search) {
+ if (this.length - offset < search.length) {
+ return false
+ }
+ for (var searchOffset = 0; searchOffset < search.length ; searchOffset++) {
+ if(this.get(offset + searchOffset) !== search[searchOffset]){
+ return false
+ }
+ }
+ return true
+}
+
+
+;(function () {
+ var methods = {
+ 'readDoubleBE' : 8
+ , 'readDoubleLE' : 8
+ , 'readFloatBE' : 4
+ , 'readFloatLE' : 4
+ , 'readInt32BE' : 4
+ , 'readInt32LE' : 4
+ , 'readUInt32BE' : 4
+ , 'readUInt32LE' : 4
+ , 'readInt16BE' : 2
+ , 'readInt16LE' : 2
+ , 'readUInt16BE' : 2
+ , 'readUInt16LE' : 2
+ , 'readInt8' : 1
+ , 'readUInt8' : 1
+ , 'readIntBE' : null
+ , 'readIntLE' : null
+ , 'readUIntBE' : null
+ , 'readUIntLE' : null
+ }
+
+ for (var m in methods) {
+ (function (m) {
+ if (methods[m] === null) {
+ BufferList.prototype[m] = function (offset, byteLength) {
+ return this.slice(offset, offset + byteLength)[m](0, byteLength)
+ }
+ }
+ else {
+ BufferList.prototype[m] = function (offset) {
+ return this.slice(offset, offset + methods[m])[m](0)
+ }
+ }
+ }(m))
+ }
+}())
+
+
+module.exports = BufferList
diff --git a/node_modules/bl/package.json b/node_modules/bl/package.json
new file mode 100644
index 00000000..b267b38f
--- /dev/null
+++ b/node_modules/bl/package.json
@@ -0,0 +1,63 @@
+{
+ "_from": "bl@^2.2.1",
+ "_id": "bl@2.2.1",
+ "_inBundle": false,
+ "_integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
+ "_location": "/bl",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "bl@^2.2.1",
+ "name": "bl",
+ "escapedName": "bl",
+ "rawSpec": "^2.2.1",
+ "saveSpec": null,
+ "fetchSpec": "^2.2.1"
+ },
+ "_requiredBy": [
+ "/mongodb"
+ ],
+ "_resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
+ "_shasum": "8c11a7b730655c5d56898cdc871224f40fd901d5",
+ "_spec": "bl@^2.2.1",
+ "_where": "C:\\Users\\rin\\Desktop\\final\\node_modules\\mongodb",
+ "authors": [
+ "Rod Vagg Welcome back, ' + escapeHtml(name) + '!
'); + } else { + res.write('Hello, new visitor!
'); + } + + res.write(''); +} + +http.createServer(onRequest).listen(3000); +``` + +## Testing + +```sh +$ npm test +``` + +## Benchmark + +``` +$ npm run bench + +> cookie@0.3.1 bench cookie +> node benchmark/index.js + + http_parser@2.8.0 + node@6.14.2 + v8@5.1.281.111 + uv@1.16.1 + zlib@1.2.11 + ares@1.10.1-DEV + icu@58.2 + modules@48 + napi@3 + openssl@1.0.2o + +> node benchmark/parse.js + + cookie.parse + + 6 tests completed. + + simple x 1,200,691 ops/sec ±1.12% (189 runs sampled) + decode x 1,012,994 ops/sec ±0.97% (186 runs sampled) + unquote x 1,074,174 ops/sec ±2.43% (186 runs sampled) + duplicates x 438,424 ops/sec ±2.17% (184 runs sampled) + 10 cookies x 147,154 ops/sec ±1.01% (186 runs sampled) + 100 cookies x 14,274 ops/sec ±1.07% (187 runs sampled) +``` + +## References + +- [RFC 6265: HTTP State Management Mechanism][rfc-6265] +- [Same-site Cookies][rfc-6265bis-03-4.1.2.7] + +[rfc-6265bis-03-4.1.2.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7 +[rfc-6265]: https://tools.ietf.org/html/rfc6265 +[rfc-6265-5.1.4]: https://tools.ietf.org/html/rfc6265#section-5.1.4 +[rfc-6265-5.2.1]: https://tools.ietf.org/html/rfc6265#section-5.2.1 +[rfc-6265-5.2.2]: https://tools.ietf.org/html/rfc6265#section-5.2.2 +[rfc-6265-5.2.3]: https://tools.ietf.org/html/rfc6265#section-5.2.3 +[rfc-6265-5.2.4]: https://tools.ietf.org/html/rfc6265#section-5.2.4 +[rfc-6265-5.2.5]: https://tools.ietf.org/html/rfc6265#section-5.2.5 +[rfc-6265-5.2.6]: https://tools.ietf.org/html/rfc6265#section-5.2.6 +[rfc-6265-5.3]: https://tools.ietf.org/html/rfc6265#section-5.3 + +## License + +[MIT](LICENSE) + +[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/cookie/master +[coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master +[node-version-image]: https://badgen.net/npm/node/cookie +[node-version-url]: https://nodejs.org/en/download +[npm-downloads-image]: https://badgen.net/npm/dm/cookie +[npm-url]: https://npmjs.org/package/cookie +[npm-version-image]: https://badgen.net/npm/v/cookie +[travis-image]: https://badgen.net/travis/jshttp/cookie/master +[travis-url]: https://travis-ci.org/jshttp/cookie diff --git a/node_modules/cookie/index.js b/node_modules/cookie/index.js new file mode 100644 index 00000000..16f56c04 --- /dev/null +++ b/node_modules/cookie/index.js @@ -0,0 +1,198 @@ +/*! + * cookie + * Copyright(c) 2012-2014 Roman Shtylman + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + */ + +'use strict'; + +/** + * Module exports. + * @public + */ + +exports.parse = parse; +exports.serialize = serialize; + +/** + * Module variables. + * @private + */ + +var decode = decodeURIComponent; +var encode = encodeURIComponent; +var pairSplitRegExp = /; */; + +/** + * RegExp to match field-content in RFC 7230 sec 3.2 + * + * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] + * field-vchar = VCHAR / obs-text + * obs-text = %x80-FF + */ + +var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/; + +/** + * Parse a cookie header. + * + * Parse the given cookie header string into an object + * The object has the various cookies as keys(names) => values + * + * @param {string} str + * @param {object} [options] + * @return {object} + * @public + */ + +function parse(str, options) { + if (typeof str !== 'string') { + throw new TypeError('argument str must be a string'); + } + + var obj = {} + var opt = options || {}; + var pairs = str.split(pairSplitRegExp); + var dec = opt.decode || decode; + + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i]; + var eq_idx = pair.indexOf('='); + + // skip things that don't look like key=value + if (eq_idx < 0) { + continue; + } + + var key = pair.substr(0, eq_idx).trim() + var val = pair.substr(++eq_idx, pair.length).trim(); + + // quoted values + if ('"' == val[0]) { + val = val.slice(1, -1); + } + + // only assign once + if (undefined == obj[key]) { + obj[key] = tryDecode(val, dec); + } + } + + return obj; +} + +/** + * Serialize data into a cookie header. + * + * Serialize the a name value pair into a cookie string suitable for + * http headers. An optional options object specified cookie parameters. + * + * serialize('foo', 'bar', { httpOnly: true }) + * => "foo=bar; httpOnly" + * + * @param {string} name + * @param {string} val + * @param {object} [options] + * @return {string} + * @public + */ + +function serialize(name, val, options) { + var opt = options || {}; + var enc = opt.encode || encode; + + if (typeof enc !== 'function') { + throw new TypeError('option encode is invalid'); + } + + if (!fieldContentRegExp.test(name)) { + throw new TypeError('argument name is invalid'); + } + + var value = enc(val); + + if (value && !fieldContentRegExp.test(value)) { + throw new TypeError('argument val is invalid'); + } + + var str = name + '=' + value; + + if (null != opt.maxAge) { + var maxAge = opt.maxAge - 0; + if (isNaN(maxAge)) throw new Error('maxAge should be a Number'); + str += '; Max-Age=' + Math.floor(maxAge); + } + + if (opt.domain) { + if (!fieldContentRegExp.test(opt.domain)) { + throw new TypeError('option domain is invalid'); + } + + str += '; Domain=' + opt.domain; + } + + if (opt.path) { + if (!fieldContentRegExp.test(opt.path)) { + throw new TypeError('option path is invalid'); + } + + str += '; Path=' + opt.path; + } + + if (opt.expires) { + if (typeof opt.expires.toUTCString !== 'function') { + throw new TypeError('option expires is invalid'); + } + + str += '; Expires=' + opt.expires.toUTCString(); + } + + if (opt.httpOnly) { + str += '; HttpOnly'; + } + + if (opt.secure) { + str += '; Secure'; + } + + if (opt.sameSite) { + var sameSite = typeof opt.sameSite === 'string' + ? opt.sameSite.toLowerCase() : opt.sameSite; + + switch (sameSite) { + case true: + str += '; SameSite=Strict'; + break; + case 'lax': + str += '; SameSite=Lax'; + break; + case 'strict': + str += '; SameSite=Strict'; + break; + case 'none': + str += '; SameSite=None'; + break; + default: + throw new TypeError('option sameSite is invalid'); + } + } + + return str; +} + +/** + * Try decoding a string using a decoding function. + * + * @param {string} str + * @param {function} decode + * @private + */ + +function tryDecode(str, decode) { + try { + return decode(str); + } catch (e) { + return str; + } +} diff --git a/node_modules/cookie/package.json b/node_modules/cookie/package.json new file mode 100644 index 00000000..efbc06af --- /dev/null +++ b/node_modules/cookie/package.json @@ -0,0 +1,78 @@ +{ + "_from": "cookie@0.4.0", + "_id": "cookie@0.4.0", + "_inBundle": false, + "_integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "_location": "/cookie", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "cookie@0.4.0", + "name": "cookie", + "escapedName": "cookie", + "rawSpec": "0.4.0", + "saveSpec": null, + "fetchSpec": "0.4.0" + }, + "_requiredBy": [ + "/express" + ], + "_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "_shasum": "beb437e7022b3b6d49019d088665303ebe9c14ba", + "_spec": "cookie@0.4.0", + "_where": "C:\\Users\\rin\\Desktop\\final\\node_modules\\express", + "author": { + "name": "Roman Shtylman", + "email": "shtylman@gmail.com" + }, + "bugs": { + "url": "https://github.com/jshttp/cookie/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Douglas Christopher Wilson", + "email": "doug@somethingdoug.com" + } + ], + "deprecated": false, + "description": "HTTP server cookie parsing and serialization", + "devDependencies": { + "beautify-benchmark": "0.2.4", + "benchmark": "2.1.4", + "eslint": "5.16.0", + "eslint-plugin-markdown": "1.0.0", + "istanbul": "0.4.5", + "mocha": "6.1.4" + }, + "engines": { + "node": ">= 0.6" + }, + "files": [ + "HISTORY.md", + "LICENSE", + "README.md", + "index.js" + ], + "homepage": "https://github.com/jshttp/cookie#readme", + "keywords": [ + "cookie", + "cookies" + ], + "license": "MIT", + "name": "cookie", + "repository": { + "type": "git", + "url": "git+https://github.com/jshttp/cookie.git" + }, + "scripts": { + "bench": "node benchmark/index.js", + "lint": "eslint --plugin markdown --ext js,md .", + "test": "mocha --reporter spec --bail --check-leaks test/", + "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/", + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/", + "version": "node scripts/version-history.js && git add HISTORY.md" + }, + "version": "0.4.0" +} diff --git a/node_modules/core-util-is/LICENSE b/node_modules/core-util-is/LICENSE new file mode 100644 index 00000000..d8d7f943 --- /dev/null +++ b/node_modules/core-util-is/LICENSE @@ -0,0 +1,19 @@ +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/node_modules/core-util-is/README.md b/node_modules/core-util-is/README.md new file mode 100644 index 00000000..5a76b414 --- /dev/null +++ b/node_modules/core-util-is/README.md @@ -0,0 +1,3 @@ +# core-util-is + +The `util.is*` functions introduced in Node v0.12. diff --git a/node_modules/core-util-is/float.patch b/node_modules/core-util-is/float.patch new file mode 100644 index 00000000..a06d5c05 --- /dev/null +++ b/node_modules/core-util-is/float.patch @@ -0,0 +1,604 @@ +diff --git a/lib/util.js b/lib/util.js +index a03e874..9074e8e 100644 +--- a/lib/util.js ++++ b/lib/util.js +@@ -19,430 +19,6 @@ + // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + // USE OR OTHER DEALINGS IN THE SOFTWARE. + +-var formatRegExp = /%[sdj%]/g; +-exports.format = function(f) { +- if (!isString(f)) { +- var objects = []; +- for (var i = 0; i < arguments.length; i++) { +- objects.push(inspect(arguments[i])); +- } +- return objects.join(' '); +- } +- +- var i = 1; +- var args = arguments; +- var len = args.length; +- var str = String(f).replace(formatRegExp, function(x) { +- if (x === '%%') return '%'; +- if (i >= len) return x; +- switch (x) { +- case '%s': return String(args[i++]); +- case '%d': return Number(args[i++]); +- case '%j': +- try { +- return JSON.stringify(args[i++]); +- } catch (_) { +- return '[Circular]'; +- } +- default: +- return x; +- } +- }); +- for (var x = args[i]; i < len; x = args[++i]) { +- if (isNull(x) || !isObject(x)) { +- str += ' ' + x; +- } else { +- str += ' ' + inspect(x); +- } +- } +- return str; +-}; +- +- +-// Mark that a method should not be used. +-// Returns a modified function which warns once by default. +-// If --no-deprecation is set, then it is a no-op. +-exports.deprecate = function(fn, msg) { +- // Allow for deprecating things in the process of starting up. +- if (isUndefined(global.process)) { +- return function() { +- return exports.deprecate(fn, msg).apply(this, arguments); +- }; +- } +- +- if (process.noDeprecation === true) { +- return fn; +- } +- +- var warned = false; +- function deprecated() { +- if (!warned) { +- if (process.throwDeprecation) { +- throw new Error(msg); +- } else if (process.traceDeprecation) { +- console.trace(msg); +- } else { +- console.error(msg); +- } +- warned = true; +- } +- return fn.apply(this, arguments); +- } +- +- return deprecated; +-}; +- +- +-var debugs = {}; +-var debugEnviron; +-exports.debuglog = function(set) { +- if (isUndefined(debugEnviron)) +- debugEnviron = process.env.NODE_DEBUG || ''; +- set = set.toUpperCase(); +- if (!debugs[set]) { +- if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { +- var pid = process.pid; +- debugs[set] = function() { +- var msg = exports.format.apply(exports, arguments); +- console.error('%s %d: %s', set, pid, msg); +- }; +- } else { +- debugs[set] = function() {}; +- } +- } +- return debugs[set]; +-}; +- +- +-/** +- * 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 {Object} opts Optional options object that alters the output. +- */ +-/* legacy: obj, showHidden, depth, colors*/ +-function inspect(obj, opts) { +- // default options +- var ctx = { +- seen: [], +- stylize: stylizeNoColor +- }; +- // legacy... +- if (arguments.length >= 3) ctx.depth = arguments[2]; +- if (arguments.length >= 4) ctx.colors = arguments[3]; +- if (isBoolean(opts)) { +- // legacy... +- ctx.showHidden = opts; +- } else if (opts) { +- // got an "options" object +- exports._extend(ctx, opts); +- } +- // set default options +- if (isUndefined(ctx.showHidden)) ctx.showHidden = false; +- if (isUndefined(ctx.depth)) ctx.depth = 2; +- if (isUndefined(ctx.colors)) ctx.colors = false; +- if (isUndefined(ctx.customInspect)) ctx.customInspect = true; +- if (ctx.colors) ctx.stylize = stylizeWithColor; +- return formatValue(ctx, obj, ctx.depth); +-} +-exports.inspect = inspect; +- +- +-// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +-inspect.colors = { +- 'bold' : [1, 22], +- 'italic' : [3, 23], +- 'underline' : [4, 24], +- 'inverse' : [7, 27], +- 'white' : [37, 39], +- 'grey' : [90, 39], +- 'black' : [30, 39], +- 'blue' : [34, 39], +- 'cyan' : [36, 39], +- 'green' : [32, 39], +- 'magenta' : [35, 39], +- 'red' : [31, 39], +- 'yellow' : [33, 39] +-}; +- +-// Don't use 'blue' not visible on cmd.exe +-inspect.styles = { +- 'special': 'cyan', +- 'number': 'yellow', +- 'boolean': 'yellow', +- 'undefined': 'grey', +- 'null': 'bold', +- 'string': 'green', +- 'date': 'magenta', +- // "name": intentionally not styling +- 'regexp': 'red' +-}; +- +- +-function stylizeWithColor(str, styleType) { +- var style = inspect.styles[styleType]; +- +- if (style) { +- return '\u001b[' + inspect.colors[style][0] + 'm' + str + +- '\u001b[' + inspect.colors[style][1] + 'm'; +- } else { +- return str; +- } +-} +- +- +-function stylizeNoColor(str, styleType) { +- return str; +-} +- +- +-function arrayToHash(array) { +- var hash = {}; +- +- array.forEach(function(val, idx) { +- hash[val] = true; +- }); +- +- return hash; +-} +- +- +-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 (ctx.customInspect && +- value && +- isFunction(value.inspect) && +- // 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)) { +- var ret = value.inspect(recurseTimes, ctx); +- if (!isString(ret)) { +- ret = formatValue(ctx, ret, recurseTimes); +- } +- return ret; +- } +- +- // Primitive types cannot have properties +- var primitive = formatPrimitive(ctx, value); +- if (primitive) { +- return primitive; +- } +- +- // Look up the keys of the object. +- var keys = Object.keys(value); +- var visibleKeys = arrayToHash(keys); +- +- if (ctx.showHidden) { +- keys = Object.getOwnPropertyNames(value); +- } +- +- // Some type of object without properties can be shortcutted. +- if (keys.length === 0) { +- if (isFunction(value)) { +- var name = value.name ? ': ' + value.name : ''; +- return ctx.stylize('[Function' + name + ']', 'special'); +- } +- if (isRegExp(value)) { +- return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); +- } +- if (isDate(value)) { +- return ctx.stylize(Date.prototype.toString.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 (isFunction(value)) { +- var n = value.name ? ': ' + value.name : ''; +- base = ' [Function' + n + ']'; +- } +- +- // 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)) { +- base = ' ' + 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) { +- if (isUndefined(value)) +- return ctx.stylize('undefined', 'undefined'); +- if (isString(value)) { +- var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') +- .replace(/'/g, "\\'") +- .replace(/\\"/g, '"') + '\''; +- return ctx.stylize(simple, 'string'); +- } +- if (isNumber(value)) { +- // Format -0 as '-0'. Strict equality won't distinguish 0 from -0, +- // so instead we use the fact that 1 / -0 < 0 whereas 1 / 0 > 0 . +- if (value === 0 && 1 / value < 0) +- return ctx.stylize('-0', 'number'); +- return ctx.stylize('' + value, 'number'); +- } +- if (isBoolean(value)) +- return ctx.stylize('' + value, 'boolean'); +- // For some reason typeof null is "object", so special case here. +- if (isNull(value)) +- 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 (hasOwnProperty(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, desc; +- desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; +- if (desc.get) { +- if (desc.set) { +- str = ctx.stylize('[Getter/Setter]', 'special'); +- } else { +- str = ctx.stylize('[Getter]', 'special'); +- } +- } else { +- if (desc.set) { +- str = ctx.stylize('[Setter]', 'special'); +- } +- } +- if (!hasOwnProperty(visibleKeys, key)) { +- name = '[' + key + ']'; +- } +- if (!str) { +- if (ctx.seen.indexOf(desc.value) < 0) { +- if (isNull(recurseTimes)) { +- str = formatValue(ctx, desc.value, null); +- } else { +- str = formatValue(ctx, desc.value, 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 (isUndefined(name)) { +- 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.replace(/\u001b\[\d\d?m/g, '').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]; +-} +- +- + // NOTE: These type checking functions intentionally don't use `instanceof` + // because it is fragile and can be easily faked with `Object.create()`. + function isArray(ar) { +@@ -522,166 +98,10 @@ function isPrimitive(arg) { + exports.isPrimitive = isPrimitive; + + function isBuffer(arg) { +- return arg instanceof Buffer; ++ return Buffer.isBuffer(arg); + } + exports.isBuffer = isBuffer; + + function objectToString(o) { + return Object.prototype.toString.call(o); +-} +- +- +-function pad(n) { +- return n < 10 ? '0' + n.toString(10) : n.toString(10); +-} +- +- +-var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', +- 'Oct', 'Nov', 'Dec']; +- +-// 26 Feb 16:19:34 +-function timestamp() { +- var d = new Date(); +- var time = [pad(d.getHours()), +- pad(d.getMinutes()), +- pad(d.getSeconds())].join(':'); +- return [d.getDate(), months[d.getMonth()], time].join(' '); +-} +- +- +-// log is just a thin wrapper to console.log that prepends a timestamp +-exports.log = function() { +- console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +-}; +- +- +-/** +- * Inherit the prototype methods from one constructor into another. +- * +- * The Function.prototype.inherits from lang.js rewritten as a standalone +- * function (not on Function.prototype). NOTE: If this file is to be loaded +- * during bootstrapping this function needs to be rewritten using some native +- * functions as prototype setup using normal JavaScript does not work as +- * expected during bootstrapping (see mirror.js in r114903). +- * +- * @param {function} ctor Constructor function which needs to inherit the +- * prototype. +- * @param {function} superCtor Constructor function to inherit prototype from. +- */ +-exports.inherits = function(ctor, superCtor) { +- ctor.super_ = superCtor; +- ctor.prototype = Object.create(superCtor.prototype, { +- constructor: { +- value: ctor, +- enumerable: false, +- writable: true, +- configurable: true +- } +- }); +-}; +- +-exports._extend = function(origin, add) { +- // Don't do anything if add isn't an object +- if (!add || !isObject(add)) return origin; +- +- var keys = Object.keys(add); +- var i = keys.length; +- while (i--) { +- origin[keys[i]] = add[keys[i]]; +- } +- return origin; +-}; +- +-function hasOwnProperty(obj, prop) { +- return Object.prototype.hasOwnProperty.call(obj, prop); +-} +- +- +-// Deprecated old stuff. +- +-exports.p = exports.deprecate(function() { +- for (var i = 0, len = arguments.length; i < len; ++i) { +- console.error(exports.inspect(arguments[i])); +- } +-}, 'util.p: Use console.error() instead'); +- +- +-exports.exec = exports.deprecate(function() { +- return require('child_process').exec.apply(this, arguments); +-}, 'util.exec is now called `child_process.exec`.'); +- +- +-exports.print = exports.deprecate(function() { +- for (var i = 0, len = arguments.length; i < len; ++i) { +- process.stdout.write(String(arguments[i])); +- } +-}, 'util.print: Use console.log instead'); +- +- +-exports.puts = exports.deprecate(function() { +- for (var i = 0, len = arguments.length; i < len; ++i) { +- process.stdout.write(arguments[i] + '\n'); +- } +-}, 'util.puts: Use console.log instead'); +- +- +-exports.debug = exports.deprecate(function(x) { +- process.stderr.write('DEBUG: ' + x + '\n'); +-}, 'util.debug: Use console.error instead'); +- +- +-exports.error = exports.deprecate(function(x) { +- for (var i = 0, len = arguments.length; i < len; ++i) { +- process.stderr.write(arguments[i] + '\n'); +- } +-}, 'util.error: Use console.error instead'); +- +- +-exports.pump = exports.deprecate(function(readStream, writeStream, callback) { +- var callbackCalled = false; +- +- function call(a, b, c) { +- if (callback && !callbackCalled) { +- callback(a, b, c); +- callbackCalled = true; +- } +- } +- +- readStream.addListener('data', function(chunk) { +- if (writeStream.write(chunk) === false) readStream.pause(); +- }); +- +- writeStream.addListener('drain', function() { +- readStream.resume(); +- }); +- +- readStream.addListener('end', function() { +- writeStream.end(); +- }); +- +- readStream.addListener('close', function() { +- call(); +- }); +- +- readStream.addListener('error', function(err) { +- writeStream.end(); +- call(err); +- }); +- +- writeStream.addListener('error', function(err) { +- readStream.destroy(); +- call(err); +- }); +-}, 'util.pump(): Use readableStream.pipe() instead'); +- +- +-var uv; +-exports._errnoException = function(err, syscall) { +- if (isUndefined(uv)) uv = process.binding('uv'); +- var errname = uv.errname(err); +- var e = new Error(syscall + ' ' + errname); +- e.code = errname; +- e.errno = errname; +- e.syscall = syscall; +- return e; +-}; ++} \ No newline at end of file diff --git a/node_modules/core-util-is/lib/util.js b/node_modules/core-util-is/lib/util.js new file mode 100644 index 00000000..ff4c851c --- /dev/null +++ b/node_modules/core-util-is/lib/util.js @@ -0,0 +1,107 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. + +function isArray(arg) { + if (Array.isArray) { + return Array.isArray(arg); + } + return objectToString(arg) === '[object Array]'; +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +exports.isBuffer = Buffer.isBuffer; + +function objectToString(o) { + return Object.prototype.toString.call(o); +} diff --git a/node_modules/core-util-is/package.json b/node_modules/core-util-is/package.json new file mode 100644 index 00000000..a9f2e398 --- /dev/null +++ b/node_modules/core-util-is/package.json @@ -0,0 +1,62 @@ +{ + "_from": "core-util-is@~1.0.0", + "_id": "core-util-is@1.0.2", + "_inBundle": false, + "_integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "_location": "/core-util-is", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "core-util-is@~1.0.0", + "name": "core-util-is", + "escapedName": "core-util-is", + "rawSpec": "~1.0.0", + "saveSpec": null, + "fetchSpec": "~1.0.0" + }, + "_requiredBy": [ + "/readable-stream" + ], + "_resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "_shasum": "b5fd54220aa2bc5ab57aab7140c940754503c1a7", + "_spec": "core-util-is@~1.0.0", + "_where": "C:\\Users\\rin\\Desktop\\final\\node_modules\\readable-stream", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "bugs": { + "url": "https://github.com/isaacs/core-util-is/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "The `util.is*` functions introduced in Node v0.12.", + "devDependencies": { + "tap": "^2.3.0" + }, + "homepage": "https://github.com/isaacs/core-util-is#readme", + "keywords": [ + "util", + "isBuffer", + "isArray", + "isNumber", + "isString", + "isRegExp", + "isThis", + "isThat", + "polyfill" + ], + "license": "MIT", + "main": "lib/util.js", + "name": "core-util-is", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/core-util-is.git" + }, + "scripts": { + "test": "tap test.js" + }, + "version": "1.0.2" +} diff --git a/node_modules/core-util-is/test.js b/node_modules/core-util-is/test.js new file mode 100644 index 00000000..1a490c65 --- /dev/null +++ b/node_modules/core-util-is/test.js @@ -0,0 +1,68 @@ +var assert = require('tap'); + +var t = require('./lib/util'); + +assert.equal(t.isArray([]), true); +assert.equal(t.isArray({}), false); + +assert.equal(t.isBoolean(null), false); +assert.equal(t.isBoolean(true), true); +assert.equal(t.isBoolean(false), true); + +assert.equal(t.isNull(null), true); +assert.equal(t.isNull(undefined), false); +assert.equal(t.isNull(false), false); +assert.equal(t.isNull(), false); + +assert.equal(t.isNullOrUndefined(null), true); +assert.equal(t.isNullOrUndefined(undefined), true); +assert.equal(t.isNullOrUndefined(false), false); +assert.equal(t.isNullOrUndefined(), true); + +assert.equal(t.isNumber(null), false); +assert.equal(t.isNumber('1'), false); +assert.equal(t.isNumber(1), true); + +assert.equal(t.isString(null), false); +assert.equal(t.isString('1'), true); +assert.equal(t.isString(1), false); + +assert.equal(t.isSymbol(null), false); +assert.equal(t.isSymbol('1'), false); +assert.equal(t.isSymbol(1), false); +assert.equal(t.isSymbol(Symbol()), true); + +assert.equal(t.isUndefined(null), false); +assert.equal(t.isUndefined(undefined), true); +assert.equal(t.isUndefined(false), false); +assert.equal(t.isUndefined(), true); + +assert.equal(t.isRegExp(null), false); +assert.equal(t.isRegExp('1'), false); +assert.equal(t.isRegExp(new RegExp()), true); + +assert.equal(t.isObject({}), true); +assert.equal(t.isObject([]), true); +assert.equal(t.isObject(new RegExp()), true); +assert.equal(t.isObject(new Date()), true); + +assert.equal(t.isDate(null), false); +assert.equal(t.isDate('1'), false); +assert.equal(t.isDate(new Date()), true); + +assert.equal(t.isError(null), false); +assert.equal(t.isError({ err: true }), false); +assert.equal(t.isError(new Error()), true); + +assert.equal(t.isFunction(null), false); +assert.equal(t.isFunction({ }), false); +assert.equal(t.isFunction(function() {}), true); + +assert.equal(t.isPrimitive(null), true); +assert.equal(t.isPrimitive(''), true); +assert.equal(t.isPrimitive(0), true); +assert.equal(t.isPrimitive(new Date()), false); + +assert.equal(t.isBuffer(null), false); +assert.equal(t.isBuffer({}), false); +assert.equal(t.isBuffer(new Buffer(0)), true); diff --git a/node_modules/csv-parse/CHANGELOG.md b/node_modules/csv-parse/CHANGELOG.md new file mode 100644 index 00000000..10b7c687 --- /dev/null +++ b/node_modules/csv-parse/CHANGELOG.md @@ -0,0 +1,651 @@ + +# Changelog + +## Todo + +Please join and contribute: + +* `skip_lines_with_empty_values`: rename to skip_records_with_empty_values (easy) +* `skip_lines_with_error`: rename to skip_records_with_error (easy) +* `relax`: rename to relax_quotes_when_unquoted (easy) +* `max_comment_size`: new option (medium) +* promise: new API module (medium) +* errors: finish normalisation of all errors (easy) +* encoding: new encoding_input and encoding_output options (medium) +* context: isolate info properties at context root (easy) +* context: merge record, raw, context, info, error into a single object (medium) +* relax_column_count: rename INCONSISTENT_RECORD_LENGTH to RECORD_INCONSISTENT_FIELDS_LENGTH (easy) +* relax_column_count: rename RECORD_DONT_MATCH_COLUMNS_LENGTH to RECORD_INCONSISTENT_COLUMNS (easy) + +## Version 4.15.3 + +* feat: lib/browser compatibility with ES5 + +## Version 4.15.2 + +* docs: browser demo fix #302 +* fix: browserify export parse instead of stringify + +## Version 4.15.1 + +* fix: skip_empty_lines don't interfere with from_line + +## Version 4.15.0 + +* feat: new ignore_last_delimiters option, solve #193 +* feat: generate browser compatible lib +* refactor: rename raw to record +* docs: comment about trimable chars +* refactor: move isCharTrimable + +## Version 4.14.2 + +* fix(skip_lines_with_error): work with relax_column_count (#303) +* sample: async iterator +* sample: promises + +## Version 4.14.1 + +* package: latest dependencies +* ts: enable strict mode +* package: mocha inside package declaration + +## Version 4.14.0 + +* on_record: expose info.error when relax_column_count is activated +* raw: move tests +* package: latest dependencies + +## Version 4.13.1 + +* encoding: buffer, detection and options samples +* encoding: return buffer when null or false +* encoding: support boolean values +* api: remove commented code + +## Version 4.13.0 + +New features: +* encoding: auto-detect from the bom +* encoding: new option +* bom: multi bom encoding + +Fixes & enhancements: +* delimiter: fix buffer size computation +* quote: compatibility with buffer size +* api: partial cache for needMoreData +* escape: support multiple characters +* quote: support multiple characters +* api: fix internal argument name + +## Version 4.12.0 + +New feature: +* ts: error types +* ts: support camelcase options (fix #287) + +## Version 4.11.1 + +New feature: +* escape: disabled when null or false + +Project management: +* travis: test node version 14 + +## Version 4.11 + +Project management: +* mistake in the release + +## Version 4.10.1 + +Minor improvements: +* columns_duplicates_to_array: error and type + +## Version 4.10.0 + +New feature: +* columns_duplicates_to_array: new option + +Project management: +* samples: new file recipie + +## Version 4.9.1 + +Minor improvements: +* delimiter: update ts definition +* delimiter: new sample + +## Version 4.9.0 + +New Feature: +* delimiter: accept multiple values + +## Version 4.8.9 + +Fix: +* sync: disregard emitted null records + +New Feature: +* trim: support form feed character + +Minor improvements: +* src: cache length in loops +* trim: new sample +* to_line: simple sample +* comment: simple sample +* bom: sample with hidden bom +* bom: test behavior with the column option + +## Version 4.8.8 + +* api: fix regression in browser environments + +## Version 4.8.7 + +* api: fix input string with output stream + +## Version 4.8.6 + +* on_record: catch and handle user errors + +## Version 4.8.5 + +* ts: fix `types` declaration + +## Version 4.8.4 + +* ts: fix `types` declaration to a single file + +## Version 4.8.3 + +* `errors`: handle undefined captureStackTrace + +## Version 4.8.2 + +* `relax_column_count`: ts definitions for less and more + +## Version 4.8.1 + +* package: move pad dependency to dev + +## Version 4.8.0 + +* `relax_column_count`: new less and more options +* columns: skip empty records before detecting headers +* errors: rename `CSV_INCONSISTENT_RECORD_LENGTH` +* errors: rename `CSV_RECORD_DONT_MATCH_COLUMNS_LENGTH` + +## Version 4.7.0 + +New Feature: +* `on_record`: user function to alter and filter records + +Minor improvements: +* test: ensure every sample is valid +* `from_line`: honours inferred column names +* `from_line`: new sample +* errors: expose `CSV_INVALID_ARGUMENT` +* errors: expose `CSV_INVALID_COLUMN_DEFINITION` +* errors: expose `CSV_OPTION_COLUMNS_MISSING_NAME` +* errors: expose `CSV_INVALID_OPTION_BOM` +* errors: expose `CSV_INVALID_OPTION_CAST` +* errors: expose `CSV_INVALID_OPTION_CAST_DATE` +* errors: expose `CSV_INVALID_OPTION_COLUMNS` +* errors: expose `CSV_INVALID_OPTION_COMMENT` +* errors: expose `CSV_INVALID_OPTION_DELIMITER` +* error: fix call to supper + +Project management: +* package: contributing +* package: code of conduct + +## Version 4.6.5 + +* context: column is null when cast force the context creation, fix #260 + +## Version 4.6.4 + +* errors: don't stringify/parse undefined and null values +* errors: expose `CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE` +* errors: expose `CSV_MAX_RECORD_SIZE` + +## Version 4.6.3 + +* lint: integrate eslint + +## Version 4.6.2 + +* context: null column when columns number inferior to record length + +## Version 4.6.1 + +* src: set const in for loop + +## Version 4.6.0 + +* `skip_lines_with_empty_values`: handle non string value +* errors: add context information +* tests: new error assertion framework +* buffer: serialize to json as string +* errors: expose `INVALID_OPENING_QUOTE` + +## Version 4.5.0 + +* errors: start normalizing errors with unique codes and context +* errors: expose `CSV_INVALID_CLOSING_QUOTE` +* errors: expose `CSV_QUOTE_NOT_CLOSED` +* errors: expose `CSV_INVALID_RECORD_LENGTH_DONT_PREVIOUS_RECORDS` +* errors: expose `CSV_INVALID_RECORD_LENGTH_DONT_MATCH_COLUMNS` +* errors: expose `CSV_INVALID_COLUMN_MAPPING` + +## Version 4.4.7 + +* travis: remove node.js 8 and add 12 +* destroy: test inside readable event + +## Version 4.4.6 + +* security: remove regexp vulnerable to DOS in cast option, npm report 69742 + +## Version 4.4.5 + +* ts: add buffer as allowed type for input, fix #248 + +## Version 4.4.4 + +* package: latest dependencies +* bom: detection when buffer smaller than bom +* package: remove deprecated `@types/should` dependency +* package: update file path + +## Version 4.4.3 + +* package: fix files declaration + +## Version 4.4.2 + +* `bom`: parsing for BOM character #239 +* ts: add sync definition +* package: replace npm ignore with file field + +## Version 4.4.1 + +Fix: +* `columns`: allows returning an array of string, undefined, null or false + +## Version 4.4.0 + +New features: +* options: new `bom` option + +## Version 4.3.4 + +* `columns`: enrich error message when provided as literal object +* `cast`: handle undefined columns +* `skip_lines_with_error`: new sample + +## Version 4.3.3 + +Fix: +columns: fix es5 generation + +## Version 4.3.2 + +Fix: +* columns: immutable option + +## Version 4.3.1 + +Minor enhancements: +* ts: distribute definitions with es5 +* ts: unused MatcherFunc type + +Project management: +* babel: include .babelrc to git + +## Version 4.3.0 + +New features: +* `objname`: accept a buffer + +Minor enhancements: +* `to_line`: validation refinements +* `trim`, ltrim, rtrim: validation refinements +* `to`: validation refinements +* `from_line`: validation refinements +* `objname`: validation refinements +* `from`: validation refinements +* `escape`: validation refinements +* `skip_empty_lines`: validation refinements +* `skip_lines_with_empty_values`: validation refinements +* `skip_lines_with_error`: validation refinements +* `relax_column_count`: validation refinements +* `relax`: validation refinements +* `delimiter`: validation refinements +* `max_record_size`: validation refinements + +## Version 4.2.0 + +Fix: +* `record_delimiter`: fix multi bytes with `skip_empty_lines` and `from_line` +* `rtrim`: accept tab + +## Version 4.1.0 + +New features: +* options: accept snake case and camel case +* `cast`: dont call cast for non column-mappable fields + +Fix: +* `cast`: ensure column is a string and not an array +* stream: handle empty input streams +* `cast`: function may return non-string values +* stream: pass stream options without modification + +## Version 4.0.1 + +Fix: +* `relax_column_count`: handle records with more columns + +## Version 4.0.0 + +This is a complete rewrite based with a Buffer implementation. There are no major breaking changes but it introduces multiple minor breaking changes: + +* option `rowDelimiter` is now `record_delimiter` +* option `max_limit_on_data_read` is now `max_record_size` +* drop the record event +* normalise error message as `{error type}: {error description}` +* state values are now isolated into the `info` object +* `count` is now `info.records` +* `lines` is now `info.lines` +* `empty_line_count` is now `info.empty_lines` +* `skipped_line_count` is now `info.invalid_field_length` +* `context.count` is cast function is now `context.records` +* drop support for deprecated options `auto_parse` and `auto_parse_date` +* drop emission of the `record` event +* in `raw` option, the `row` property is renamed `record` +* default value of `max_record_size` is now `0` (unlimited) +* remove the `record` event, use the `readable` event and `this.read()` instead + +New features: +* new options `info`, `from_line` and `to_line` +* `trim`: respect `ltrim` and `rtrim` when defined +* `delimiter`: may be a Buffer +* `delimiter`: handle multiple bytes/characters +* callback: export info object as third argument +* `cast`: catch error in user functions +* ts: mark info as readonly with required properties +* `comment_lines`: count the number of commented lines with no records +* callback: pass undefined instead of null + +API management: +* Multiple tests have been rewritten with easier data sample +* Source code is now written in ES6 instead of CoffeeScript +* package: switch to MIT license + +## Version 3.2.0 + +* `max_limit_on_data_read`: update error msg +* src: simplify detection for more data +* lines: test empty line account for 1 line +* options: extract default options +* package: add a few keywords +* src: precompute escapeIsQuote +* travis: test against Node.js 11 + +## Version 3.1.3 + +* `rowDelimiter`: fix overlap with delimiter +* internal: rename rowDelimiterLength to `rowDelimiterMaxLength` + +## Version 3.1.2 + +* readme: fix links to project website + +## Version 3.1.1 + +* src: generate code + +## Version 3.1.0 + +* package: move to csv.js.org +* samples: new cast sample +* package: upgrade to babel 7 +* samples: new mixed api samples +* samples: new column script +* samples: update syntax +* package: improve ignore files + +## Version 3.0.0 + +Breaking changes: +* `columns`: skip empty values when null, false or undefined + +Cleanup: +* sync: refactor internal variables +* index: use destructuring assignment for deps + +## Version 2.5.0 + +* typescript: make definition header more relevant + +## Version 2.4.1 + +* `to`: ignore future records when to is reached + +## Version 2.4.0 + +* `trim`: after and before quote +* tests: compatibility with Node.js 10 +* `trim`: handle quote followed by escape +* parser: set nextChar to null instead of empty +* travis: run against node 8 and 10 + +## Version 2.3.0 + +* `cast`: pass the header property +* `auto_parse`: deprecated message on tests +* `cast`: inject lines property + +## Version 2.2.0 + +* `cast`: deprecate `auto_parse` +* `auto_parse`: function get context as second argument + +## Version 2.1.0 + +* `skip_lines_with_error`: DRYed implementation +* `skip_lines_with_error`: Go process the next line on error +* events: register and write not blocking +* test: prefix names by group membership +* events: emit record +* raw: test to ensure it preserve columns +* package: latest dependencies (28 march 2018) +* raw: ensure tests call and success +* package: ignore npm and yarn lock files +* sync: handle errors on last line + +## Version 2.0.4 + +* package: move babel to dev dependencies + +## Version 2.0.3 + +* package: es5 backward compatibility +* package: ignore yarn lock file + +## Version 2.0.2 + +* package: only remove js files in lib +* source: remove unreferenced variables #179 +* package: start running tests in preversion +* package: new release workflow + +## 2.0.0 + +This major version use CoffeeScript 2 which produces a modern JavaScript syntax +(ES6, or ES2015 and later) and break the compatibility with versions of Node.js +lower than 7.6 as well as the browsers. It is however stable in term of API. + +* package: use CoffeeScript 2 + +## v1.3.3 + +* package: revert to CoffeeScript 1 + +## v1.3.2 + +Irrelevant release, forgot to generate the coffee files. + +## v1.3.1 + +* package: preserve compatibility with Node.js < 7.6 + +## v1.3.0 + +* options: `auto_parse` as a user function +* options: `auto_parse_date` as a user function +* test: should require handled by mocha +* package: coffeescript 2 and use semver tilde +* options: ensure objectMode is cloned + +## v1.2.4 + +* `relax_column_count`: honors count while preserving skipped_line_count +* api: improve argument validation + +## v1.2.3 + +* sync: catch err on write + +## v1.2.2 + +* relax: handle double quote + +## v1.2.1 + +* src: group state variable initialisation +* package: update repo url +* quote: disabled when null, false or empty +* src: remove try/catch +* src: optimize estimation for row delimiter length +* lines: improve tests +* src: use in instead of multiple is +* src: string optimization + +## v1.2.0 + +* skip default row delimiters when quoted #58 +* `auto_parse`: cleaner implementation +* src: isolate internal variables + +## v1.1.12 + +* options: new to and from options + +## v1.1.11 + +* `rowDelimiters`: fix all last month issues + +## v1.1.10 + +* regression with trim and last empty field #123 + +## V1.1.9 + +* `rowDelimiter`: simplification +* fix regression when trim and skip_empty_lines activated #122 +* `auto_parse` = simplify internal function + +## V1.1.8 + +* src: trailing whitespace and empty headers #120 +* `rowDelimiter`: adding support for multiple row delimiters #119 +* Remove unnecessary argument: `Parser.prototype.__write` #114 + +## v1.1.7 + +* `skip_lines_with_empty_values`: support space and tabs #108 +* test: remove coverage support +* test: group by api, options and properties +* `skip_lines_with_empty_values` option +* write test illustrating column function throwing an error #98 +* added ability to skip columns #50 + +## v1.1.6 + +* reduce substr usage +* new raw option + +## v1.1.5 + +* `empty_line_count` counter and renamed skipped to `skipped_line_count` +* skipped line count + +## v1.1.4 + +* avoid de-optimisation due to wrong charAt index #103 +* parser writing before assigning listeners + +## v1.1.3 + +* `columns`: stop on column count error #100 + +## v1.1.2 + +* make the parser more sensitive to input +* test case about the chunks of multiple chars without quotes +* test about data emission with newline + +## v1.1.1 + +* stream: call end if data instance of buffer +* travis: add nodejs 6 +* `columns`: fix line error #97 + +## v1.1.0 + +* `relax_column_count`: default to false (strict) + +## v1.0.6 + +* `relax_column_count`: backward compatibility for 1.0.x +* `relax_column_count`: introduce new option +* `columns`: detect column length and fix lines count + +## v1.0.5 + +* fix quotes tests that used data with inconsistent number of #73 +* add tests for inconsistent number of columns #73 +* throw an error when a column is missing #73 +* travis: test nodejs versions 4, 5 +* `max_limit_on_data_read`: new option +* removing the duplicate files in test and samples #86 +* option argument to accept the number of bytes can be read #86 +* avoid unwanted parsing when there is wrong delimiter or row delimiter #86 + +## v1.0.4 + +* sync: support `objname` + +## v1.0.3 + +* sync: please older versions of node.js +* sync: new sample + +## v1.0.2 + +* sync: new module +* removed global variable record on stream.js example #70 + +## v1.0.1 + +* api: accept buffer with 3 arguments #57 +* package: latest dependencies +* spectrum: bypass regression test + +## v1.0.0 + +* `auto_parse`: work on all fields, rename to “is_*†+* `auto_parse`: simplify test diff --git a/node_modules/csv-parse/LICENSE b/node_modules/csv-parse/LICENSE new file mode 100644 index 00000000..918eaf05 --- /dev/null +++ b/node_modules/csv-parse/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2010 Adaltas + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/csv-parse/README.md b/node_modules/csv-parse/README.md new file mode 100644 index 00000000..9d8c28e9 --- /dev/null +++ b/node_modules/csv-parse/README.md @@ -0,0 +1,27 @@ + +# CSV Parser for Node.js + +[](https://travis-ci.org/#!/adaltas/node-csv-parse) [](https://www.npmjs.com/package/csv-parse) [](https://www.npmjs.com/package/csv-parse) + +Part of the [CSV module](https://csv.js.org/), this project is a parser converting CSV text input into arrays or objects. It implements the Node.js [`stream.Transform` API](http://nodejs.org/api/stream.html#stream_class_stream_transform). It also provides a simple callback-based API for convenience. It is both extremely easy to use and powerful. It was first released in 2010 and is used against big data sets by a large community. + +## Documentation + +* [Project homepage](http://csv.js.org/parse/) +* [API](http://csv.js.org/parse/api/) +* [Options](http://csv.js.org/parse/options/) +* [Info properties](http://csv.js.org/parse/info/) +* [Common errors](http://csv.js.org/parse/errors/) +* [Examples](http://csv.js.org/project/examples/) + +## Features + +* Follow the Node.js streaming API +* Simplicity with the optional callback API +* Support delimiters, quotes, escape characters and comments +* Line breaks discovery +* Support big datasets +* Complete test coverage and samples for inspiration +* No external dependencies +* Work nicely with the [csv-generate](https://csv.js.org/generate/), [stream-transform](https://csv.js.org/transform/) and [csv-stringify](https://csv.js.org/stringify/) packages +* MIT License diff --git a/node_modules/csv-parse/lib/.DS_Store b/node_modules/csv-parse/lib/.DS_Store new file mode 100644 index 00000000..14c24fb7 Binary files /dev/null and b/node_modules/csv-parse/lib/.DS_Store differ diff --git a/node_modules/csv-parse/lib/ResizeableBuffer.js b/node_modules/csv-parse/lib/ResizeableBuffer.js new file mode 100644 index 00000000..467422c1 --- /dev/null +++ b/node_modules/csv-parse/lib/ResizeableBuffer.js @@ -0,0 +1,65 @@ + + +class ResizeableBuffer{ + constructor(size=100){ + this.size = size + this.length = 0 + this.buf = Buffer.alloc(size) + } + prepend(val){ + if(Buffer.isBuffer(val)){ + const length = this.length + val.length + if(length >= this.size){ + this.resize() + if(length >= this.size){ + throw Error('INVALID_BUFFER_STATE') + } + } + const buf = this.buf + this.buf = Buffer.alloc(this.size) + val.copy(this.buf, 0) + buf.copy(this.buf, val.length) + this.length += val.length + }else{ + const length = this.length++ + if(length === this.size){ + this.resize() + } + const buf = this.clone() + this.buf[0] = val + buf.copy(this.buf,1, 0, length) + } + } + append(val){ + const length = this.length++ + if(length === this.size){ + this.resize() + } + this.buf[length] = val + } + clone(){ + return Buffer.from(this.buf.slice(0, this.length)) + } + resize(){ + const length = this.length + this.size = this.size * 2 + const buf = Buffer.alloc(this.size) + this.buf.copy(buf,0, 0, length) + this.buf = buf + } + toString(encoding){ + if(encoding){ + return this.buf.slice(0, this.length).toString(encoding) + }else{ + return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)) + } + } + toJSON(){ + return this.toString('utf8') + } + reset(){ + this.length = 0 + } +} + +module.exports = ResizeableBuffer diff --git a/node_modules/csv-parse/lib/browser/index.js b/node_modules/csv-parse/lib/browser/index.js new file mode 100644 index 00000000..33fface4 --- /dev/null +++ b/node_modules/csv-parse/lib/browser/index.js @@ -0,0 +1,8090 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.parse = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i
](http://bl.ocks.org/mbostock/3048450)
+
+Binning groups discrete samples into a smaller number of consecutive, non-overlapping intervals. They are often used to visualize the distribution of numerical data as histograms.
+
+# d3.bin() · [Source](https://github.com/d3/d3-array/blob/master/src/bin.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+Constructs a new bin generator with the default settings.
+
+# bin(data) · [Source](https://github.com/d3/d3-array/blob/master/src/bin.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+Bins the given iterable of *data* samples. Returns an array of bins, where each bin is an array containing the associated elements from the input *data*. Thus, the `length` of the bin is the number of elements in that bin. Each bin has two additional attributes:
+
+* `x0` - the lower bound of the bin (inclusive).
+* `x1` - the upper bound of the bin (exclusive, except for the last bin).
+
+# bin.value([value]) · [Source](https://github.com/d3/d3-array/blob/master/src/bin.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+If *value* is specified, sets the value accessor to the specified function or constant and returns this bin generator. If *value* is not specified, returns the current value accessor, which defaults to the identity function.
+
+When bins are [generated](#_bin), the value accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default value accessor assumes that the input data are orderable (comparable), such as numbers or dates. If your data are not, then you should specify an accessor that returns the corresponding orderable value for a given datum.
+
+This is similar to mapping your data to values before invoking the bin generator, but has the benefit that the input data remains associated with the returned bins, thereby making it easier to access other fields of the data.
+
+# bin.domain([domain]) · [Source](https://github.com/d3/d3-array/blob/master/src/bin.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+If *domain* is specified, sets the domain accessor to the specified function or array and returns this bin generator. If *domain* is not specified, returns the current domain accessor, which defaults to [extent](#extent). The bin domain is defined as an array [*min*, *max*], where *min* is the minimum observable value and *max* is the maximum observable value; both values are inclusive. Any value outside of this domain will be ignored when the bins are [generated](#_bin).
+
+For example, if you are using the bin generator in conjunction with a [linear scale](https://github.com/d3/d3-scale/blob/master/README.md#linear-scales) `x`, you might say:
+
+```js
+var bin = d3.bin()
+ .domain(x.domain())
+ .thresholds(x.ticks(20));
+```
+
+You can then compute the bins from an array of numbers like so:
+
+```js
+var bins = bin(numbers);
+```
+
+If the default [extent](#extent) domain is used and the [thresholds](#bin_thresholds) are specified as a count (rather than explicit values), then the computed domain will be [niced](#nice) such that all bins are uniform width.
+
+Note that the domain accessor is invoked on the materialized array of [values](#bin_value), not on the input data array.
+
+# bin.thresholds([count]) · [Source](https://github.com/d3/d3-array/blob/master/src/bin.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
](https://observablehq.com/@d3/styled-axes)
+
+An axis consists of a [path element](https://www.w3.org/TR/SVG/paths.html#PathElement) of class “domain†representing the extent of the scale’s domain, followed by transformed [g elements](https://www.w3.org/TR/SVG/struct.html#Groups) of class “tick†representing each of the scale’s ticks. Each tick has a [line element](https://www.w3.org/TR/SVG/shapes.html#LineElement) to draw the tick line, and a [text element](https://www.w3.org/TR/SVG/text.html#TextElement) for the tick label. For example, here is a typical bottom-oriented axis:
+
+```html
+
](https://observablehq.com/@d3/mona-lisa-histogram)
+
+The d3-brush module implements brushing for mouse and touch events using [SVG](https://www.w3.org/TR/SVG/). Click and drag on the brush selection to translate the selection. Click and drag on one of the selection handles to move the corresponding edge (or edges) of the selection. Click and drag on the invisible overlay to define a new brush selection, or click anywhere within the brushable region while holding down the META (⌘) key. Holding down the ALT (⌥) key while moving the brush causes it to reposition around its center, while holding down SPACE locks the current brush size, allowing only translation.
+
+Brushes also support programmatic control. For example, you can listen to [*end* events](#brush-events), and then initiate a transition with [*brush*.move](#brush_move) to snap the brush selection to semantic boundaries:
+
+[
](https://observablehq.com/@d3/brush-snapping-transitions)
+
+Or you can have the brush recenter when you click outside the current selection:
+
+[
](https://observablehq.com/@d3/click-to-recenter-brush)
+
+## Installing
+
+If you use NPM, `npm install d3-brush`. Otherwise, download the [latest release](https://github.com/d3/d3-brush/releases/latest). You can load as a [standalone library](https://d3js.org/d3-brush.v1.min.js) or as part of [D3](https://github.com/d3/d3). ES modules, AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+[Try d3-brush in your browser.](https://observablehq.com/collection/@d3/d3-brush)
+
+## API Reference
+
+# d3.brush() · [Source](https://github.com/d3/d3-brush/blob/master/src/brush.js), [Examples](https://observablehq.com/@d3/brushable-scatterplot)
+
+Creates a new two-dimensional brush.
+
+# d3.brushX() · [Source](https://github.com/d3/d3-brush/blob/master/src/brush.js), [Examples](https://observablehq.com/@d3/focus-context)
+
+Creates a new one-dimensional brush along the *x*-dimension.
+
+# d3.brushY() · [Source](https://github.com/d3/d3-brush/blob/master/src/brush.js)
+
+Creates a new one-dimensional brush along the *y*-dimension.
+
+# brush(group) · [Source](https://github.com/d3/d3-brush/blob/master/src/brush.js), [Examples](https://observablehq.com/@d3/brushable-scatterplot-matrix)
+
+Applies the brush to the specified *group*, which must be a [selection](https://github.com/d3/d3-selection) of SVG [G elements](https://www.w3.org/TR/SVG/struct.html#Groups). This function is typically not invoked directly, and is instead invoked via [*selection*.call](https://github.com/d3/d3-selection#selection_call). For example, to render a brush:
+
+```js
+svg.append("g")
+ .attr("class", "brush")
+ .call(d3.brush().on("brush", brushed));
+```
+
+Internally, the brush uses [*selection*.on](https://github.com/d3/d3-selection#selection_on) to bind the necessary event listeners for dragging. The listeners use the name `.brush`, so you can subsequently unbind the brush event listeners as follows:
+
+```js
+group.on(".brush", null);
+```
+
+The brush also creates the SVG elements necessary to display the brush selection and to receive input events for interaction. You can add, remove or modify these elements as desired to change the brush appearance; you can also apply stylesheets to modify the brush appearance. The structure of a two-dimensional brush is as follows:
+
+```html
+
](https://observablehq.com/@d3/chord-diagram)
+
+## Installing
+
+If you use NPM, `npm install d3-chord`. Otherwise, download the [latest release](https://github.com/d3/d3-chord/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-chord.v2.min.js) or as part of [D3](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:
+
+```html
+
+
+
+```
+
+## API Reference
+
+# d3.chord() [<>](https://github.com/d3/d3-chord/blob/master/src/chord.js "Source")
+
+Constructs a new chord layout with the default settings.
+
+# chord(matrix) [<>](https://github.com/d3/d3-chord/blob/master/src/chord.js "Source")
+
+Computes the chord layout for the specified square *matrix* of size *n*×*n*, where the *matrix* represents the directed flow amongst a network (a complete digraph) of *n* nodes. The given *matrix* must be an array of length *n*, where each element *matrix*[*i*] is an array of *n* numbers, where each *matrix*[*i*][*j*] represents the flow from the *i*th node in the network to the *j*th node. Each number *matrix*[*i*][*j*] must be nonnegative, though it can be zero if there is no flow from node *i* to node *j*. From the [Circos tableviewer example](http://mkweb.bcgsc.ca/circos/guide/tables/):
+
+```js
+var matrix = [
+ [11975, 5871, 8916, 2868],
+ [ 1951, 10048, 2060, 6171],
+ [ 8010, 16145, 8090, 8045],
+ [ 1013, 990, 940, 6907]
+];
+```
+
+The return value of *chord*(*matrix*) is an array of *chords*, where each chord represents the combined bidirectional flow between two nodes *i* and *j* (where *i* may be equal to *j*) and is an object with the following properties:
+
+* `source` - the source subgroup
+* `target` - the target subgroup
+
+Each source and target subgroup is also an object with the following properties:
+
+* `startAngle` - the start angle in radians
+* `endAngle` - the end angle in radians
+* `value` - the flow value *matrix*[*i*][*j*]
+* `index` - the node index *i*
+
+The chords are typically passed to [d3.ribbon](#ribbon) to display the network relationships. The returned array includes only chord objects for which the value *matrix*[*i*][*j*] or *matrix*[*j*][*i*] is non-zero. Furthermore, the returned array only contains unique chords: a given chord *ij* represents the bidirectional flow from *i* to *j* *and* from *j* to *i*, and does not contain a duplicate chord *ji*; *i* and *j* are chosen such that the chord’s source always represents the larger of *matrix*[*i*][*j*] and *matrix*[*j*][*i*].
+
+The *chords* array also defines a secondary array of length *n*, *chords*.groups, where each group represents the combined outflow for node *i*, corresponding to the elements *matrix*[*i*][0 … *n* - 1], and is an object with the following properties:
+
+* `startAngle` - the start angle in radians
+* `endAngle` - the end angle in radians
+* `value` - the total outgoing flow value for node *i*
+* `index` - the node index *i*
+
+The groups are typically passed to [d3.arc](https://github.com/d3/d3-shape#arc) to produce a donut chart around the circumference of the chord layout.
+
+# chord.padAngle([angle]) [<>](https://github.com/d3/d3-chord/blob/master/src/chord.js "Source")
+
+If *angle* is specified, sets the pad angle between adjacent groups to the specified number in radians and returns this chord layout. If *angle* is not specified, returns the current pad angle, which defaults to zero.
+
+# chord.sortGroups([compare]) [<>](https://github.com/d3/d3-chord/blob/master/src/chord.js "Source")
+
+If *compare* is specified, sets the group comparator to the specified function or null and returns this chord layout. If *compare* is not specified, returns the current group comparator, which defaults to null. If the group comparator is non-null, it is used to sort the groups by their total outflow. See also [d3.ascending](https://github.com/d3/d3-array/blob/master/README.md#ascending) and [d3.descending](https://github.com/d3/d3-array/blob/master/README.md#descending).
+
+# chord.sortSubgroups([compare]) [<>](https://github.com/d3/d3-chord/blob/master/src/chord.js "Source")
+
+If *compare* is specified, sets the subgroup comparator to the specified function or null and returns this chord layout. If *compare* is not specified, returns the current subgroup comparator, which defaults to null. If the subgroup comparator is non-null, it is used to sort the subgroups corresponding to *matrix*[*i*][0 … *n* - 1] for a given group *i* by their total outflow. See also [d3.ascending](https://github.com/d3/d3-array/blob/master/README.md#ascending) and [d3.descending](https://github.com/d3/d3-array/blob/master/README.md#descending).
+
+# chord.sortChords([compare]) [<>](https://github.com/d3/d3-chord/blob/master/src/chord.js "Source")
+
+If *compare* is specified, sets the chord comparator to the specified function or null and returns this chord layout. If *compare* is not specified, returns the current chord comparator, which defaults to null. If the chord comparator is non-null, it is used to sort the [chords](#_chord) by their combined flow; this only affects the *z*-order of the chords. See also [d3.ascending](https://github.com/d3/d3-array/blob/master/README.md#ascending) and [d3.descending](https://github.com/d3/d3-array/blob/master/README.md#descending).
+
+# d3.ribbon() [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+Creates a new ribbon generator with the default settings.
+
+# ribbon(arguments…) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+Generates a ribbon for the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the ribbon generator’s accessor functions along with the `this` object. For example, with the default settings, a [chord object](#_chord) expected:
+
+```js
+var ribbon = d3.ribbon();
+
+ribbon({
+ source: {startAngle: 0.7524114, endAngle: 1.1212972, radius: 240},
+ target: {startAngle: 1.8617078, endAngle: 1.9842927, radius: 240}
+}); // "M164.0162810494058,-175.21032946354026A240,240,0,0,1,216.1595644740915,-104.28347273835429Q0,0,229.9158815306728,68.8381247563705A240,240,0,0,1,219.77316791012538,96.43523560788266Q0,0,164.0162810494058,-175.21032946354026Z"
+```
+
+Or equivalently if the radius is instead defined as a constant:
+
+```js
+var ribbon = d3.ribbon()
+ .radius(240);
+
+ribbon({
+ source: {startAngle: 0.7524114, endAngle: 1.1212972},
+ target: {startAngle: 1.8617078, endAngle: 1.9842927}
+}); // "M164.0162810494058,-175.21032946354026A240,240,0,0,1,216.1595644740915,-104.28347273835429Q0,0,229.9158815306728,68.8381247563705A240,240,0,0,1,219.77316791012538,96.43523560788266Q0,0,164.0162810494058,-175.21032946354026Z"
+```
+
+If the ribbon generator has a context, then the ribbon is rendered to this context as a sequence of path method calls and this function returns void. Otherwise, a path data string is returned.
+
+# ribbon.source([source]) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+If *source* is specified, sets the source accessor to the specified function and returns this ribbon generator. If *source* is not specified, returns the current source accessor, which defaults to:
+
+```js
+function source(d) {
+ return d.source;
+}
+```
+
+# ribbon.target([target]) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+If *target* is specified, sets the target accessor to the specified function and returns this ribbon generator. If *target* is not specified, returns the current target accessor, which defaults to:
+
+```js
+function target(d) {
+ return d.target;
+}
+```
+
+# ribbon.radius([radius]) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+If *radius* is specified, sets the source and target radius accessor to the specified function and returns this ribbon generator. If *radius* is not specified, returns the current source radius accessor, which defaults to:
+
+```js
+function radius(d) {
+ return d.radius;
+}
+```
+
+# ribbon.sourceRadius([radius]) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+If *radius* is specified, sets the source radius accessor to the specified function and returns this ribbon generator. If *radius* is not specified, returns the current source radius accessor, which defaults to:
+
+```js
+function radius(d) {
+ return d.radius;
+}
+```
+
+# ribbon.targetRadius([radius]) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+If *radius* is specified, sets the target radius accessor to the specified function and returns this ribbon generator. If *radius* is not specified, returns the current target radius accessor, which defaults to:
+
+```js
+function radius(d) {
+ return d.radius;
+}
+```
+
+By convention, the target radius in asymmetric chord diagrams is typically inset from the source radius, resulting in a gap between the end of the directed link and its associated group arc.
+
+# ribbon.startAngle([angle]) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+If *angle* is specified, sets the start angle accessor to the specified function and returns this ribbon generator. If *angle* is not specified, returns the current start angle accessor, which defaults to:
+
+```js
+function startAngle(d) {
+ return d.startAngle;
+}
+```
+
+The *angle* is specified in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.
+
+# ribbon.endAngle([angle]) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+If *angle* is specified, sets the end angle accessor to the specified function and returns this ribbon generator. If *angle* is not specified, returns the current end angle accessor, which defaults to:
+
+```js
+function endAngle(d) {
+ return d.endAngle;
+}
+```
+
+The *angle* is specified in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.
+
+# ribbon.padAngle([angle]) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+If *angle* is specified, sets the pad angle accessor to the specified function and returns this ribbon generator. If *angle* is not specified, returns the current pad angle accessor, which defaults to:
+
+```js
+function padAngle() {
+ return 0;
+}
+```
+
+The pad angle specifies the angular gap between adjacent ribbons.
+
+# ribbon.context([context]) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+If *context* is specified, sets the context and returns this ribbon generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated ribbon](#_ribbon) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated ribbon is returned. See also [d3-path](https://github.com/d3/d3-path).
+
+# d3.ribbonArrow() [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+Creates a new arrow ribbon generator with the default settings.
+
+# ribbonArrow.headRadius([radius]) [<>](https://github.com/d3/d3-chord/blob/master/src/ribbon.js "Source")
+
+If *radius* is specified, sets the arrowhead radius accessor to the specified function and returns this ribbon generator. If *radius* is not specified, returns the current arrowhead radius accessor, which defaults to:
+
+```js
+function headRadius() {
+ return 10;
+}
+```
diff --git a/node_modules/d3-chord/dist/d3-chord.js b/node_modules/d3-chord/dist/d3-chord.js
new file mode 100644
index 00000000..2bbc8977
--- /dev/null
+++ b/node_modules/d3-chord/dist/d3-chord.js
@@ -0,0 +1,284 @@
+// https://d3js.org/d3-chord/ v2.0.0 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-path')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-path'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}, global.d3));
+}(this, function (exports, d3Path) { 'use strict';
+
+var abs = Math.abs;
+var cos = Math.cos;
+var sin = Math.sin;
+var pi = Math.PI;
+var halfPi = pi / 2;
+var tau = pi * 2;
+var max = Math.max;
+var epsilon = 1e-12;
+
+function range(i, j) {
+ return Array.from({length: j - i}, (_, k) => i + k);
+}
+
+function compareValue(compare) {
+ return function(a, b) {
+ return compare(
+ a.source.value + a.target.value,
+ b.source.value + b.target.value
+ );
+ };
+}
+
+function chord() {
+ return chord$1(false, false);
+}
+
+function chordTranspose() {
+ return chord$1(false, true);
+}
+
+function chordDirected() {
+ return chord$1(true, false);
+}
+
+function chord$1(directed, transpose) {
+ var padAngle = 0,
+ sortGroups = null,
+ sortSubgroups = null,
+ sortChords = null;
+
+ function chord(matrix) {
+ var n = matrix.length,
+ groupSums = new Array(n),
+ groupIndex = range(0, n),
+ chords = new Array(n * n),
+ groups = new Array(n),
+ k = 0, dx;
+
+ matrix = Float64Array.from({length: n * n}, transpose
+ ? (_, i) => matrix[i % n][i / n | 0]
+ : (_, i) => matrix[i / n | 0][i % n]);
+
+ // Compute the scaling factor from value to angle in [0, 2pi].
+ for (let i = 0; i < n; ++i) {
+ let x = 0;
+ for (let j = 0; j < n; ++j) x += matrix[i * n + j] + directed * matrix[j * n + i];
+ k += groupSums[i] = x;
+ }
+ k = max(0, tau - padAngle * n) / k;
+ dx = k ? padAngle : tau / n;
+
+ // Compute the angles for each group and constituent chord.
+ {
+ let x = 0;
+ if (sortGroups) groupIndex.sort((a, b) => sortGroups(groupSums[a], groupSums[b]));
+ for (const i of groupIndex) {
+ const x0 = x;
+ if (directed) {
+ const subgroupIndex = range(~n + 1, n).filter(j => j < 0 ? matrix[~j * n + i] : matrix[i * n + j]);
+ if (sortSubgroups) subgroupIndex.sort((a, b) => sortSubgroups(a < 0 ? -matrix[~a * n + i] : matrix[i * n + a], b < 0 ? -matrix[~b * n + i] : matrix[i * n + b]));
+ for (const j of subgroupIndex) {
+ if (j < 0) {
+ const chord = chords[~j * n + i] || (chords[~j * n + i] = {source: null, target: null});
+ chord.target = {index: i, startAngle: x, endAngle: x += matrix[~j * n + i] * k, value: matrix[~j * n + i]};
+ } else {
+ const chord = chords[i * n + j] || (chords[i * n + j] = {source: null, target: null});
+ chord.source = {index: i, startAngle: x, endAngle: x += matrix[i * n + j] * k, value: matrix[i * n + j]};
+ }
+ }
+ groups[i] = {index: i, startAngle: x0, endAngle: x, value: groupSums[i]};
+ } else {
+ const subgroupIndex = range(0, n).filter(j => matrix[i * n + j] || matrix[j * n + i]);
+ if (sortSubgroups) subgroupIndex.sort((a, b) => sortSubgroups(matrix[i * n + a], matrix[i * n + b]));
+ for (const j of subgroupIndex) {
+ let chord;
+ if (i < j) {
+ chord = chords[i * n + j] || (chords[i * n + j] = {source: null, target: null});
+ chord.source = {index: i, startAngle: x, endAngle: x += matrix[i * n + j] * k, value: matrix[i * n + j]};
+ } else {
+ chord = chords[j * n + i] || (chords[j * n + i] = {source: null, target: null});
+ chord.target = {index: i, startAngle: x, endAngle: x += matrix[i * n + j] * k, value: matrix[i * n + j]};
+ if (i === j) chord.source = chord.target;
+ }
+ if (chord.source && chord.target && chord.source.value < chord.target.value) {
+ const source = chord.source;
+ chord.source = chord.target;
+ chord.target = source;
+ }
+ }
+ groups[i] = {index: i, startAngle: x0, endAngle: x, value: groupSums[i]};
+ }
+ x += dx;
+ }
+ }
+
+ // Remove empty chords.
+ chords = Object.values(chords);
+ chords.groups = groups;
+ return sortChords ? chords.sort(sortChords) : chords;
+ }
+
+ chord.padAngle = function(_) {
+ return arguments.length ? (padAngle = max(0, _), chord) : padAngle;
+ };
+
+ chord.sortGroups = function(_) {
+ return arguments.length ? (sortGroups = _, chord) : sortGroups;
+ };
+
+ chord.sortSubgroups = function(_) {
+ return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups;
+ };
+
+ chord.sortChords = function(_) {
+ return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._;
+ };
+
+ return chord;
+}
+
+var slice = Array.prototype.slice;
+
+function constant(x) {
+ return function() {
+ return x;
+ };
+}
+
+function defaultSource(d) {
+ return d.source;
+}
+
+function defaultTarget(d) {
+ return d.target;
+}
+
+function defaultRadius(d) {
+ return d.radius;
+}
+
+function defaultStartAngle(d) {
+ return d.startAngle;
+}
+
+function defaultEndAngle(d) {
+ return d.endAngle;
+}
+
+function defaultPadAngle() {
+ return 0;
+}
+
+function defaultArrowheadRadius() {
+ return 10;
+}
+
+function ribbon(headRadius) {
+ var source = defaultSource,
+ target = defaultTarget,
+ sourceRadius = defaultRadius,
+ targetRadius = defaultRadius,
+ startAngle = defaultStartAngle,
+ endAngle = defaultEndAngle,
+ padAngle = defaultPadAngle,
+ context = null;
+
+ function ribbon() {
+ var buffer,
+ s = source.apply(this, arguments),
+ t = target.apply(this, arguments),
+ ap = padAngle.apply(this, arguments) / 2,
+ argv = slice.call(arguments),
+ sr = +sourceRadius.apply(this, (argv[0] = s, argv)),
+ sa0 = startAngle.apply(this, argv) - halfPi,
+ sa1 = endAngle.apply(this, argv) - halfPi,
+ tr = +targetRadius.apply(this, (argv[0] = t, argv)),
+ ta0 = startAngle.apply(this, argv) - halfPi,
+ ta1 = endAngle.apply(this, argv) - halfPi;
+
+ if (!context) context = buffer = d3Path.path();
+
+ if (ap > epsilon) {
+ if (abs(sa1 - sa0) > ap * 2 + epsilon) sa1 > sa0 ? (sa0 += ap, sa1 -= ap) : (sa0 -= ap, sa1 += ap);
+ else sa0 = sa1 = (sa0 + sa1) / 2;
+ if (abs(ta1 - ta0) > ap * 2 + epsilon) ta1 > ta0 ? (ta0 += ap, ta1 -= ap) : (ta0 -= ap, ta1 += ap);
+ else ta0 = ta1 = (ta0 + ta1) / 2;
+ }
+
+ context.moveTo(sr * cos(sa0), sr * sin(sa0));
+ context.arc(0, 0, sr, sa0, sa1);
+ if (sa0 !== ta0 || sa1 !== ta1) {
+ if (headRadius) {
+ var hr = +headRadius.apply(this, arguments), tr2 = tr - hr, ta2 = (ta0 + ta1) / 2;
+ context.quadraticCurveTo(0, 0, tr2 * cos(ta0), tr2 * sin(ta0));
+ context.lineTo(tr * cos(ta2), tr * sin(ta2));
+ context.lineTo(tr2 * cos(ta1), tr2 * sin(ta1));
+ } else {
+ context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));
+ context.arc(0, 0, tr, ta0, ta1);
+ }
+ }
+ context.quadraticCurveTo(0, 0, sr * cos(sa0), sr * sin(sa0));
+ context.closePath();
+
+ if (buffer) return context = null, buffer + "" || null;
+ }
+
+ if (headRadius) ribbon.headRadius = function(_) {
+ return arguments.length ? (headRadius = typeof _ === "function" ? _ : constant(+_), ribbon) : headRadius;
+ };
+
+ ribbon.radius = function(_) {
+ return arguments.length ? (sourceRadius = targetRadius = typeof _ === "function" ? _ : constant(+_), ribbon) : sourceRadius;
+ };
+
+ ribbon.sourceRadius = function(_) {
+ return arguments.length ? (sourceRadius = typeof _ === "function" ? _ : constant(+_), ribbon) : sourceRadius;
+ };
+
+ ribbon.targetRadius = function(_) {
+ return arguments.length ? (targetRadius = typeof _ === "function" ? _ : constant(+_), ribbon) : targetRadius;
+ };
+
+ ribbon.startAngle = function(_) {
+ return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant(+_), ribbon) : startAngle;
+ };
+
+ ribbon.endAngle = function(_) {
+ return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant(+_), ribbon) : endAngle;
+ };
+
+ ribbon.padAngle = function(_) {
+ return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant(+_), ribbon) : padAngle;
+ };
+
+ ribbon.source = function(_) {
+ return arguments.length ? (source = _, ribbon) : source;
+ };
+
+ ribbon.target = function(_) {
+ return arguments.length ? (target = _, ribbon) : target;
+ };
+
+ ribbon.context = function(_) {
+ return arguments.length ? ((context = _ == null ? null : _), ribbon) : context;
+ };
+
+ return ribbon;
+}
+
+function ribbon$1() {
+ return ribbon();
+}
+
+function ribbonArrow() {
+ return ribbon(defaultArrowheadRadius);
+}
+
+exports.chord = chord;
+exports.chordDirected = chordDirected;
+exports.chordTranspose = chordTranspose;
+exports.ribbon = ribbon$1;
+exports.ribbonArrow = ribbonArrow;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-chord/dist/d3-chord.min.js b/node_modules/d3-chord/dist/d3-chord.min.js
new file mode 100644
index 00000000..9e808958
--- /dev/null
+++ b/node_modules/d3-chord/dist/d3-chord.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-chord/ v2.0.0 Copyright 2020 Mike Bostock
+!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-path")):"function"==typeof define&&define.amd?define(["exports","d3-path"],t):t((n=n||self).d3=n.d3||{},n.d3)}(this,function(n,t){"use strict";var e=Math.abs,r=Math.cos,u=Math.sin,o=Math.PI,l=o/2,a=2*o,i=Math.max,c=1e-12;function f(n,t){return Array.from({length:t-n},(t,e)=>n+e)}function s(n){return function(t,e){return n(t.source.value+t.target.value,e.source.value+e.target.value)}}function g(n,t){var e=0,r=null,u=null,o=null;function l(l){var c,s=l.length,g=new Array(s),p=f(0,s),d=new Array(s*s),h=new Array(s),y=0;l=Float64Array.from({length:s*s},t?(n,t)=>l[t%s][t/s|0]:(n,t)=>l[t/s|0][t%s]);for(let t=0;t
](https://observablehq.com/@d3/volcano-contours)
+
+For each [threshold value](#contours_thresholds), the [contour generator](#_contours) constructs a GeoJSON MultiPolygon geometry object representing the area where the input values are greater than or equal to the threshold value. The geometry is in planar coordinates, where ⟨i + 0.5, j + 0.5⟩ corresponds to element i + jn in the input values array. Here is an example that loads a GeoTIFF of surface temperatures, and another that blurs a noisy monochrome PNG to produce smooth contours of cloud fraction:
+
+[
](https://bl.ocks.org/mbostock/4886c227038510f1c103ce305bef6fcc)
+[
](https://bl.ocks.org/mbostock/818053c76d79d4841790c332656bf9da)
+
+Since the contour polygons are GeoJSON, you can transform and display them using standard tools; see [d3.geoPath](https://github.com/d3/d3-geo/blob/master/README.md#geoPath), [d3.geoProject](https://github.com/d3/d3-geo-projection/blob/master/README.md#geoProject) and [d3.geoStitch](https://github.com/d3/d3-geo-projection/blob/master/README.md#geoStitch), for example. Here the above contours of surface temperature are displayed in the Natural Earth projection:
+
+[
](https://bl.ocks.org/mbostock/83c0be21dba7602ee14982b020b12f51)
+
+Contour plots can also visualize continuous functions by sampling. Here is the Goldstein–Price function (a test function for global optimization) and a trippy animation of *sin*(*x* + *y*)*sin*(*x* - *y*):
+
+[
](https://observablehq.com/@d3/contours)
+[
](https://observablehq.com/@d3/animated-contours)
+
+Contours can also show the [estimated density](#density-estimation) of point clouds, which is especially useful to avoid overplotting in large datasets. This library implements fast two-dimensional kernel density estimation; see [d3.contourDensity](#contourDensity). Here is a scatterplot showing the relationship between the idle duration and eruption duration for Old Faithful:
+
+[
](https://bl.ocks.org/mbostock/e3f4376d54e02d5d43ae32a7cf0e6aa9)
+
+And here is a density contour plot showing the relationship between the weight and price of 53,940 diamonds:
+
+[
](https://observablehq.com/@d3/density-contours)
+
+## Installing
+
+If you use NPM, `npm install d3-contour`. Otherwise, download the [latest release](https://github.com/d3/d3-contour/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-contour.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:
+
+```html
+
+
+
+```
+
+## API Reference
+
+# d3.contours() [<>](https://github.com/d3/d3-contour/blob/master/src/contours.js "Source")
+
+Constructs a new contour generator with the default settings.
+
+# contours(values) [<>](https://github.com/d3/d3-contour/blob/master/src/contours.js "Source")
+
+Computes the contours for the given array of *values*, returning an array of [GeoJSON](http://geojson.org/geojson-spec.html) [MultiPolygon](http://geojson.org/geojson-spec.html#multipolygon) [geometry objects](http://geojson.org/geojson-spec.html#geometry-objects). Each geometry object represents the area where the input values are greater than or equal to the corresponding [threshold value](#contours_thresholds); the threshold value for each geometry object is exposed as geometry.value.
+
+The input *values* must be an array of length n×m where [n, m] is the contour generator’s [size](#contours_size); furthermore, each values[i + jn] must represent the value at the position ⟨i, j⟩. For example, to construct a 256×256 grid for the [Goldstein–Price function](https://en.wikipedia.org/wiki/Test_functions_for_optimization) where -2 ≤ x ≤ 2 and -2 ≤ y ≤ 1:
+
+```js
+var n = 256, m = 256, values = new Array(n * m);
+for (var j = 0.5, k = 0; j < m; ++j) {
+ for (var i = 0.5; i < n; ++i, ++k) {
+ values[k] = goldsteinPrice(i / n * 4 - 2, 1 - j / m * 3);
+ }
+}
+
+function goldsteinPrice(x, y) {
+ return (1 + Math.pow(x + y + 1, 2) * (19 - 14 * x + 3 * x * x - 14 * y + 6 * x * x + 3 * y * y))
+ * (30 + Math.pow(2 * x - 3 * y, 2) * (18 - 32 * x + 12 * x * x + 48 * y - 36 * x * y + 27 * y * y));
+}
+```
+
+The returned geometry objects are typically passed to [d3.geoPath](https://github.com/d3/d3-geo/blob/master/README.md#geoPath) to display, using null or [d3.geoIdentity](https://github.com/d3/d3-geo/blob/master/README.md#geoIdentity) as the associated projection.
+
+# contours.contour(values, threshold) [<>](https://github.com/d3/d3-contour/blob/master/src/contours.js "Source")
+
+Computes a single contour, returning a [GeoJSON](http://geojson.org/geojson-spec.html) [MultiPolygon](http://geojson.org/geojson-spec.html#multipolygon) [geometry object](http://geojson.org/geojson-spec.html#geometry-objects) representing the area where the input values are greater than or equal to the given [*threshold* value](#contours_thresholds); the threshold value for each geometry object is exposed as geometry.value.
+
+The input *values* must be an array of length n×m where [n, m] is the contour generator’s [size](#contours_size); furthermore, each values[i + jn] must represent the value at the position ⟨i, j⟩. See [*contours*](#_contours) for an example.
+
+# contours.size([size]) [<>](https://github.com/d3/d3-contour/blob/master/src/contours.js "Source")
+
+If *size* is specified, sets the expected size of the input *values* grid to the [contour generator](#_contour) and returns the contour generator. The *size* is specified as an array \[n, m\] where n is the number of columns in the grid and m is the number of rows; *n* and *m* must be positive integers. If *size* is not specified, returns the current size which defaults to [1, 1].
+
+# contours.smooth([smooth]) [<>](https://github.com/d3/d3-contour/blob/master/src/contours.js "Source")
+
+If *smooth* is specified, sets whether or not the generated contour polygons are smoothed using linear interpolation. If *smooth* is not specified, returns the current smoothing flag, which defaults to true.
+
+# contours.thresholds([thresholds]) [<>](https://github.com/d3/d3-contour/blob/master/src/contours.js "Source")
+
+If *thresholds* is specified, sets the threshold generator to the specified function or array and returns this contour generator. If *thresholds* is not specified, returns the current threshold generator, which by default implements [Sturges’ formula](https://github.com/d3/d3-array/blob/master/README.md#thresholdSturges).
+
+Thresholds are defined as an array of values [*x0*, *x1*, …]. The first [generated contour](#_contour) corresponds to the area where the input values are greater than or equal to *x0*; the second contour corresponds to the area where the input values are greater than or equal to *x1*, and so on. Thus, there is exactly one generated MultiPolygon geometry object for each specified threshold value; the threshold value is exposed as geometry.value.
+
+If a *count* is specified instead of an array of *thresholds*, then the input values’ [extent](https://github.com/d3/d3-array/blob/master/README.md#extent) will be uniformly divided into approximately *count* bins; see [d3.ticks](https://github.com/d3/d3-array/blob/master/README.md#ticks).
+
+## Density Estimation
+
+# d3.contourDensity() [<>](https://github.com/d3/d3-contour/blob/master/src/density.js "Source")
+
+Constructs a new density estimator with the default settings.
+
+# density(data) [<>](https://github.com/d3/d3-contour/blob/master/src/density.js "Source")
+
+Estimates the density contours for the given array of *data*, returning an array of [GeoJSON](http://geojson.org/geojson-spec.html) [MultiPolygon](http://geojson.org/geojson-spec.html#multipolygon) [geometry objects](http://geojson.org/geojson-spec.html#geometry-objects). Each geometry object represents the area where the estimated number of points per square pixel is greater than or equal to the corresponding [threshold value](#density_thresholds); the threshold value for each geometry object is exposed as geometry.value. The returned geometry objects are typically passed to [d3.geoPath](https://github.com/d3/d3-geo/blob/master/README.md#geoPath) to display, using null or [d3.geoIdentity](https://github.com/d3/d3-geo/blob/master/README.md#geoIdentity) as the associated projection. See also [d3.contours](#contours).
+
+The *x*- and *y*-coordinate for each data point are computed using [*density*.x](#density_x) and [*density*.y](#density_y). In addition, [*density*.weight](#density_weight) indicates the relative contribution of each data point (default 1). The generated contours are only accurate within the estimator’s [defined size](#density_size).
+
+# density.x([x]) [<>](https://github.com/d3/d3-contour/blob/master/src/density.js "Source")
+
+If *x* is specified, sets the *x*-coordinate accessor. If *x* is not specified, returns the current *x*-coordinate accessor, which defaults to:
+
+```js
+function x(d) {
+ return d[0];
+}
+```
+
+# density.y([y]) [<>](https://github.com/d3/d3-contour/blob/master/src/density.js "Source")
+
+If *y* is specified, sets the *y*-coordinate accessor. If *y* is not specified, returns the current *y*-coordinate accessor, which defaults to:
+
+```js
+function y(d) {
+ return d[1];
+}
+```
+
+# density.weight([weight]) [<>](https://github.com/d3/d3-contour/blob/master/src/density.js "Source")
+
+If *weight* is specified, sets the accessor for point weights. If *weight* is not specified, returns the current point weight accessor, which defaults to:
+
+```js
+function weight() {
+ return 1;
+}
+```
+
+# density.size([size]) [<>](https://github.com/d3/d3-contour/blob/master/src/density.js "Source")
+
+If *size* is specified, sets the size of the density estimator to the specified bounds and returns the estimator. The *size* is specified as an array \[width, height\], where width is the maximum *x*-value and height is the maximum *y*-value. If *size* is not specified, returns the current size which defaults to [960, 500]. The [estimated density contours](#_density) are only accurate within the defined size.
+
+# density.cellSize([cellSize]) [<>](https://github.com/d3/d3-contour/blob/master/src/density.js "Source")
+
+If *cellSize* is specified, sets the size of individual cells in the underlying bin grid to the specified positive integer and returns the estimator. If *cellSize* is not specified, returns the current cell size, which defaults to 4. The cell size is rounded down to the nearest power of two. Smaller cells produce more detailed contour polygons, but are more expensive to compute.
+
+# density.thresholds([thresholds]) [<>](https://github.com/d3/d3-contour/blob/master/src/density.js "Source")
+
+If *thresholds* is specified, sets the threshold generator to the specified function or array and returns this contour generator. If *thresholds* is not specified, returns the current threshold generator, which by default generates about twenty nicely-rounded density thresholds.
+
+Thresholds are defined as an array of values [*x0*, *x1*, …]. The first [generated density contour](#_density) corresponds to the area where the estimated density is greater than or equal to *x0*; the second contour corresponds to the area where the estimated density is greater than or equal to *x1*, and so on. Thus, there is exactly one generated MultiPolygon geometry object for each specified threshold value; the threshold value is exposed as geometry.value. The first value *x0* should typically be greater than zero.
+
+If a *count* is specified instead of an array of *thresholds*, then approximately *count* uniformly-spaced nicely-rounded thresholds will be generated; see [d3.ticks](https://github.com/d3/d3-array/blob/master/README.md#ticks).
+
+# density.bandwidth([bandwidth]) [<>](https://github.com/d3/d3-contour/blob/master/src/density.js "Source")
+
+If *bandwidth* is specified, sets the bandwidth (the standard deviation) of the Gaussian kernel and returns the estimate. If *bandwidth* is not specified, returns the current bandwidth, which defaults to 20.4939…. The specified *bandwidth* is currently rounded to the nearest supported value by this implementation, and must be nonnegative.
diff --git a/node_modules/d3-contour/dist/d3-contour.js b/node_modules/d3-contour/dist/d3-contour.js
new file mode 100644
index 00000000..0903808e
--- /dev/null
+++ b/node_modules/d3-contour/dist/d3-contour.js
@@ -0,0 +1,427 @@
+// https://d3js.org/d3-contour/ v2.0.0 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-array'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}, global.d3));
+}(this, function (exports, d3Array) { 'use strict';
+
+var array = Array.prototype;
+
+var slice = array.slice;
+
+function ascending(a, b) {
+ return a - b;
+}
+
+function area(ring) {
+ var i = 0, n = ring.length, area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1];
+ while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1];
+ return area;
+}
+
+var constant = x => () => x;
+
+function contains(ring, hole) {
+ var i = -1, n = hole.length, c;
+ while (++i < n) if (c = ringContains(ring, hole[i])) return c;
+ return 0;
+}
+
+function ringContains(ring, point) {
+ var x = point[0], y = point[1], contains = -1;
+ for (var i = 0, n = ring.length, j = n - 1; i < n; j = i++) {
+ var pi = ring[i], xi = pi[0], yi = pi[1], pj = ring[j], xj = pj[0], yj = pj[1];
+ if (segmentContains(pi, pj, point)) return 0;
+ if (((yi > y) !== (yj > y)) && ((x < (xj - xi) * (y - yi) / (yj - yi) + xi))) contains = -contains;
+ }
+ return contains;
+}
+
+function segmentContains(a, b, c) {
+ var i; return collinear(a, b, c) && within(a[i = +(a[0] === b[0])], c[i], b[i]);
+}
+
+function collinear(a, b, c) {
+ return (b[0] - a[0]) * (c[1] - a[1]) === (c[0] - a[0]) * (b[1] - a[1]);
+}
+
+function within(p, q, r) {
+ return p <= q && q <= r || r <= q && q <= p;
+}
+
+function noop() {}
+
+var cases = [
+ [],
+ [[[1.0, 1.5], [0.5, 1.0]]],
+ [[[1.5, 1.0], [1.0, 1.5]]],
+ [[[1.5, 1.0], [0.5, 1.0]]],
+ [[[1.0, 0.5], [1.5, 1.0]]],
+ [[[1.0, 1.5], [0.5, 1.0]], [[1.0, 0.5], [1.5, 1.0]]],
+ [[[1.0, 0.5], [1.0, 1.5]]],
+ [[[1.0, 0.5], [0.5, 1.0]]],
+ [[[0.5, 1.0], [1.0, 0.5]]],
+ [[[1.0, 1.5], [1.0, 0.5]]],
+ [[[0.5, 1.0], [1.0, 0.5]], [[1.5, 1.0], [1.0, 1.5]]],
+ [[[1.5, 1.0], [1.0, 0.5]]],
+ [[[0.5, 1.0], [1.5, 1.0]]],
+ [[[1.0, 1.5], [1.5, 1.0]]],
+ [[[0.5, 1.0], [1.0, 1.5]]],
+ []
+];
+
+function contours() {
+ var dx = 1,
+ dy = 1,
+ threshold = d3Array.thresholdSturges,
+ smooth = smoothLinear;
+
+ function contours(values) {
+ var tz = threshold(values);
+
+ // Convert number of thresholds into uniform thresholds.
+ if (!Array.isArray(tz)) {
+ var domain = d3Array.extent(values), start = domain[0], stop = domain[1];
+ tz = d3Array.tickStep(start, stop, tz);
+ tz = d3Array.range(Math.floor(start / tz) * tz, Math.floor(stop / tz) * tz, tz);
+ } else {
+ tz = tz.slice().sort(ascending);
+ }
+
+ return tz.map(function(value) {
+ return contour(values, value);
+ });
+ }
+
+ // Accumulate, smooth contour rings, assign holes to exterior rings.
+ // Based on https://github.com/mbostock/shapefile/blob/v0.6.2/shp/polygon.js
+ function contour(values, value) {
+ var polygons = [],
+ holes = [];
+
+ isorings(values, value, function(ring) {
+ smooth(ring, values, value);
+ if (area(ring) > 0) polygons.push([ring]);
+ else holes.push(ring);
+ });
+
+ holes.forEach(function(hole) {
+ for (var i = 0, n = polygons.length, polygon; i < n; ++i) {
+ if (contains((polygon = polygons[i])[0], hole) !== -1) {
+ polygon.push(hole);
+ return;
+ }
+ }
+ });
+
+ return {
+ type: "MultiPolygon",
+ value: value,
+ coordinates: polygons
+ };
+ }
+
+ // Marching squares with isolines stitched into rings.
+ // Based on https://github.com/topojson/topojson-client/blob/v3.0.0/src/stitch.js
+ function isorings(values, value, callback) {
+ var fragmentByStart = new Array,
+ fragmentByEnd = new Array,
+ x, y, t0, t1, t2, t3;
+
+ // Special case for the first row (y = -1, t2 = t3 = 0).
+ x = y = -1;
+ t1 = values[0] >= value;
+ cases[t1 << 1].forEach(stitch);
+ while (++x < dx - 1) {
+ t0 = t1, t1 = values[x + 1] >= value;
+ cases[t0 | t1 << 1].forEach(stitch);
+ }
+ cases[t1 << 0].forEach(stitch);
+
+ // General case for the intermediate rows.
+ while (++y < dy - 1) {
+ x = -1;
+ t1 = values[y * dx + dx] >= value;
+ t2 = values[y * dx] >= value;
+ cases[t1 << 1 | t2 << 2].forEach(stitch);
+ while (++x < dx - 1) {
+ t0 = t1, t1 = values[y * dx + dx + x + 1] >= value;
+ t3 = t2, t2 = values[y * dx + x + 1] >= value;
+ cases[t0 | t1 << 1 | t2 << 2 | t3 << 3].forEach(stitch);
+ }
+ cases[t1 | t2 << 3].forEach(stitch);
+ }
+
+ // Special case for the last row (y = dy - 1, t0 = t1 = 0).
+ x = -1;
+ t2 = values[y * dx] >= value;
+ cases[t2 << 2].forEach(stitch);
+ while (++x < dx - 1) {
+ t3 = t2, t2 = values[y * dx + x + 1] >= value;
+ cases[t2 << 2 | t3 << 3].forEach(stitch);
+ }
+ cases[t2 << 3].forEach(stitch);
+
+ function stitch(line) {
+ var start = [line[0][0] + x, line[0][1] + y],
+ end = [line[1][0] + x, line[1][1] + y],
+ startIndex = index(start),
+ endIndex = index(end),
+ f, g;
+ if (f = fragmentByEnd[startIndex]) {
+ if (g = fragmentByStart[endIndex]) {
+ delete fragmentByEnd[f.end];
+ delete fragmentByStart[g.start];
+ if (f === g) {
+ f.ring.push(end);
+ callback(f.ring);
+ } else {
+ fragmentByStart[f.start] = fragmentByEnd[g.end] = {start: f.start, end: g.end, ring: f.ring.concat(g.ring)};
+ }
+ } else {
+ delete fragmentByEnd[f.end];
+ f.ring.push(end);
+ fragmentByEnd[f.end = endIndex] = f;
+ }
+ } else if (f = fragmentByStart[endIndex]) {
+ if (g = fragmentByEnd[startIndex]) {
+ delete fragmentByStart[f.start];
+ delete fragmentByEnd[g.end];
+ if (f === g) {
+ f.ring.push(end);
+ callback(f.ring);
+ } else {
+ fragmentByStart[g.start] = fragmentByEnd[f.end] = {start: g.start, end: f.end, ring: g.ring.concat(f.ring)};
+ }
+ } else {
+ delete fragmentByStart[f.start];
+ f.ring.unshift(start);
+ fragmentByStart[f.start = startIndex] = f;
+ }
+ } else {
+ fragmentByStart[startIndex] = fragmentByEnd[endIndex] = {start: startIndex, end: endIndex, ring: [start, end]};
+ }
+ }
+ }
+
+ function index(point) {
+ return point[0] * 2 + point[1] * (dx + 1) * 4;
+ }
+
+ function smoothLinear(ring, values, value) {
+ ring.forEach(function(point) {
+ var x = point[0],
+ y = point[1],
+ xt = x | 0,
+ yt = y | 0,
+ v0,
+ v1 = values[yt * dx + xt];
+ if (x > 0 && x < dx && xt === x) {
+ v0 = values[yt * dx + xt - 1];
+ point[0] = x + (value - v0) / (v1 - v0) - 0.5;
+ }
+ if (y > 0 && y < dy && yt === y) {
+ v0 = values[(yt - 1) * dx + xt];
+ point[1] = y + (value - v0) / (v1 - v0) - 0.5;
+ }
+ });
+ }
+
+ contours.contour = contour;
+
+ contours.size = function(_) {
+ if (!arguments.length) return [dx, dy];
+ var _0 = Math.floor(_[0]), _1 = Math.floor(_[1]);
+ if (!(_0 >= 0 && _1 >= 0)) throw new Error("invalid size");
+ return dx = _0, dy = _1, contours;
+ };
+
+ contours.thresholds = function(_) {
+ return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), contours) : threshold;
+ };
+
+ contours.smooth = function(_) {
+ return arguments.length ? (smooth = _ ? smoothLinear : noop, contours) : smooth === smoothLinear;
+ };
+
+ return contours;
+}
+
+// TODO Optimize edge cases.
+// TODO Optimize index calculation.
+// TODO Optimize arguments.
+function blurX(source, target, r) {
+ var n = source.width,
+ m = source.height,
+ w = (r << 1) + 1;
+ for (var j = 0; j < m; ++j) {
+ for (var i = 0, sr = 0; i < n + r; ++i) {
+ if (i < n) {
+ sr += source.data[i + j * n];
+ }
+ if (i >= r) {
+ if (i >= w) {
+ sr -= source.data[i - w + j * n];
+ }
+ target.data[i - r + j * n] = sr / Math.min(i + 1, n - 1 + w - i, w);
+ }
+ }
+ }
+}
+
+// TODO Optimize edge cases.
+// TODO Optimize index calculation.
+// TODO Optimize arguments.
+function blurY(source, target, r) {
+ var n = source.width,
+ m = source.height,
+ w = (r << 1) + 1;
+ for (var i = 0; i < n; ++i) {
+ for (var j = 0, sr = 0; j < m + r; ++j) {
+ if (j < m) {
+ sr += source.data[i + j * n];
+ }
+ if (j >= r) {
+ if (j >= w) {
+ sr -= source.data[i + (j - w) * n];
+ }
+ target.data[i + (j - r) * n] = sr / Math.min(j + 1, m - 1 + w - j, w);
+ }
+ }
+ }
+}
+
+function defaultX(d) {
+ return d[0];
+}
+
+function defaultY(d) {
+ return d[1];
+}
+
+function defaultWeight() {
+ return 1;
+}
+
+function density() {
+ var x = defaultX,
+ y = defaultY,
+ weight = defaultWeight,
+ dx = 960,
+ dy = 500,
+ r = 20, // blur radius
+ k = 2, // log2(grid cell size)
+ o = r * 3, // grid offset, to pad for blur
+ n = (dx + o * 2) >> k, // grid width
+ m = (dy + o * 2) >> k, // grid height
+ threshold = constant(20);
+
+ function density(data) {
+ var values0 = new Float32Array(n * m),
+ values1 = new Float32Array(n * m);
+
+ data.forEach(function(d, i, data) {
+ var xi = (+x(d, i, data) + o) >> k,
+ yi = (+y(d, i, data) + o) >> k,
+ wi = +weight(d, i, data);
+ if (xi >= 0 && xi < n && yi >= 0 && yi < m) {
+ values0[xi + yi * n] += wi;
+ }
+ });
+
+ // TODO Optimize.
+ blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k);
+ blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k);
+ blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k);
+ blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k);
+ blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k);
+ blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k);
+
+ var tz = threshold(values0);
+
+ // Convert number of thresholds into uniform thresholds.
+ if (!Array.isArray(tz)) {
+ var stop = d3Array.max(values0);
+ tz = d3Array.tickStep(0, stop, tz);
+ tz = d3Array.range(0, Math.floor(stop / tz) * tz, tz);
+ tz.shift();
+ }
+
+ return contours()
+ .thresholds(tz)
+ .size([n, m])
+ (values0)
+ .map(transform);
+ }
+
+ function transform(geometry) {
+ geometry.value *= Math.pow(2, -2 * k); // Density in points per square pixel.
+ geometry.coordinates.forEach(transformPolygon);
+ return geometry;
+ }
+
+ function transformPolygon(coordinates) {
+ coordinates.forEach(transformRing);
+ }
+
+ function transformRing(coordinates) {
+ coordinates.forEach(transformPoint);
+ }
+
+ // TODO Optimize.
+ function transformPoint(coordinates) {
+ coordinates[0] = coordinates[0] * Math.pow(2, k) - o;
+ coordinates[1] = coordinates[1] * Math.pow(2, k) - o;
+ }
+
+ function resize() {
+ o = r * 3;
+ n = (dx + o * 2) >> k;
+ m = (dy + o * 2) >> k;
+ return density;
+ }
+
+ density.x = function(_) {
+ return arguments.length ? (x = typeof _ === "function" ? _ : constant(+_), density) : x;
+ };
+
+ density.y = function(_) {
+ return arguments.length ? (y = typeof _ === "function" ? _ : constant(+_), density) : y;
+ };
+
+ density.weight = function(_) {
+ return arguments.length ? (weight = typeof _ === "function" ? _ : constant(+_), density) : weight;
+ };
+
+ density.size = function(_) {
+ if (!arguments.length) return [dx, dy];
+ var _0 = +_[0], _1 = +_[1];
+ if (!(_0 >= 0 && _1 >= 0)) throw new Error("invalid size");
+ return dx = _0, dy = _1, resize();
+ };
+
+ density.cellSize = function(_) {
+ if (!arguments.length) return 1 << k;
+ if (!((_ = +_) >= 1)) throw new Error("invalid cell size");
+ return k = Math.floor(Math.log(_) / Math.LN2), resize();
+ };
+
+ density.thresholds = function(_) {
+ return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), density) : threshold;
+ };
+
+ density.bandwidth = function(_) {
+ if (!arguments.length) return Math.sqrt(r * (r + 1));
+ if (!((_ = +_) >= 0)) throw new Error("invalid bandwidth");
+ return r = Math.round((Math.sqrt(4 * _ * _ + 1) - 1) / 2), resize();
+ };
+
+ return density;
+}
+
+exports.contourDensity = density;
+exports.contours = contours;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-contour/dist/d3-contour.min.js b/node_modules/d3-contour/dist/d3-contour.min.js
new file mode 100644
index 00000000..53abde59
--- /dev/null
+++ b/node_modules/d3-contour/dist/d3-contour.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-contour/ v2.0.0 Copyright 2020 Mike Bostock
+!function(t,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("d3-array")):"function"==typeof define&&define.amd?define(["exports","d3-array"],r):r((t=t||self).d3=t.d3||{},t.d3)}(this,function(t,r){"use strict";var n=Array.prototype.slice;function e(t,r){return t-r}var i=t=>()=>t;function a(t,r){for(var n,e=-1,i=r.length;++ee!=g>e&&n<(s-c)*(e-d)/(g-d)+c&&(i=-i)}return i}function h(t,r,n){var e,i,a,o;return function(t,r,n){return(r[0]-t[0])*(n[1]-t[1])==(n[0]-t[0])*(r[1]-t[1])}(t,r,n)&&(i=t[e=+(t[0]===r[0])],a=n[e],o=r[e],i<=a&&a<=o||o<=a&&a<=i)}function f(){}var u=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function c(){var t=1,o=1,h=r.thresholdSturges,c=g;function d(t){var n=h(t);if(Array.isArray(n))n=n.slice().sort(e);else{var i=r.extent(t),a=i[0],o=i[1];n=r.tickStep(a,o,n),n=r.range(Math.floor(a/n)*n,Math.floor(o/n)*n,n)}return n.map(function(r){return l(t,r)})}function l(r,n){var e=[],i=[];return function(r,n,e){var i,a,h,f,c,d,l=new Array,g=new Array;i=a=-1,f=r[0]>=n,u[f<<1].forEach(v);for(;++i>u),l({width:y,height:p,data:o},{width:y,height:p,data:i},f>>u),d({width:y,height:p,data:i},{width:y,height:p,data:o},f>>u),l({width:y,height:p,data:o},{width:y,height:p,data:i},f>>u),d({width:y,height:p,data:i},{width:y,height:p,data:o},f>>u),l({width:y,height:p,data:o},{width:y,height:p,data:i},f>>u);var h=E(i);if(!Array.isArray(h)){var s=r.max(i);h=r.tickStep(0,s,h),(h=r.range(0,Math.floor(s/h)*h,h)).shift()}return c().thresholds(h).size([y,p])(i).map(A)}function A(t){return t.value*=Math.pow(2,-2*u),t.coordinates.forEach(m),t}function m(t){t.forEach(z)}function z(t){t.forEach(x)}function x(t){t[0]=t[0]*Math.pow(2,u)-w,t[1]=t[1]*Math.pow(2,u)-w}function b(){return y=o+2*(w=3*f)>>u,p=h+2*w>>u,M}return M.x=function(r){return arguments.length?(t="function"==typeof r?r:i(+r),M):t},M.y=function(t){return arguments.length?(e="function"==typeof t?t:i(+t),M):e},M.weight=function(t){return arguments.length?(a="function"==typeof t?t:i(+t),M):a},M.size=function(t){if(!arguments.length)return[o,h];var r=+t[0],n=+t[1];if(!(r>=0&&n>=0))throw new Error("invalid size");return o=r,h=n,b()},M.cellSize=function(t){if(!arguments.length)return 1<=1))throw new Error("invalid cell size");return u=Math.floor(Math.log(t)/Math.LN2),b()},M.thresholds=function(t){return arguments.length?(E="function"==typeof t?t:Array.isArray(t)?i(n.call(t)):i(t),M):E},M.bandwidth=function(t){if(!arguments.length)return Math.sqrt(f*(f+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return f=Math.round((Math.sqrt(4*t*t+1)-1)/2),b()},M},t.contours=c,Object.defineProperty(t,"__esModule",{value:!0})}); diff --git a/node_modules/d3-contour/package.json b/node_modules/d3-contour/package.json new file mode 100644 index 00000000..e13df82e --- /dev/null +++ b/node_modules/d3-contour/package.json @@ -0,0 +1,73 @@ +{ + "_from": "d3-contour@2", + "_id": "d3-contour@2.0.0", + "_inBundle": false, + "_integrity": "sha512-9unAtvIaNk06UwqBmvsdHX7CZ+NPDZnn8TtNH1myW93pWJkhsV25JcgnYAu0Ck5Veb1DHiCv++Ic5uvJ+h50JA==", + "_location": "/d3-contour", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "d3-contour@2", + "name": "d3-contour", + "escapedName": "d3-contour", + "rawSpec": "2", + "saveSpec": null, + "fetchSpec": "2" + }, + "_requiredBy": [ + "/d3" + ], + "_resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-2.0.0.tgz", + "_shasum": "80ee834988563e3bea9d99ddde72c0f8c089ea40", + "_spec": "d3-contour@2", + "_where": "C:\\Users\\rin\\Desktop\\final\\node_modules\\d3", + "author": { + "name": "Mike Bostock", + "url": "http://bost.ocks.org/mike" + }, + "bugs": { + "url": "https://github.com/d3/d3-contour/issues" + }, + "bundleDependencies": false, + "dependencies": { + "d3-array": "2" + }, + "deprecated": false, + "description": "Compute contour polygons using marching squares.", + "devDependencies": { + "eslint": "6", + "rollup": "1", + "rollup-plugin-terser": "5", + "tape": "4" + }, + "files": [ + "dist/**/*.js", + "src/**/*.js" + ], + "homepage": "https://d3js.org/d3-contour/", + "jsdelivr": "dist/d3-contour.min.js", + "keywords": [ + "d3", + "d3-module", + "contour", + "isoline" + ], + "license": "BSD-3-Clause", + "main": "dist/d3-contour.js", + "module": "src/index.js", + "name": "d3-contour", + "repository": { + "type": "git", + "url": "git+https://github.com/d3/d3-contour.git" + }, + "scripts": { + "postpublish": "git push && git push --tags && cd ../d3.github.com && git pull && cp ../${npm_package_name}/dist/${npm_package_name}.js ${npm_package_name}.v${npm_package_version%%.*}.js && cp ../${npm_package_name}/dist/${npm_package_name}.min.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git add ${npm_package_name}.v${npm_package_version%%.*}.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git commit -m \"${npm_package_name} ${npm_package_version}\" && git push && cd - && zip -j dist/${npm_package_name}.zip -- LICENSE README.md dist/${npm_package_name}.js dist/${npm_package_name}.min.js", + "prepublishOnly": "rm -rf dist && yarn test", + "pretest": "rollup -c", + "test": "tape 'test/**/*-test.js' && eslint src" + }, + "sideEffects": false, + "unpkg": "dist/d3-contour.min.js", + "version": "2.0.0" +} diff --git a/node_modules/d3-contour/src/area.js b/node_modules/d3-contour/src/area.js new file mode 100644 index 00000000..2157a7ef --- /dev/null +++ b/node_modules/d3-contour/src/area.js @@ -0,0 +1,5 @@ +export default function(ring) { + var i = 0, n = ring.length, area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1]; + while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1]; + return area; +} diff --git a/node_modules/d3-contour/src/array.js b/node_modules/d3-contour/src/array.js new file mode 100644 index 00000000..d2361352 --- /dev/null +++ b/node_modules/d3-contour/src/array.js @@ -0,0 +1,3 @@ +var array = Array.prototype; + +export var slice = array.slice; diff --git a/node_modules/d3-contour/src/ascending.js b/node_modules/d3-contour/src/ascending.js new file mode 100644 index 00000000..8939af70 --- /dev/null +++ b/node_modules/d3-contour/src/ascending.js @@ -0,0 +1,3 @@ +export default function(a, b) { + return a - b; +} diff --git a/node_modules/d3-contour/src/blur.js b/node_modules/d3-contour/src/blur.js new file mode 100644 index 00000000..0edfb3ef --- /dev/null +++ b/node_modules/d3-contour/src/blur.js @@ -0,0 +1,43 @@ +// TODO Optimize edge cases. +// TODO Optimize index calculation. +// TODO Optimize arguments. +export function blurX(source, target, r) { + var n = source.width, + m = source.height, + w = (r << 1) + 1; + for (var j = 0; j < m; ++j) { + for (var i = 0, sr = 0; i < n + r; ++i) { + if (i < n) { + sr += source.data[i + j * n]; + } + if (i >= r) { + if (i >= w) { + sr -= source.data[i - w + j * n]; + } + target.data[i - r + j * n] = sr / Math.min(i + 1, n - 1 + w - i, w); + } + } + } +} + +// TODO Optimize edge cases. +// TODO Optimize index calculation. +// TODO Optimize arguments. +export function blurY(source, target, r) { + var n = source.width, + m = source.height, + w = (r << 1) + 1; + for (var i = 0; i < n; ++i) { + for (var j = 0, sr = 0; j < m + r; ++j) { + if (j < m) { + sr += source.data[i + j * n]; + } + if (j >= r) { + if (j >= w) { + sr -= source.data[i + (j - w) * n]; + } + target.data[i + (j - r) * n] = sr / Math.min(j + 1, m - 1 + w - j, w); + } + } + } +} diff --git a/node_modules/d3-contour/src/constant.js b/node_modules/d3-contour/src/constant.js new file mode 100644 index 00000000..3487c0dd --- /dev/null +++ b/node_modules/d3-contour/src/constant.js @@ -0,0 +1 @@ +export default x => () => x; diff --git a/node_modules/d3-contour/src/contains.js b/node_modules/d3-contour/src/contains.js new file mode 100644 index 00000000..f364b354 --- /dev/null +++ b/node_modules/d3-contour/src/contains.js @@ -0,0 +1,27 @@ +export default function(ring, hole) { + var i = -1, n = hole.length, c; + while (++i < n) if (c = ringContains(ring, hole[i])) return c; + return 0; +} + +function ringContains(ring, point) { + var x = point[0], y = point[1], contains = -1; + for (var i = 0, n = ring.length, j = n - 1; i < n; j = i++) { + var pi = ring[i], xi = pi[0], yi = pi[1], pj = ring[j], xj = pj[0], yj = pj[1]; + if (segmentContains(pi, pj, point)) return 0; + if (((yi > y) !== (yj > y)) && ((x < (xj - xi) * (y - yi) / (yj - yi) + xi))) contains = -contains; + } + return contains; +} + +function segmentContains(a, b, c) { + var i; return collinear(a, b, c) && within(a[i = +(a[0] === b[0])], c[i], b[i]); +} + +function collinear(a, b, c) { + return (b[0] - a[0]) * (c[1] - a[1]) === (c[0] - a[0]) * (b[1] - a[1]); +} + +function within(p, q, r) { + return p <= q && q <= r || r <= q && q <= p; +} diff --git a/node_modules/d3-contour/src/contours.js b/node_modules/d3-contour/src/contours.js new file mode 100644 index 00000000..614e9ecf --- /dev/null +++ b/node_modules/d3-contour/src/contours.js @@ -0,0 +1,203 @@ +import {extent, thresholdSturges, tickStep, range} from "d3-array"; +import {slice} from "./array.js"; +import ascending from "./ascending.js"; +import area from "./area.js"; +import constant from "./constant.js"; +import contains from "./contains.js"; +import noop from "./noop.js"; + +var cases = [ + [], + [[[1.0, 1.5], [0.5, 1.0]]], + [[[1.5, 1.0], [1.0, 1.5]]], + [[[1.5, 1.0], [0.5, 1.0]]], + [[[1.0, 0.5], [1.5, 1.0]]], + [[[1.0, 1.5], [0.5, 1.0]], [[1.0, 0.5], [1.5, 1.0]]], + [[[1.0, 0.5], [1.0, 1.5]]], + [[[1.0, 0.5], [0.5, 1.0]]], + [[[0.5, 1.0], [1.0, 0.5]]], + [[[1.0, 1.5], [1.0, 0.5]]], + [[[0.5, 1.0], [1.0, 0.5]], [[1.5, 1.0], [1.0, 1.5]]], + [[[1.5, 1.0], [1.0, 0.5]]], + [[[0.5, 1.0], [1.5, 1.0]]], + [[[1.0, 1.5], [1.5, 1.0]]], + [[[0.5, 1.0], [1.0, 1.5]]], + [] +]; + +export default function() { + var dx = 1, + dy = 1, + threshold = thresholdSturges, + smooth = smoothLinear; + + function contours(values) { + var tz = threshold(values); + + // Convert number of thresholds into uniform thresholds. + if (!Array.isArray(tz)) { + var domain = extent(values), start = domain[0], stop = domain[1]; + tz = tickStep(start, stop, tz); + tz = range(Math.floor(start / tz) * tz, Math.floor(stop / tz) * tz, tz); + } else { + tz = tz.slice().sort(ascending); + } + + return tz.map(function(value) { + return contour(values, value); + }); + } + + // Accumulate, smooth contour rings, assign holes to exterior rings. + // Based on https://github.com/mbostock/shapefile/blob/v0.6.2/shp/polygon.js + function contour(values, value) { + var polygons = [], + holes = []; + + isorings(values, value, function(ring) { + smooth(ring, values, value); + if (area(ring) > 0) polygons.push([ring]); + else holes.push(ring); + }); + + holes.forEach(function(hole) { + for (var i = 0, n = polygons.length, polygon; i < n; ++i) { + if (contains((polygon = polygons[i])[0], hole) !== -1) { + polygon.push(hole); + return; + } + } + }); + + return { + type: "MultiPolygon", + value: value, + coordinates: polygons + }; + } + + // Marching squares with isolines stitched into rings. + // Based on https://github.com/topojson/topojson-client/blob/v3.0.0/src/stitch.js + function isorings(values, value, callback) { + var fragmentByStart = new Array, + fragmentByEnd = new Array, + x, y, t0, t1, t2, t3; + + // Special case for the first row (y = -1, t2 = t3 = 0). + x = y = -1; + t1 = values[0] >= value; + cases[t1 << 1].forEach(stitch); + while (++x < dx - 1) { + t0 = t1, t1 = values[x + 1] >= value; + cases[t0 | t1 << 1].forEach(stitch); + } + cases[t1 << 0].forEach(stitch); + + // General case for the intermediate rows. + while (++y < dy - 1) { + x = -1; + t1 = values[y * dx + dx] >= value; + t2 = values[y * dx] >= value; + cases[t1 << 1 | t2 << 2].forEach(stitch); + while (++x < dx - 1) { + t0 = t1, t1 = values[y * dx + dx + x + 1] >= value; + t3 = t2, t2 = values[y * dx + x + 1] >= value; + cases[t0 | t1 << 1 | t2 << 2 | t3 << 3].forEach(stitch); + } + cases[t1 | t2 << 3].forEach(stitch); + } + + // Special case for the last row (y = dy - 1, t0 = t1 = 0). + x = -1; + t2 = values[y * dx] >= value; + cases[t2 << 2].forEach(stitch); + while (++x < dx - 1) { + t3 = t2, t2 = values[y * dx + x + 1] >= value; + cases[t2 << 2 | t3 << 3].forEach(stitch); + } + cases[t2 << 3].forEach(stitch); + + function stitch(line) { + var start = [line[0][0] + x, line[0][1] + y], + end = [line[1][0] + x, line[1][1] + y], + startIndex = index(start), + endIndex = index(end), + f, g; + if (f = fragmentByEnd[startIndex]) { + if (g = fragmentByStart[endIndex]) { + delete fragmentByEnd[f.end]; + delete fragmentByStart[g.start]; + if (f === g) { + f.ring.push(end); + callback(f.ring); + } else { + fragmentByStart[f.start] = fragmentByEnd[g.end] = {start: f.start, end: g.end, ring: f.ring.concat(g.ring)}; + } + } else { + delete fragmentByEnd[f.end]; + f.ring.push(end); + fragmentByEnd[f.end = endIndex] = f; + } + } else if (f = fragmentByStart[endIndex]) { + if (g = fragmentByEnd[startIndex]) { + delete fragmentByStart[f.start]; + delete fragmentByEnd[g.end]; + if (f === g) { + f.ring.push(end); + callback(f.ring); + } else { + fragmentByStart[g.start] = fragmentByEnd[f.end] = {start: g.start, end: f.end, ring: g.ring.concat(f.ring)}; + } + } else { + delete fragmentByStart[f.start]; + f.ring.unshift(start); + fragmentByStart[f.start = startIndex] = f; + } + } else { + fragmentByStart[startIndex] = fragmentByEnd[endIndex] = {start: startIndex, end: endIndex, ring: [start, end]}; + } + } + } + + function index(point) { + return point[0] * 2 + point[1] * (dx + 1) * 4; + } + + function smoothLinear(ring, values, value) { + ring.forEach(function(point) { + var x = point[0], + y = point[1], + xt = x | 0, + yt = y | 0, + v0, + v1 = values[yt * dx + xt]; + if (x > 0 && x < dx && xt === x) { + v0 = values[yt * dx + xt - 1]; + point[0] = x + (value - v0) / (v1 - v0) - 0.5; + } + if (y > 0 && y < dy && yt === y) { + v0 = values[(yt - 1) * dx + xt]; + point[1] = y + (value - v0) / (v1 - v0) - 0.5; + } + }); + } + + contours.contour = contour; + + contours.size = function(_) { + if (!arguments.length) return [dx, dy]; + var _0 = Math.floor(_[0]), _1 = Math.floor(_[1]); + if (!(_0 >= 0 && _1 >= 0)) throw new Error("invalid size"); + return dx = _0, dy = _1, contours; + }; + + contours.thresholds = function(_) { + return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), contours) : threshold; + }; + + contours.smooth = function(_) { + return arguments.length ? (smooth = _ ? smoothLinear : noop, contours) : smooth === smoothLinear; + }; + + return contours; +} diff --git a/node_modules/d3-contour/src/density.js b/node_modules/d3-contour/src/density.js new file mode 100644 index 00000000..a817f0a8 --- /dev/null +++ b/node_modules/d3-contour/src/density.js @@ -0,0 +1,133 @@ +import {max, range, tickStep} from "d3-array"; +import {slice} from "./array.js"; +import {blurX, blurY} from "./blur.js"; +import constant from "./constant.js"; +import contours from "./contours.js"; + +function defaultX(d) { + return d[0]; +} + +function defaultY(d) { + return d[1]; +} + +function defaultWeight() { + return 1; +} + +export default function() { + var x = defaultX, + y = defaultY, + weight = defaultWeight, + dx = 960, + dy = 500, + r = 20, // blur radius + k = 2, // log2(grid cell size) + o = r * 3, // grid offset, to pad for blur + n = (dx + o * 2) >> k, // grid width + m = (dy + o * 2) >> k, // grid height + threshold = constant(20); + + function density(data) { + var values0 = new Float32Array(n * m), + values1 = new Float32Array(n * m); + + data.forEach(function(d, i, data) { + var xi = (+x(d, i, data) + o) >> k, + yi = (+y(d, i, data) + o) >> k, + wi = +weight(d, i, data); + if (xi >= 0 && xi < n && yi >= 0 && yi < m) { + values0[xi + yi * n] += wi; + } + }); + + // TODO Optimize. + blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k); + blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k); + blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k); + blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k); + blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k); + blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k); + + var tz = threshold(values0); + + // Convert number of thresholds into uniform thresholds. + if (!Array.isArray(tz)) { + var stop = max(values0); + tz = tickStep(0, stop, tz); + tz = range(0, Math.floor(stop / tz) * tz, tz); + tz.shift(); + } + + return contours() + .thresholds(tz) + .size([n, m]) + (values0) + .map(transform); + } + + function transform(geometry) { + geometry.value *= Math.pow(2, -2 * k); // Density in points per square pixel. + geometry.coordinates.forEach(transformPolygon); + return geometry; + } + + function transformPolygon(coordinates) { + coordinates.forEach(transformRing); + } + + function transformRing(coordinates) { + coordinates.forEach(transformPoint); + } + + // TODO Optimize. + function transformPoint(coordinates) { + coordinates[0] = coordinates[0] * Math.pow(2, k) - o; + coordinates[1] = coordinates[1] * Math.pow(2, k) - o; + } + + function resize() { + o = r * 3; + n = (dx + o * 2) >> k; + m = (dy + o * 2) >> k; + return density; + } + + density.x = function(_) { + return arguments.length ? (x = typeof _ === "function" ? _ : constant(+_), density) : x; + }; + + density.y = function(_) { + return arguments.length ? (y = typeof _ === "function" ? _ : constant(+_), density) : y; + }; + + density.weight = function(_) { + return arguments.length ? (weight = typeof _ === "function" ? _ : constant(+_), density) : weight; + }; + + density.size = function(_) { + if (!arguments.length) return [dx, dy]; + var _0 = +_[0], _1 = +_[1]; + if (!(_0 >= 0 && _1 >= 0)) throw new Error("invalid size"); + return dx = _0, dy = _1, resize(); + }; + + density.cellSize = function(_) { + if (!arguments.length) return 1 << k; + if (!((_ = +_) >= 1)) throw new Error("invalid cell size"); + return k = Math.floor(Math.log(_) / Math.LN2), resize(); + }; + + density.thresholds = function(_) { + return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), density) : threshold; + }; + + density.bandwidth = function(_) { + if (!arguments.length) return Math.sqrt(r * (r + 1)); + if (!((_ = +_) >= 0)) throw new Error("invalid bandwidth"); + return r = Math.round((Math.sqrt(4 * _ * _ + 1) - 1) / 2), resize(); + }; + + return density; +} diff --git a/node_modules/d3-contour/src/index.js b/node_modules/d3-contour/src/index.js new file mode 100644 index 00000000..8e6b5f0d --- /dev/null +++ b/node_modules/d3-contour/src/index.js @@ -0,0 +1,2 @@ +export {default as contours} from "./contours.js"; +export {default as contourDensity} from "./density.js"; diff --git a/node_modules/d3-contour/src/noop.js b/node_modules/d3-contour/src/noop.js new file mode 100644 index 00000000..6ab80bc8 --- /dev/null +++ b/node_modules/d3-contour/src/noop.js @@ -0,0 +1 @@ +export default function() {} diff --git a/node_modules/d3-delaunay/LICENSE b/node_modules/d3-delaunay/LICENSE new file mode 100644 index 00000000..cf16bc44 --- /dev/null +++ b/node_modules/d3-delaunay/LICENSE @@ -0,0 +1,13 @@ +Copyright 2018 Observable, Inc. + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/node_modules/d3-delaunay/README.md b/node_modules/d3-delaunay/README.md new file mode 100644 index 00000000..baf04812 --- /dev/null +++ b/node_modules/d3-delaunay/README.md @@ -0,0 +1,201 @@ +# d3-delaunay + +
+
Georgy “The Voronator†Voronoy
+
+This is a fast, no-dependency library for computing the [Voronoi diagram](https://en.wikipedia.org/wiki/Voronoi_diagram) of a set of two-dimensional points. It is based on [Delaunator](https://github.com/mapbox/delaunator), a fast library for computing the [Delaunay triangulation](https://en.wikipedia.org/wiki/Delaunay_triangulation) using [sweep algorithms](https://github.com/mapbox/delaunator/blob/master/README.md#papers). The Voronoi diagram is constructed by connecting the circumcenters of adjacent triangles in the Delaunay triangulation.
+
+For an interactive explanation of how this library works, see [The Delaunay’s Dual](https://observablehq.com/@mbostock/the-delaunays-dual).
+
+## Installing
+
+To install, `npm install d3-delaunay` or `yarn add d3-delaunay`. You can also download the [latest release](https://github.com/d3/d3-delaunay/releases/latest) or load directly from [unpkg](https://unpkg.com/d3-delaunay/). AMD, CommonJS and ES6+ environments are supported. In vanilla, a `d3` global is exported.
+
+```js
+import {Delaunay} from "d3-delaunay";
+
+const points = [[0, 0], [0, 1], [1, 0], [1, 1]];
+const delaunay = Delaunay.from(points);
+const voronoi = delaunay.voronoi([0, 0, 960, 500]);
+```
+
+## API Reference
+
+### Delaunay
+
+# new Delaunay(points) [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+Returns the Delaunay triangulation for the given flat array [*x0*, *y0*, *x1*, *y1*, …] of *points*.
+
+```js
+const delaunay = new Delaunay(Float64Array.of(0, 0, 0, 1, 1, 0, 1, 1));
+```
+
+# Delaunay.from(points[, fx[, fy[, that]]]) [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+Returns the Delaunay triangulation for the given array or iterable of *points*. If *fx* and *fy* are not specified, then *points* is assumed to be an array of two-element arrays of numbers: [[*x0*, *y0*], [*x1*, *y1*], …]. Otherwise, *fx* and *fy* are functions that are invoked for each element in the *points* array in order, and must return the respective *x*- and *y*-coordinate for each point. If *that* is specified, the functions *fx* and *fy* are invoked with *that* as *this*. (See [Array.from](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/from) for reference.)
+
+```js
+const delaunay = Delaunay.from([[0, 0], [0, 1], [1, 0], [1, 1]]);
+```
+
+# delaunay.points
+
+The coordinates of the points as an array [*x0*, *y0*, *x1*, *y1*, …]. Typically, this is a Float64Array, however you can use any array-like type in the [constructor](#new_Delaunay).
+
+# delaunay.halfedges
+
+The halfedge indexes as an Int32Array [*j0*, *j1*, …]. For each index 0 ≤ *i* < *halfedges*.length, there is a halfedge from triangle vertex *j* = *halfedges*[*i*] to triangle vertex *i*. Equivalently, this means that triangle ⌊*i* / 3⌋ is adjacent to triangle ⌊*j* / 3⌋. If *j* is negative, then triangle ⌊*i* / 3⌋ is an exterior triangle on the [convex hull](#delaunay_hull). For example, to render the internal edges of the Delaunay triangulation:
+
+```js
+const {points, halfedges, triangles} = delaunay;
+for (let i = 0, n = halfedges.length; i < n; ++i) {
+ const j = halfedges[i];
+ if (j < i) continue;
+ const ti = triangles[i];
+ const tj = triangles[j];
+ context.moveTo(points[ti * 2], points[ti * 2 + 1]);
+ context.lineTo(points[tj * 2], points[tj * 2 + 1]);
+}
+```
+
+See also [*delaunay*.render](#delaunay_render).
+
+# delaunay.hull
+
+An Int32Array of point indexes that form the convex hull in counterclockwise order. If the points are collinear, returns them ordered.
+
+See also [*delaunay*.renderHull](#delaunay_renderHull).
+
+# delaunay.triangles
+
+The triangle vertex indexes as an Uint32Array [*i0*, *j0*, *k0*, *i1*, *j1*, *k1*, …]. Each contiguous triplet of indexes *i*, *j*, *k* forms a counterclockwise triangle. The coordinates of the triangle’s points can be found by going through [*delaunay*.points](#delaunay_points). For example, to render triangle *i*:
+
+```js
+const {points, triangles} = delaunay;
+const t0 = triangles[i * 3 + 0];
+const t1 = triangles[i * 3 + 1];
+const t2 = triangles[i * 3 + 2];
+context.moveTo(points[t0 * 2], points[t0 * 2 + 1]);
+context.lineTo(points[t1 * 2], points[t1 * 2 + 1]);
+context.lineTo(points[t2 * 2], points[t2 * 2 + 1]);
+context.closePath();
+```
+
+See also [*delaunay*.renderTriangle](#delaunay_renderTriangle).
+
+# delaunay.inedges
+
+The incoming halfedge indexes as a Int32Array [*e0*, *e1*, *e2*, …]. For each point *i*, *inedges*[*i*] is the halfedge index *e* of an incoming halfedge. For coincident points, the halfedge index is -1; for points on the convex hull, the incoming halfedge is on the convex hull; for other points, the choice of incoming halfedge is arbitrary. The *inedges* table can be used to traverse the Delaunay triangulation; see also [*delaunay*.neighbors](#delaunay_neighbors).
+
+# delaunay.find(x, y[, i]) [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+Returns the index of the input point that is closest to the specified point ⟨*x*, *y*⟩. The search is started at the specified point *i*. If *i* is not specified, it defaults to zero.
+
+# delaunay.neighbors(i) [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+Returns an iterable over the indexes of the neighboring points to the specified point *i*. The iterable is empty if *i* is a coincident point.
+
+# delaunay.render([context]) [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+ +n,n.easePoly=a,n.easePolyIn=u,n.easePolyInOut=a,n.easePolyOut=r,n.easeQuad=e,n.easeQuadIn=function(n){return n*n},n.easeQuadInOut=e,n.easeQuadOut=function(n){return n*(2-n)},n.easeSin=c,n.easeSinIn=function(n){return 1==+n?1:1-Math.cos(n*i)},n.easeSinInOut=c,n.easeSinOut=function(n){return Math.sin(n*i)},Object.defineProperty(n,"__esModule",{value:!0})});
diff --git a/node_modules/d3-ease/package.json b/node_modules/d3-ease/package.json
new file mode 100644
index 00000000..6d0a7db7
--- /dev/null
+++ b/node_modules/d3-ease/package.json
@@ -0,0 +1,73 @@
+{
+ "_from": "d3-ease@2",
+ "_id": "d3-ease@2.0.0",
+ "_inBundle": false,
+ "_integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==",
+ "_location": "/d3-ease",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "d3-ease@2",
+ "name": "d3-ease",
+ "escapedName": "d3-ease",
+ "rawSpec": "2",
+ "saveSpec": null,
+ "fetchSpec": "2"
+ },
+ "_requiredBy": [
+ "/d3",
+ "/d3-transition"
+ ],
+ "_resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz",
+ "_shasum": "fd1762bfca00dae4bacea504b1d628ff290ac563",
+ "_spec": "d3-ease@2",
+ "_where": "C:\\Users\\rin\\Desktop\\final\\node_modules\\d3",
+ "author": {
+ "name": "Mike Bostock",
+ "url": "http://bost.ocks.org/mike"
+ },
+ "bugs": {
+ "url": "https://github.com/d3/d3-ease/issues"
+ },
+ "bundleDependencies": false,
+ "deprecated": false,
+ "description": "Easing functions for smooth animation.",
+ "devDependencies": {
+ "eslint": "6",
+ "rollup": "1",
+ "rollup-plugin-terser": "5",
+ "tape": "4"
+ },
+ "files": [
+ "dist/**/*.js",
+ "src/**/*.js"
+ ],
+ "homepage": "https://d3js.org/d3-ease/",
+ "jsdelivr": "dist/d3-ease.min.js",
+ "keywords": [
+ "d3",
+ "d3-module",
+ "ease",
+ "easing",
+ "animation",
+ "transition"
+ ],
+ "license": "BSD-3-Clause",
+ "main": "dist/d3-ease.js",
+ "module": "src/index.js",
+ "name": "d3-ease",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/d3/d3-ease.git"
+ },
+ "scripts": {
+ "postpublish": "git push && git push --tags && cd ../d3.github.com && git pull && cp ../${npm_package_name}/dist/${npm_package_name}.js ${npm_package_name}.v${npm_package_version%%.*}.js && cp ../${npm_package_name}/dist/${npm_package_name}.min.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git add ${npm_package_name}.v${npm_package_version%%.*}.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git commit -m \"${npm_package_name} ${npm_package_version}\" && git push && cd - && zip -j dist/${npm_package_name}.zip -- LICENSE README.md dist/${npm_package_name}.js dist/${npm_package_name}.min.js",
+ "prepublishOnly": "rm -rf dist && yarn test",
+ "pretest": "rollup -c",
+ "test": "tape 'test/**/*-test.js' && eslint src test"
+ },
+ "sideEffects": false,
+ "unpkg": "dist/d3-ease.min.js",
+ "version": "2.0.0"
+}
diff --git a/node_modules/d3-ease/src/back.js b/node_modules/d3-ease/src/back.js
new file mode 100644
index 00000000..b9c1bcc9
--- /dev/null
+++ b/node_modules/d3-ease/src/back.js
@@ -0,0 +1,37 @@
+var overshoot = 1.70158;
+
+export var backIn = (function custom(s) {
+ s = +s;
+
+ function backIn(t) {
+ return (t = +t) * t * (s * (t - 1) + t);
+ }
+
+ backIn.overshoot = custom;
+
+ return backIn;
+})(overshoot);
+
+export var backOut = (function custom(s) {
+ s = +s;
+
+ function backOut(t) {
+ return --t * t * ((t + 1) * s + t) + 1;
+ }
+
+ backOut.overshoot = custom;
+
+ return backOut;
+})(overshoot);
+
+export var backInOut = (function custom(s) {
+ s = +s;
+
+ function backInOut(t) {
+ return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
+ }
+
+ backInOut.overshoot = custom;
+
+ return backInOut;
+})(overshoot);
diff --git a/node_modules/d3-ease/src/bounce.js b/node_modules/d3-ease/src/bounce.js
new file mode 100644
index 00000000..d2d81caf
--- /dev/null
+++ b/node_modules/d3-ease/src/bounce.js
@@ -0,0 +1,22 @@
+var b1 = 4 / 11,
+ b2 = 6 / 11,
+ b3 = 8 / 11,
+ b4 = 3 / 4,
+ b5 = 9 / 11,
+ b6 = 10 / 11,
+ b7 = 15 / 16,
+ b8 = 21 / 22,
+ b9 = 63 / 64,
+ b0 = 1 / b1 / b1;
+
+export function bounceIn(t) {
+ return 1 - bounceOut(1 - t);
+}
+
+export function bounceOut(t) {
+ return (t = +t) < b1 ? b0 * t * t : t < b3 ? b0 * (t -= b2) * t + b4 : t < b6 ? b0 * (t -= b5) * t + b7 : b0 * (t -= b8) * t + b9;
+}
+
+export function bounceInOut(t) {
+ return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
+}
diff --git a/node_modules/d3-ease/src/circle.js b/node_modules/d3-ease/src/circle.js
new file mode 100644
index 00000000..8b9bb1de
--- /dev/null
+++ b/node_modules/d3-ease/src/circle.js
@@ -0,0 +1,11 @@
+export function circleIn(t) {
+ return 1 - Math.sqrt(1 - t * t);
+}
+
+export function circleOut(t) {
+ return Math.sqrt(1 - --t * t);
+}
+
+export function circleInOut(t) {
+ return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
+}
diff --git a/node_modules/d3-ease/src/cubic.js b/node_modules/d3-ease/src/cubic.js
new file mode 100644
index 00000000..bad3a7ca
--- /dev/null
+++ b/node_modules/d3-ease/src/cubic.js
@@ -0,0 +1,11 @@
+export function cubicIn(t) {
+ return t * t * t;
+}
+
+export function cubicOut(t) {
+ return --t * t * t + 1;
+}
+
+export function cubicInOut(t) {
+ return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
+}
diff --git a/node_modules/d3-ease/src/elastic.js b/node_modules/d3-ease/src/elastic.js
new file mode 100644
index 00000000..48ca6733
--- /dev/null
+++ b/node_modules/d3-ease/src/elastic.js
@@ -0,0 +1,46 @@
+import {tpmt} from "./math.js";
+
+var tau = 2 * Math.PI,
+ amplitude = 1,
+ period = 0.3;
+
+export var elasticIn = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticIn(t) {
+ return a * tpmt(-(--t)) * Math.sin((s - t) / p);
+ }
+
+ elasticIn.amplitude = function(a) { return custom(a, p * tau); };
+ elasticIn.period = function(p) { return custom(a, p); };
+
+ return elasticIn;
+})(amplitude, period);
+
+export var elasticOut = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticOut(t) {
+ return 1 - a * tpmt(t = +t) * Math.sin((t + s) / p);
+ }
+
+ elasticOut.amplitude = function(a) { return custom(a, p * tau); };
+ elasticOut.period = function(p) { return custom(a, p); };
+
+ return elasticOut;
+})(amplitude, period);
+
+export var elasticInOut = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticInOut(t) {
+ return ((t = t * 2 - 1) < 0
+ ? a * tpmt(-t) * Math.sin((s - t) / p)
+ : 2 - a * tpmt(t) * Math.sin((s + t) / p)) / 2;
+ }
+
+ elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
+ elasticInOut.period = function(p) { return custom(a, p); };
+
+ return elasticInOut;
+})(amplitude, period);
diff --git a/node_modules/d3-ease/src/exp.js b/node_modules/d3-ease/src/exp.js
new file mode 100644
index 00000000..f3c1cf0f
--- /dev/null
+++ b/node_modules/d3-ease/src/exp.js
@@ -0,0 +1,13 @@
+import {tpmt} from "./math.js";
+
+export function expIn(t) {
+ return tpmt(1 - +t);
+}
+
+export function expOut(t) {
+ return 1 - tpmt(t);
+}
+
+export function expInOut(t) {
+ return ((t *= 2) <= 1 ? tpmt(1 - t) : 2 - tpmt(t - 1)) / 2;
+}
diff --git a/node_modules/d3-ease/src/index.js b/node_modules/d3-ease/src/index.js
new file mode 100644
index 00000000..710d3df5
--- /dev/null
+++ b/node_modules/d3-ease/src/index.js
@@ -0,0 +1,66 @@
+export {
+ linear as easeLinear
+} from "./linear.js";
+
+export {
+ quadInOut as easeQuad,
+ quadIn as easeQuadIn,
+ quadOut as easeQuadOut,
+ quadInOut as easeQuadInOut
+} from "./quad.js";
+
+export {
+ cubicInOut as easeCubic,
+ cubicIn as easeCubicIn,
+ cubicOut as easeCubicOut,
+ cubicInOut as easeCubicInOut
+} from "./cubic.js";
+
+export {
+ polyInOut as easePoly,
+ polyIn as easePolyIn,
+ polyOut as easePolyOut,
+ polyInOut as easePolyInOut
+} from "./poly.js";
+
+export {
+ sinInOut as easeSin,
+ sinIn as easeSinIn,
+ sinOut as easeSinOut,
+ sinInOut as easeSinInOut
+} from "./sin.js";
+
+export {
+ expInOut as easeExp,
+ expIn as easeExpIn,
+ expOut as easeExpOut,
+ expInOut as easeExpInOut
+} from "./exp.js";
+
+export {
+ circleInOut as easeCircle,
+ circleIn as easeCircleIn,
+ circleOut as easeCircleOut,
+ circleInOut as easeCircleInOut
+} from "./circle.js";
+
+export {
+ bounceOut as easeBounce,
+ bounceIn as easeBounceIn,
+ bounceOut as easeBounceOut,
+ bounceInOut as easeBounceInOut
+} from "./bounce.js";
+
+export {
+ backInOut as easeBack,
+ backIn as easeBackIn,
+ backOut as easeBackOut,
+ backInOut as easeBackInOut
+} from "./back.js";
+
+export {
+ elasticOut as easeElastic,
+ elasticIn as easeElasticIn,
+ elasticOut as easeElasticOut,
+ elasticInOut as easeElasticInOut
+} from "./elastic.js";
diff --git a/node_modules/d3-ease/src/linear.js b/node_modules/d3-ease/src/linear.js
new file mode 100644
index 00000000..7b7d2c11
--- /dev/null
+++ b/node_modules/d3-ease/src/linear.js
@@ -0,0 +1 @@
+export const linear = t => +t;
diff --git a/node_modules/d3-ease/src/math.js b/node_modules/d3-ease/src/math.js
new file mode 100644
index 00000000..d342db17
--- /dev/null
+++ b/node_modules/d3-ease/src/math.js
@@ -0,0 +1,4 @@
+// tpmt is two power minus ten times t scaled to [0,1]
+export function tpmt(x) {
+ return (Math.pow(2, -10 * x) - 0.0009765625) * 1.0009775171065494;
+}
diff --git a/node_modules/d3-ease/src/poly.js b/node_modules/d3-ease/src/poly.js
new file mode 100644
index 00000000..827cf874
--- /dev/null
+++ b/node_modules/d3-ease/src/poly.js
@@ -0,0 +1,37 @@
+var exponent = 3;
+
+export var polyIn = (function custom(e) {
+ e = +e;
+
+ function polyIn(t) {
+ return Math.pow(t, e);
+ }
+
+ polyIn.exponent = custom;
+
+ return polyIn;
+})(exponent);
+
+export var polyOut = (function custom(e) {
+ e = +e;
+
+ function polyOut(t) {
+ return 1 - Math.pow(1 - t, e);
+ }
+
+ polyOut.exponent = custom;
+
+ return polyOut;
+})(exponent);
+
+export var polyInOut = (function custom(e) {
+ e = +e;
+
+ function polyInOut(t) {
+ return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
+ }
+
+ polyInOut.exponent = custom;
+
+ return polyInOut;
+})(exponent);
diff --git a/node_modules/d3-ease/src/quad.js b/node_modules/d3-ease/src/quad.js
new file mode 100644
index 00000000..df65bc29
--- /dev/null
+++ b/node_modules/d3-ease/src/quad.js
@@ -0,0 +1,11 @@
+export function quadIn(t) {
+ return t * t;
+}
+
+export function quadOut(t) {
+ return t * (2 - t);
+}
+
+export function quadInOut(t) {
+ return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
+}
diff --git a/node_modules/d3-ease/src/sin.js b/node_modules/d3-ease/src/sin.js
new file mode 100644
index 00000000..d8e09b8e
--- /dev/null
+++ b/node_modules/d3-ease/src/sin.js
@@ -0,0 +1,14 @@
+var pi = Math.PI,
+ halfPi = pi / 2;
+
+export function sinIn(t) {
+ return (+t === 1) ? 1 : 1 - Math.cos(t * halfPi);
+}
+
+export function sinOut(t) {
+ return Math.sin(t * halfPi);
+}
+
+export function sinInOut(t) {
+ return (1 - Math.cos(pi * t)) / 2;
+}
diff --git a/node_modules/d3-fetch/LICENSE b/node_modules/d3-fetch/LICENSE
new file mode 100644
index 00000000..fb54fc9e
--- /dev/null
+++ b/node_modules/d3-fetch/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2016 Mike Bostock
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the author nor the names of contributors may be used to
+ endorse or promote products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node_modules/d3-fetch/README.md b/node_modules/d3-fetch/README.md
new file mode 100644
index 00000000..36283fb5
--- /dev/null
+++ b/node_modules/d3-fetch/README.md
@@ -0,0 +1,104 @@
+# d3-fetch
+
+This module provides convenient parsing on top of [Fetch](https://fetch.spec.whatwg.org/). For example, to load a text file:
+
+```js
+d3.text("/path/to/file.txt").then(function(text) {
+ console.log(text); // Hello, world!
+});
+```
+
+To load and parse a CSV file:
+
+```js
+d3.csv("/path/to/file.csv").then(function(data) {
+ console.log(data); // [{"Hello": "world"}, …]
+});
+```
+
+This module has built-in support for parsing [JSON](#json), [CSV](#csv), and [TSV](#tsv). You can parse additional formats by using [text](#text) directly. (This module replaced [d3-request](https://github.com/d3/d3-request).)
+
+## Installing
+
+If you use NPM, `npm install d3-fetch`. Otherwise, download the [latest release](https://github.com/d3/d3-fetch/releases/latest). You can also load directly from [d3js.org](https://d3js.org) as a [standalone library](https://d3js.org/d3-fetch.v1.min.js). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:
+
+```html
+
+
+
+```
+
+## API Reference
+
+# d3.blob(input[, init]) [<>](https://github.com/d3/d3-fetch/blob/master/src/blob.js "Source")
+
+Fetches the binary file at the specified *input* URL as a Blob. If *init* is specified, it is passed along to the underlying call to [fetch](https://fetch.spec.whatwg.org/#fetch-method); see [RequestInit](https://fetch.spec.whatwg.org/#requestinit) for allowed fields.
+
+# d3.buffer(input[, init]) [<>](https://github.com/d3/d3-fetch/blob/master/src/buffer.js "Source")
+
+Fetches the binary file at the specified *input* URL as an ArrayBuffer. If *init* is specified, it is passed along to the underlying call to [fetch](https://fetch.spec.whatwg.org/#fetch-method); see [RequestInit](https://fetch.spec.whatwg.org/#requestinit) for allowed fields.
+
+# d3.csv(input[, init][, row]) [<>](https://github.com/d3/d3-fetch/blob/master/src/dsv.js "Source")
+
+Equivalent to [d3.dsv](#dsv) with the comma character as the delimiter.
+
+# d3.dsv(delimiter, input[, init][, row]) [<>](https://github.com/d3/d3-fetch/blob/master/src/dsv.js "Source")
+
+Fetches the [DSV](https://github.com/d3/d3-dsv) file at the specified *input* URL. If *init* is specified, it is passed along to the underlying call to [fetch](https://fetch.spec.whatwg.org/#fetch-method); see [RequestInit](https://fetch.spec.whatwg.org/#requestinit) for allowed fields. An optional *row* conversion function may be specified to map and filter row objects to a more-specific representation; see [*dsv*.parse](https://github.com/d3/d3-dsv#dsv_parse) for details. For example:
+
+```js
+d3.dsv(",", "test.csv", function(d) {
+ return {
+ year: new Date(+d.Year, 0, 1), // convert "Year" column to Date
+ make: d.Make,
+ model: d.Model,
+ length: +d.Length // convert "Length" column to number
+ };
+}).then(function(data) {
+ console.log(data);
+});
+```
+
+If only one of *init* and *row* is specified, it is interpreted as the *row* conversion function if it is a function, and otherwise an *init* object.
+
+See also [d3.csv](#csv) and [d3.tsv](#tsv).
+
+# d3.html(input[, init]) [<>](https://github.com/d3/d3-fetch/blob/master/src/xml.js "Source")
+
+Fetches the file at the specified *input* URL as [text](#text) and then [parses it](https://developer.mozilla.org/docs/Web/API/DOMParser) as HTML. If *init* is specified, it is passed along to the underlying call to [fetch](https://fetch.spec.whatwg.org/#fetch-method); see [RequestInit](https://fetch.spec.whatwg.org/#requestinit) for allowed fields.
+
+# d3.image(input[, init]) [<>](https://github.com/d3/d3-fetch/blob/master/src/image.js "Source")
+
+Fetches the image at the specified *input* URL. If *init* is specified, sets any additional properties on the image before loading. For example, to enable an anonymous [cross-origin request](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image):
+
+```js
+d3.image("https://example.com/test.png", {crossOrigin: "anonymous"}).then(function(img) {
+ console.log(img);
+});
+```
+
+# d3.json(input[, init]) [<>](https://github.com/d3/d3-fetch/blob/master/src/json.js "Source")
+
+Fetches the [JSON](http://json.org) file at the specified *input* URL. If *init* is specified, it is passed along to the underlying call to [fetch](https://fetch.spec.whatwg.org/#fetch-method); see [RequestInit](https://fetch.spec.whatwg.org/#requestinit) for allowed fields. If the server returns a status code of [204 No Content](https://developer.mozilla.org/docs/Web/HTTP/Status/204) or [205 Reset Content](https://developer.mozilla.org/docs/Web/HTTP/Status/205), the promise resolves to `undefined`.
+
+# d3.svg(input[, init]) [<>](https://github.com/d3/d3-fetch/blob/master/src/xml.js "Source")
+
+Fetches the file at the specified *input* URL as [text](#text) and then [parses it](https://developer.mozilla.org/docs/Web/API/DOMParser) as SVG. If *init* is specified, it is passed along to the underlying call to [fetch](https://fetch.spec.whatwg.org/#fetch-method); see [RequestInit](https://fetch.spec.whatwg.org/#requestinit) for allowed fields.
+
+# d3.text(input[, init]) [<>](https://github.com/d3/d3-fetch/blob/master/src/text.js "Source")
+
+Fetches the text file at the specified *input* URL. If *init* is specified, it is passed along to the underlying call to [fetch](https://fetch.spec.whatwg.org/#fetch-method); see [RequestInit](https://fetch.spec.whatwg.org/#requestinit) for allowed fields.
+
+# d3.tsv(input[, init][, row]) [<>](https://github.com/d3/d3-fetch/blob/master/src/dsv.js "Source")
+
+Equivalent to [d3.dsv](#dsv) with the tab character as the delimiter.
+
+# d3.xml(input[, init]) [<>](https://github.com/d3/d3-fetch/blob/master/src/xml.js "Source")
+
+Fetches the file at the specified *input* URL as [text](#text) and then [parses it](https://developer.mozilla.org/docs/Web/API/DOMParser) as XML. If *init* is specified, it is passed along to the underlying call to [fetch](https://fetch.spec.whatwg.org/#fetch-method); see [RequestInit](https://fetch.spec.whatwg.org/#requestinit) for allowed fields.
diff --git a/node_modules/d3-fetch/dist/d3-fetch.js b/node_modules/d3-fetch/dist/d3-fetch.js
new file mode 100644
index 00000000..81c7e1a5
--- /dev/null
+++ b/node_modules/d3-fetch/dist/d3-fetch.js
@@ -0,0 +1,100 @@
+// https://d3js.org/d3-fetch/ v2.0.0 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-dsv')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-dsv'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}, global.d3));
+}(this, function (exports, d3Dsv) { 'use strict';
+
+function responseBlob(response) {
+ if (!response.ok) throw new Error(response.status + " " + response.statusText);
+ return response.blob();
+}
+
+function blob(input, init) {
+ return fetch(input, init).then(responseBlob);
+}
+
+function responseArrayBuffer(response) {
+ if (!response.ok) throw new Error(response.status + " " + response.statusText);
+ return response.arrayBuffer();
+}
+
+function buffer(input, init) {
+ return fetch(input, init).then(responseArrayBuffer);
+}
+
+function responseText(response) {
+ if (!response.ok) throw new Error(response.status + " " + response.statusText);
+ return response.text();
+}
+
+function text(input, init) {
+ return fetch(input, init).then(responseText);
+}
+
+function dsvParse(parse) {
+ return function(input, init, row) {
+ if (arguments.length === 2 && typeof init === "function") row = init, init = undefined;
+ return text(input, init).then(function(response) {
+ return parse(response, row);
+ });
+ };
+}
+
+function dsv(delimiter, input, init, row) {
+ if (arguments.length === 3 && typeof init === "function") row = init, init = undefined;
+ var format = d3Dsv.dsvFormat(delimiter);
+ return text(input, init).then(function(response) {
+ return format.parse(response, row);
+ });
+}
+
+var csv = dsvParse(d3Dsv.csvParse);
+var tsv = dsvParse(d3Dsv.tsvParse);
+
+function image(input, init) {
+ return new Promise(function(resolve, reject) {
+ var image = new Image;
+ for (var key in init) image[key] = init[key];
+ image.onerror = reject;
+ image.onload = function() { resolve(image); };
+ image.src = input;
+ });
+}
+
+function responseJson(response) {
+ if (!response.ok) throw new Error(response.status + " " + response.statusText);
+ if (response.status === 204 || response.status === 205) return;
+ return response.json();
+}
+
+function json(input, init) {
+ return fetch(input, init).then(responseJson);
+}
+
+function parser(type) {
+ return (input, init) => text(input, init)
+ .then(text => (new DOMParser).parseFromString(text, type));
+}
+
+var xml = parser("application/xml");
+
+var html = parser("text/html");
+
+var svg = parser("image/svg+xml");
+
+exports.blob = blob;
+exports.buffer = buffer;
+exports.csv = csv;
+exports.dsv = dsv;
+exports.html = html;
+exports.image = image;
+exports.json = json;
+exports.svg = svg;
+exports.text = text;
+exports.tsv = tsv;
+exports.xml = xml;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-fetch/dist/d3-fetch.min.js b/node_modules/d3-fetch/dist/d3-fetch.min.js
new file mode 100644
index 00000000..205ed452
--- /dev/null
+++ b/node_modules/d3-fetch/dist/d3-fetch.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-fetch/ v2.0.0 Copyright 2020 Mike Bostock
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("d3-dsv")):"function"==typeof define&&define.amd?define(["exports","d3-dsv"],n):n((t=t||self).d3=t.d3||{},t.d3)}(this,function(t,n){"use strict";function e(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function r(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function o(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function u(t,n){return fetch(t,n).then(o)}function f(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=void 0),u(n,e).then(function(n){return t(n,r)})}}var s=f(n.csvParse),i=f(n.tsvParse);function c(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);if(204!==t.status&&205!==t.status)return t.json()}function a(t){return(n,e)=>u(n,e).then(n=>(new DOMParser).parseFromString(n,t))}var d=a("application/xml"),h=a("text/html"),v=a("image/svg+xml");t.blob=function(t,n){return fetch(t,n).then(e)},t.buffer=function(t,n){return fetch(t,n).then(r)},t.csv=s,t.dsv=function(t,e,r,o){3===arguments.length&&"function"==typeof r&&(o=r,r=void 0);var f=n.dsvFormat(t);return u(e,r).then(function(t){return f.parse(t,o)})},t.html=h,t.image=function(t,n){return new Promise(function(e,r){var o=new Image;for(var u in n)o[u]=n[u];o.onerror=r,o.onload=function(){e(o)},o.src=t})},t.json=function(t,n){return fetch(t,n).then(c)},t.svg=v,t.text=u,t.tsv=i,t.xml=d,Object.defineProperty(t,"__esModule",{value:!0})});
diff --git a/node_modules/d3-fetch/package.json b/node_modules/d3-fetch/package.json
new file mode 100644
index 00000000..b2906a2d
--- /dev/null
+++ b/node_modules/d3-fetch/package.json
@@ -0,0 +1,74 @@
+{
+ "_from": "d3-fetch@2",
+ "_id": "d3-fetch@2.0.0",
+ "_inBundle": false,
+ "_integrity": "sha512-TkYv/hjXgCryBeNKiclrwqZH7Nb+GaOwo3Neg24ZVWA3MKB+Rd+BY84Nh6tmNEMcjUik1CSUWjXYndmeO6F7sw==",
+ "_location": "/d3-fetch",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "d3-fetch@2",
+ "name": "d3-fetch",
+ "escapedName": "d3-fetch",
+ "rawSpec": "2",
+ "saveSpec": null,
+ "fetchSpec": "2"
+ },
+ "_requiredBy": [
+ "/d3"
+ ],
+ "_resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-2.0.0.tgz",
+ "_shasum": "ecd7ef2128d9847a3b41b548fec80918d645c064",
+ "_spec": "d3-fetch@2",
+ "_where": "C:\\Users\\rin\\Desktop\\final\\node_modules\\d3",
+ "author": {
+ "name": "Mike Bostock",
+ "url": "http://bost.ocks.org/mike"
+ },
+ "bugs": {
+ "url": "https://github.com/d3/d3-fetch/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "d3-dsv": "1 - 2"
+ },
+ "deprecated": false,
+ "description": "Convenient parsing for Fetch.",
+ "devDependencies": {
+ "eslint": "6",
+ "rollup": "1",
+ "rollup-plugin-terser": "5",
+ "tape": "4"
+ },
+ "files": [
+ "dist/**/*.js",
+ "src/**/*.js"
+ ],
+ "homepage": "https://d3js.org/d3-fetch/",
+ "jsdelivr": "dist/d3-fetch.min.js",
+ "keywords": [
+ "d3",
+ "d3-module",
+ "fetch",
+ "ajax",
+ "XMLHttpRequest"
+ ],
+ "license": "BSD-3-Clause",
+ "main": "dist/d3-fetch.js",
+ "module": "src/index.js",
+ "name": "d3-fetch",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/d3/d3-fetch.git"
+ },
+ "scripts": {
+ "postpublish": "git push && git push --tags && cd ../d3.github.com && git pull && cp ../${npm_package_name}/dist/${npm_package_name}.js ${npm_package_name}.v${npm_package_version%%.*}.js && cp ../${npm_package_name}/dist/${npm_package_name}.min.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git add ${npm_package_name}.v${npm_package_version%%.*}.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git commit -m \"${npm_package_name} ${npm_package_version}\" && git push && cd - && zip -j dist/${npm_package_name}.zip -- LICENSE README.md dist/${npm_package_name}.js dist/${npm_package_name}.min.js",
+ "prepublishOnly": "rm -rf dist && yarn test",
+ "pretest": "rollup -c",
+ "test": "tape 'test/**/*-test.js' && eslint src"
+ },
+ "sideEffects": false,
+ "unpkg": "dist/d3-fetch.min.js",
+ "version": "2.0.0"
+}
diff --git a/node_modules/d3-fetch/src/blob.js b/node_modules/d3-fetch/src/blob.js
new file mode 100644
index 00000000..646664c3
--- /dev/null
+++ b/node_modules/d3-fetch/src/blob.js
@@ -0,0 +1,8 @@
+function responseBlob(response) {
+ if (!response.ok) throw new Error(response.status + " " + response.statusText);
+ return response.blob();
+}
+
+export default function(input, init) {
+ return fetch(input, init).then(responseBlob);
+}
diff --git a/node_modules/d3-fetch/src/buffer.js b/node_modules/d3-fetch/src/buffer.js
new file mode 100644
index 00000000..f776a94b
--- /dev/null
+++ b/node_modules/d3-fetch/src/buffer.js
@@ -0,0 +1,8 @@
+function responseArrayBuffer(response) {
+ if (!response.ok) throw new Error(response.status + " " + response.statusText);
+ return response.arrayBuffer();
+}
+
+export default function(input, init) {
+ return fetch(input, init).then(responseArrayBuffer);
+}
diff --git a/node_modules/d3-fetch/src/dsv.js b/node_modules/d3-fetch/src/dsv.js
new file mode 100644
index 00000000..99d7bc39
--- /dev/null
+++ b/node_modules/d3-fetch/src/dsv.js
@@ -0,0 +1,22 @@
+import {csvParse, dsvFormat, tsvParse} from "d3-dsv";
+import text from "./text.js";
+
+function dsvParse(parse) {
+ return function(input, init, row) {
+ if (arguments.length === 2 && typeof init === "function") row = init, init = undefined;
+ return text(input, init).then(function(response) {
+ return parse(response, row);
+ });
+ };
+}
+
+export default function dsv(delimiter, input, init, row) {
+ if (arguments.length === 3 && typeof init === "function") row = init, init = undefined;
+ var format = dsvFormat(delimiter);
+ return text(input, init).then(function(response) {
+ return format.parse(response, row);
+ });
+}
+
+export var csv = dsvParse(csvParse);
+export var tsv = dsvParse(tsvParse);
diff --git a/node_modules/d3-fetch/src/image.js b/node_modules/d3-fetch/src/image.js
new file mode 100644
index 00000000..c80a74bc
--- /dev/null
+++ b/node_modules/d3-fetch/src/image.js
@@ -0,0 +1,9 @@
+export default function(input, init) {
+ return new Promise(function(resolve, reject) {
+ var image = new Image;
+ for (var key in init) image[key] = init[key];
+ image.onerror = reject;
+ image.onload = function() { resolve(image); };
+ image.src = input;
+ });
+}
diff --git a/node_modules/d3-fetch/src/index.js b/node_modules/d3-fetch/src/index.js
new file mode 100644
index 00000000..f3ac0f99
--- /dev/null
+++ b/node_modules/d3-fetch/src/index.js
@@ -0,0 +1,7 @@
+export {default as blob} from "./blob.js";
+export {default as buffer} from "./buffer.js";
+export {default as dsv, csv, tsv} from "./dsv.js";
+export {default as image} from "./image.js";
+export {default as json} from "./json.js";
+export {default as text} from "./text.js";
+export {default as xml, html, svg} from "./xml.js";
diff --git a/node_modules/d3-fetch/src/json.js b/node_modules/d3-fetch/src/json.js
new file mode 100644
index 00000000..25e9798d
--- /dev/null
+++ b/node_modules/d3-fetch/src/json.js
@@ -0,0 +1,9 @@
+function responseJson(response) {
+ if (!response.ok) throw new Error(response.status + " " + response.statusText);
+ if (response.status === 204 || response.status === 205) return;
+ return response.json();
+}
+
+export default function(input, init) {
+ return fetch(input, init).then(responseJson);
+}
diff --git a/node_modules/d3-fetch/src/text.js b/node_modules/d3-fetch/src/text.js
new file mode 100644
index 00000000..8ea18f8e
--- /dev/null
+++ b/node_modules/d3-fetch/src/text.js
@@ -0,0 +1,8 @@
+function responseText(response) {
+ if (!response.ok) throw new Error(response.status + " " + response.statusText);
+ return response.text();
+}
+
+export default function(input, init) {
+ return fetch(input, init).then(responseText);
+}
diff --git a/node_modules/d3-fetch/src/xml.js b/node_modules/d3-fetch/src/xml.js
new file mode 100644
index 00000000..56282804
--- /dev/null
+++ b/node_modules/d3-fetch/src/xml.js
@@ -0,0 +1,12 @@
+import text from "./text.js";
+
+function parser(type) {
+ return (input, init) => text(input, init)
+ .then(text => (new DOMParser).parseFromString(text, type));
+}
+
+export default parser("application/xml");
+
+export var html = parser("text/html");
+
+export var svg = parser("image/svg+xml");
diff --git a/node_modules/d3-force/LICENSE b/node_modules/d3-force/LICENSE
new file mode 100644
index 00000000..721bd22e
--- /dev/null
+++ b/node_modules/d3-force/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2010-2016 Mike Bostock
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the author nor the names of contributors may be used to
+ endorse or promote products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node_modules/d3-force/README.md b/node_modules/d3-force/README.md
new file mode 100644
index 00000000..08323395
--- /dev/null
+++ b/node_modules/d3-force/README.md
@@ -0,0 +1,468 @@
+# d3-force
+
+This module implements a [velocity Verlet](https://en.wikipedia.org/wiki/Verlet_integration) numerical integrator for simulating physical forces on particles. The simulation is simplified: it assumes a constant unit time step Δ*t* = 1 for each step, and a constant unit mass *m* = 1 for all particles. As a result, a force *F* acting on a particle is equivalent to a constant acceleration *a* over the time interval Δ*t*, and can be simulated simply by adding to the particle’s velocity, which is then added to the particle’s position.
+
+In the domain of information visualization, physical simulations are useful for studying [networks](http://bl.ocks.org/mbostock/ad70335eeef6d167bc36fd3c04378048) and [hierarchies](http://bl.ocks.org/mbostock/95aa92e2f4e8345aaa55a4a94d41ce37)!
+
+[ I&&(I=o):s^(a*W<(p=(p+360)%360-180)&&pI&&(I=t)),s?n 1?r:1)},t}(K);n.cluster=function(){var n=r,i=1,u=1,o=!1;function a(r){var a,f=0;r.eachAfter(function(r){var i=r.children;i?(r.x=function(n){return n.reduce(t,0)/n.length}(i),r.y=function(n){return 1+n.reduce(e,0)}(i)):(r.x=a?f+=n(r,a):0,r.y=0,a=r)});var c=function(n){for(var r;r=n.children;)n=r[0];return n}(r),h=function(n){for(var r;r=n.children;)n=r[r.length-1];return n}(r),l=c.x-n(c,h)/2,p=h.x+n(h,c)/2;return r.eachAfter(o?function(n){n.x=(n.x-r.x)*i,n.y=(r.y-n.y)*u}:function(n){n.x=(n.x-l)/(p-l)*i,n.y=(1-(r.y?n.y/r.y:1))*u})}return a.separation=function(r){return arguments.length?(n=r,a):n},a.size=function(n){return arguments.length?(o=!1,i=+n[0],u=+n[1],a):o?null:[i,u]},a.nodeSize=function(n){return arguments.length?(o=!0,i=+n[0],u=+n[1],a):o?[i,u]:null},a},n.hierarchy=u,n.pack=function(){var n=null,r=1,t=1,e=A;function i(i){return i.x=r/2,i.y=t/2,n?i.eachBefore(E(n)).eachAfter(S(e,.5)).eachBefore(k(1)):i.eachBefore(E(b)).eachAfter(S(A,1)).eachAfter(S(e,i.r/Math.min(r,t))).eachBefore(k(Math.min(r,t)/(2*i.r))),i}return i.radius=function(r){return arguments.length?(n=z(r),i):n},i.size=function(n){return arguments.length?(r=+n[0],t=+n[1],i):[r,t]},i.padding=function(n){return arguments.length?(e="function"==typeof n?n:q(+n),i):e},i},n.packEnclose=h,n.packSiblings=function(n){return M(n),n},n.partition=function(){var n=1,r=1,t=0,e=!1;function i(i){var u=i.height+1;return i.x0=i.y0=t,i.x1=n,i.y1=r/u,i.eachBefore(function(n,r){return function(e){e.children&&j(e,e.x0,n*(e.depth+1)/r,e.x1,n*(e.depth+2)/r);var i=e.x0,u=e.y0,o=e.x1-t,a=e.y1-t;o0)throw new Error("cycle");return u}return t.id=function(r){return arguments.length?(n=B(r),t):n},t.parentId=function(n){return arguments.length?(r=B(n),t):r},t},n.tree=function(){var n=L,r=1,t=1,e=null;function i(i){var f=function(n){for(var r,t,e,i,u,o=new H(n,0),a=[o];r=a.pop();)if(e=r._.children)for(r.children=new Array(u=e.length),i=u-1;i>=0;--i)a.push(t=r.children[i]=new H(e[i],i)),t.parent=r;return(o.parent=new H(null,0)).children=[o],o}(i);if(f.eachAfter(u),f.parent.m=-f.z,f.eachBefore(o),e)i.eachBefore(a);else{var c=i,h=i,l=i;i.eachBefore(function(n){n.x f-u){var g=e?(i*y+o*x)/e:o;n(r,d,x,i,u,g,f),n(d,t,y,g,u,o,f)}else{var m=e?(u*y+f*x)/e:f;n(r,d,x,i,u,o,m),n(d,t,y,i,m,o,f)}}(0,f,n.value,r,t,e,i)},n.treemapDice=j,n.treemapResquarify=U,n.treemapSlice=J,n.treemapSliceDice=function(n,r,t,e,i){(1&n.depth?J:j)(n,r,t,e,i)},n.treemapSquarify=Q,Object.defineProperty(n,"__esModule",{value:!0})});
diff --git a/node_modules/d3-hierarchy/package.json b/node_modules/d3-hierarchy/package.json
new file mode 100644
index 00000000..61ba83a6
--- /dev/null
+++ b/node_modules/d3-hierarchy/package.json
@@ -0,0 +1,77 @@
+{
+ "_from": "d3-hierarchy@2",
+ "_id": "d3-hierarchy@2.0.0",
+ "_inBundle": false,
+ "_integrity": "sha512-SwIdqM3HxQX2214EG9GTjgmCc/mbSx4mQBn+DuEETubhOw6/U3fmnji4uCVrmzOydMHSO1nZle5gh6HB/wdOzw==",
+ "_location": "/d3-hierarchy",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "d3-hierarchy@2",
+ "name": "d3-hierarchy",
+ "escapedName": "d3-hierarchy",
+ "rawSpec": "2",
+ "saveSpec": null,
+ "fetchSpec": "2"
+ },
+ "_requiredBy": [
+ "/d3"
+ ],
+ "_resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-2.0.0.tgz",
+ "_shasum": "dab88a58ca3e7a1bc6cab390e89667fcc6d20218",
+ "_spec": "d3-hierarchy@2",
+ "_where": "C:\\Users\\rin\\Desktop\\final\\node_modules\\d3",
+ "author": {
+ "name": "Mike Bostock",
+ "url": "http://bost.ocks.org/mike"
+ },
+ "bugs": {
+ "url": "https://github.com/d3/d3-hierarchy/issues"
+ },
+ "bundleDependencies": false,
+ "deprecated": false,
+ "description": "Layout algorithms for visualizing hierarchical data.",
+ "devDependencies": {
+ "benchmark": "^2.1.4",
+ "d3-array": "1.2.0 - 2",
+ "d3-dsv": "1 - 2",
+ "d3-random": "1.1.0 - 2",
+ "eslint": "6",
+ "rollup": "1",
+ "rollup-plugin-terser": "5",
+ "tape": "4"
+ },
+ "files": [
+ "dist/**/*.js",
+ "src/**/*.js"
+ ],
+ "homepage": "https://d3js.org/d3-hierarchy/",
+ "jsdelivr": "dist/d3-hierarchy.min.js",
+ "keywords": [
+ "d3",
+ "d3-module",
+ "layout",
+ "tree",
+ "treemap",
+ "hierarchy",
+ "infovis"
+ ],
+ "license": "BSD-3-Clause",
+ "main": "dist/d3-hierarchy.js",
+ "module": "src/index.js",
+ "name": "d3-hierarchy",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/d3/d3-hierarchy.git"
+ },
+ "scripts": {
+ "postpublish": "git push && git push --tags && cd ../d3.github.com && git pull && cp ../${npm_package_name}/dist/${npm_package_name}.js ${npm_package_name}.v${npm_package_version%%.*}.js && cp ../${npm_package_name}/dist/${npm_package_name}.min.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git add ${npm_package_name}.v${npm_package_version%%.*}.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git commit -m \"${npm_package_name} ${npm_package_version}\" && git push && cd - && zip -j dist/${npm_package_name}.zip -- LICENSE README.md dist/${npm_package_name}.js dist/${npm_package_name}.min.js",
+ "prepublishOnly": "rm -rf dist && yarn test",
+ "pretest": "rollup -c",
+ "test": "tape 'test/**/*-test.js' && eslint src test"
+ },
+ "sideEffects": false,
+ "unpkg": "dist/d3-hierarchy.min.js",
+ "version": "2.0.0"
+}
diff --git a/node_modules/d3-hierarchy/src/accessors.js b/node_modules/d3-hierarchy/src/accessors.js
new file mode 100644
index 00000000..369c4145
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/accessors.js
@@ -0,0 +1,8 @@
+export function optional(f) {
+ return f == null ? null : required(f);
+}
+
+export function required(f) {
+ if (typeof f !== "function") throw new Error;
+ return f;
+}
diff --git a/node_modules/d3-hierarchy/src/array.js b/node_modules/d3-hierarchy/src/array.js
new file mode 100644
index 00000000..df69e807
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/array.js
@@ -0,0 +1,20 @@
+export default function(x) {
+ return typeof x === "object" && "length" in x
+ ? x // Array, TypedArray, NodeList, array-like
+ : Array.from(x); // Map, Set, iterable, string, or anything else
+}
+
+export function shuffle(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;
+}
diff --git a/node_modules/d3-hierarchy/src/cluster.js b/node_modules/d3-hierarchy/src/cluster.js
new file mode 100644
index 00000000..f5a280e2
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/cluster.js
@@ -0,0 +1,84 @@
+function defaultSeparation(a, b) {
+ return a.parent === b.parent ? 1 : 2;
+}
+
+function meanX(children) {
+ return children.reduce(meanXReduce, 0) / children.length;
+}
+
+function meanXReduce(x, c) {
+ return x + c.x;
+}
+
+function maxY(children) {
+ return 1 + children.reduce(maxYReduce, 0);
+}
+
+function maxYReduce(y, c) {
+ return Math.max(y, c.y);
+}
+
+function leafLeft(node) {
+ var children;
+ while (children = node.children) node = children[0];
+ return node;
+}
+
+function leafRight(node) {
+ var children;
+ while (children = node.children) node = children[children.length - 1];
+ return node;
+}
+
+export default function() {
+ var separation = defaultSeparation,
+ dx = 1,
+ dy = 1,
+ nodeSize = false;
+
+ function cluster(root) {
+ var previousNode,
+ x = 0;
+
+ // First walk, computing the initial x & y values.
+ root.eachAfter(function(node) {
+ var children = node.children;
+ if (children) {
+ node.x = meanX(children);
+ node.y = maxY(children);
+ } else {
+ node.x = previousNode ? x += separation(node, previousNode) : 0;
+ node.y = 0;
+ previousNode = node;
+ }
+ });
+
+ var left = leafLeft(root),
+ right = leafRight(root),
+ x0 = left.x - separation(left, right) / 2,
+ x1 = right.x + separation(right, left) / 2;
+
+ // Second walk, normalizing x & y to the desired size.
+ return root.eachAfter(nodeSize ? function(node) {
+ node.x = (node.x - root.x) * dx;
+ node.y = (root.y - node.y) * dy;
+ } : function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * dx;
+ node.y = (1 - (root.y ? node.y / root.y : 1)) * dy;
+ });
+ }
+
+ cluster.separation = function(x) {
+ return arguments.length ? (separation = x, cluster) : separation;
+ };
+
+ cluster.size = function(x) {
+ return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? null : [dx, dy]);
+ };
+
+ cluster.nodeSize = function(x) {
+ return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? [dx, dy] : null);
+ };
+
+ return cluster;
+}
diff --git a/node_modules/d3-hierarchy/src/constant.js b/node_modules/d3-hierarchy/src/constant.js
new file mode 100644
index 00000000..1d947c4f
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/constant.js
@@ -0,0 +1,9 @@
+export function constantZero() {
+ return 0;
+}
+
+export default function(x) {
+ return function() {
+ return x;
+ };
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/ancestors.js b/node_modules/d3-hierarchy/src/hierarchy/ancestors.js
new file mode 100644
index 00000000..f70c7264
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/ancestors.js
@@ -0,0 +1,7 @@
+export default function() {
+ var node = this, nodes = [node];
+ while (node = node.parent) {
+ nodes.push(node);
+ }
+ return nodes;
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/count.js b/node_modules/d3-hierarchy/src/hierarchy/count.js
new file mode 100644
index 00000000..0b90f1bd
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/count.js
@@ -0,0 +1,12 @@
+function count(node) {
+ var sum = 0,
+ children = node.children,
+ i = children && children.length;
+ if (!i) sum = 1;
+ else while (--i >= 0) sum += children[i].value;
+ node.value = sum;
+}
+
+export default function() {
+ return this.eachAfter(count);
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/descendants.js b/node_modules/d3-hierarchy/src/hierarchy/descendants.js
new file mode 100644
index 00000000..7f38090d
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/descendants.js
@@ -0,0 +1,3 @@
+export default function() {
+ return Array.from(this);
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/each.js b/node_modules/d3-hierarchy/src/hierarchy/each.js
new file mode 100644
index 00000000..af911cc7
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/each.js
@@ -0,0 +1,7 @@
+export default function(callback, that) {
+ let index = -1;
+ for (const node of this) {
+ callback.call(that, node, ++index, this);
+ }
+ return this;
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/eachAfter.js b/node_modules/d3-hierarchy/src/hierarchy/eachAfter.js
new file mode 100644
index 00000000..a3f0a2c0
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/eachAfter.js
@@ -0,0 +1,15 @@
+export default function(callback, that) {
+ var node = this, nodes = [node], next = [], children, i, n, index = -1;
+ while (node = nodes.pop()) {
+ next.push(node);
+ if (children = node.children) {
+ for (i = 0, n = children.length; i < n; ++i) {
+ nodes.push(children[i]);
+ }
+ }
+ }
+ while (node = next.pop()) {
+ callback.call(that, node, ++index, this);
+ }
+ return this;
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/eachBefore.js b/node_modules/d3-hierarchy/src/hierarchy/eachBefore.js
new file mode 100644
index 00000000..f3cd524b
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/eachBefore.js
@@ -0,0 +1,12 @@
+export default function(callback, that) {
+ var node = this, nodes = [node], children, i, index = -1;
+ while (node = nodes.pop()) {
+ callback.call(that, node, ++index, this);
+ if (children = node.children) {
+ for (i = children.length - 1; i >= 0; --i) {
+ nodes.push(children[i]);
+ }
+ }
+ }
+ return this;
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/find.js b/node_modules/d3-hierarchy/src/hierarchy/find.js
new file mode 100644
index 00000000..f4ed8c68
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/find.js
@@ -0,0 +1,8 @@
+export default function(callback, that) {
+ let index = -1;
+ for (const node of this) {
+ if (callback.call(that, node, ++index, this)) {
+ return node;
+ }
+ }
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/index.js b/node_modules/d3-hierarchy/src/hierarchy/index.js
new file mode 100644
index 00000000..b9c1026f
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/index.js
@@ -0,0 +1,91 @@
+import node_count from "./count.js";
+import node_each from "./each.js";
+import node_eachBefore from "./eachBefore.js";
+import node_eachAfter from "./eachAfter.js";
+import node_find from "./find.js";
+import node_sum from "./sum.js";
+import node_sort from "./sort.js";
+import node_path from "./path.js";
+import node_ancestors from "./ancestors.js";
+import node_descendants from "./descendants.js";
+import node_leaves from "./leaves.js";
+import node_links from "./links.js";
+import node_iterator from "./iterator.js";
+
+export default function hierarchy(data, children) {
+ if (data instanceof Map) {
+ data = [undefined, data];
+ if (children === undefined) children = mapChildren;
+ } else if (children === undefined) {
+ children = objectChildren;
+ }
+
+ var root = new Node(data),
+ node,
+ nodes = [root],
+ child,
+ childs,
+ i,
+ n;
+
+ while (node = nodes.pop()) {
+ if ((childs = children(node.data)) && (n = (childs = Array.from(childs)).length)) {
+ node.children = childs;
+ for (i = n - 1; i >= 0; --i) {
+ nodes.push(child = childs[i] = new Node(childs[i]));
+ child.parent = node;
+ child.depth = node.depth + 1;
+ }
+ }
+ }
+
+ return root.eachBefore(computeHeight);
+}
+
+function node_copy() {
+ return hierarchy(this).eachBefore(copyData);
+}
+
+function objectChildren(d) {
+ return d.children;
+}
+
+function mapChildren(d) {
+ return Array.isArray(d) ? d[1] : null;
+}
+
+function copyData(node) {
+ if (node.data.value !== undefined) node.value = node.data.value;
+ node.data = node.data.data;
+}
+
+export function computeHeight(node) {
+ var height = 0;
+ do node.height = height;
+ while ((node = node.parent) && (node.height < ++height));
+}
+
+export function Node(data) {
+ this.data = data;
+ this.depth =
+ this.height = 0;
+ this.parent = null;
+}
+
+Node.prototype = hierarchy.prototype = {
+ constructor: Node,
+ count: node_count,
+ each: node_each,
+ eachAfter: node_eachAfter,
+ eachBefore: node_eachBefore,
+ find: node_find,
+ sum: node_sum,
+ sort: node_sort,
+ path: node_path,
+ ancestors: node_ancestors,
+ descendants: node_descendants,
+ leaves: node_leaves,
+ links: node_links,
+ copy: node_copy,
+ [Symbol.iterator]: node_iterator
+};
diff --git a/node_modules/d3-hierarchy/src/hierarchy/iterator.js b/node_modules/d3-hierarchy/src/hierarchy/iterator.js
new file mode 100644
index 00000000..7e06b620
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/iterator.js
@@ -0,0 +1,14 @@
+export default function*() {
+ var node = this, current, next = [node], children, i, n;
+ do {
+ current = next.reverse(), next = [];
+ while (node = current.pop()) {
+ yield node;
+ if (children = node.children) {
+ for (i = 0, n = children.length; i < n; ++i) {
+ next.push(children[i]);
+ }
+ }
+ }
+ } while (next.length);
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/leaves.js b/node_modules/d3-hierarchy/src/hierarchy/leaves.js
new file mode 100644
index 00000000..401c5b53
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/leaves.js
@@ -0,0 +1,9 @@
+export default function() {
+ var leaves = [];
+ this.eachBefore(function(node) {
+ if (!node.children) {
+ leaves.push(node);
+ }
+ });
+ return leaves;
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/links.js b/node_modules/d3-hierarchy/src/hierarchy/links.js
new file mode 100644
index 00000000..6fcb82fa
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/links.js
@@ -0,0 +1,9 @@
+export default function() {
+ var root = this, links = [];
+ root.each(function(node) {
+ if (node !== root) { // Don’t include the root’s parent, if any.
+ links.push({source: node.parent, target: node});
+ }
+ });
+ return links;
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/path.js b/node_modules/d3-hierarchy/src/hierarchy/path.js
new file mode 100644
index 00000000..99589138
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/path.js
@@ -0,0 +1,30 @@
+export default function(end) {
+ var start = this,
+ ancestor = leastCommonAncestor(start, end),
+ nodes = [start];
+ while (start !== ancestor) {
+ start = start.parent;
+ nodes.push(start);
+ }
+ var k = nodes.length;
+ while (end !== ancestor) {
+ nodes.splice(k, 0, end);
+ end = end.parent;
+ }
+ return nodes;
+}
+
+function leastCommonAncestor(a, b) {
+ if (a === b) return a;
+ var aNodes = a.ancestors(),
+ bNodes = b.ancestors(),
+ c = null;
+ a = aNodes.pop();
+ b = bNodes.pop();
+ while (a === b) {
+ c = a;
+ a = aNodes.pop();
+ b = bNodes.pop();
+ }
+ return c;
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/sort.js b/node_modules/d3-hierarchy/src/hierarchy/sort.js
new file mode 100644
index 00000000..5d0426d5
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/sort.js
@@ -0,0 +1,7 @@
+export default function(compare) {
+ return this.eachBefore(function(node) {
+ if (node.children) {
+ node.children.sort(compare);
+ }
+ });
+}
diff --git a/node_modules/d3-hierarchy/src/hierarchy/sum.js b/node_modules/d3-hierarchy/src/hierarchy/sum.js
new file mode 100644
index 00000000..350a965e
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/hierarchy/sum.js
@@ -0,0 +1,9 @@
+export default function(value) {
+ return this.eachAfter(function(node) {
+ var sum = +value(node.data) || 0,
+ children = node.children,
+ i = children && children.length;
+ while (--i >= 0) sum += children[i].value;
+ node.value = sum;
+ });
+}
diff --git a/node_modules/d3-hierarchy/src/index.js b/node_modules/d3-hierarchy/src/index.js
new file mode 100644
index 00000000..cd4cca39
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/index.js
@@ -0,0 +1,15 @@
+export {default as cluster} from "./cluster.js";
+export {default as hierarchy} from "./hierarchy/index.js";
+export {default as pack} from "./pack/index.js";
+export {default as packSiblings} from "./pack/siblings.js";
+export {default as packEnclose} from "./pack/enclose.js";
+export {default as partition} from "./partition.js";
+export {default as stratify} from "./stratify.js";
+export {default as tree} from "./tree.js";
+export {default as treemap} from "./treemap/index.js";
+export {default as treemapBinary} from "./treemap/binary.js";
+export {default as treemapDice} from "./treemap/dice.js";
+export {default as treemapSlice} from "./treemap/slice.js";
+export {default as treemapSliceDice} from "./treemap/sliceDice.js";
+export {default as treemapSquarify} from "./treemap/squarify.js";
+export {default as treemapResquarify} from "./treemap/resquarify.js";
diff --git a/node_modules/d3-hierarchy/src/pack/enclose.js b/node_modules/d3-hierarchy/src/pack/enclose.js
new file mode 100644
index 00000000..86231caa
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/pack/enclose.js
@@ -0,0 +1,118 @@
+import {shuffle} from "../array.js";
+
+export default function(circles) {
+ var i = 0, n = (circles = shuffle(Array.from(circles))).length, B = [], p, e;
+
+ while (i < n) {
+ p = circles[i];
+ if (e && enclosesWeak(e, p)) ++i;
+ else e = encloseBasis(B = extendBasis(B, p)), i = 0;
+ }
+
+ return e;
+}
+
+function extendBasis(B, p) {
+ var i, j;
+
+ if (enclosesWeakAll(p, B)) return [p];
+
+ // If we get here then B must have at least one element.
+ for (i = 0; i < B.length; ++i) {
+ if (enclosesNot(p, B[i])
+ && enclosesWeakAll(encloseBasis2(B[i], p), B)) {
+ return [B[i], p];
+ }
+ }
+
+ // If we get here then B must have at least two elements.
+ for (i = 0; i < B.length - 1; ++i) {
+ for (j = i + 1; j < B.length; ++j) {
+ if (enclosesNot(encloseBasis2(B[i], B[j]), p)
+ && enclosesNot(encloseBasis2(B[i], p), B[j])
+ && enclosesNot(encloseBasis2(B[j], p), B[i])
+ && enclosesWeakAll(encloseBasis3(B[i], B[j], p), B)) {
+ return [B[i], B[j], p];
+ }
+ }
+ }
+
+ // If we get here then something is very wrong.
+ throw new Error;
+}
+
+function enclosesNot(a, b) {
+ var dr = a.r - b.r, dx = b.x - a.x, dy = b.y - a.y;
+ return dr < 0 || dr * dr < dx * dx + dy * dy;
+}
+
+function enclosesWeak(a, b) {
+ var dr = a.r - b.r + Math.max(a.r, b.r, 1) * 1e-9, dx = b.x - a.x, dy = b.y - a.y;
+ return dr > 0 && dr * dr > dx * dx + dy * dy;
+}
+
+function enclosesWeakAll(a, B) {
+ for (var i = 0; i < B.length; ++i) {
+ if (!enclosesWeak(a, B[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function encloseBasis(B) {
+ switch (B.length) {
+ case 1: return encloseBasis1(B[0]);
+ case 2: return encloseBasis2(B[0], B[1]);
+ case 3: return encloseBasis3(B[0], B[1], B[2]);
+ }
+}
+
+function encloseBasis1(a) {
+ return {
+ x: a.x,
+ y: a.y,
+ r: a.r
+ };
+}
+
+function encloseBasis2(a, b) {
+ var x1 = a.x, y1 = a.y, r1 = a.r,
+ x2 = b.x, y2 = b.y, r2 = b.r,
+ x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
+ l = Math.sqrt(x21 * x21 + y21 * y21);
+ return {
+ x: (x1 + x2 + x21 / l * r21) / 2,
+ y: (y1 + y2 + y21 / l * r21) / 2,
+ r: (l + r1 + r2) / 2
+ };
+}
+
+function encloseBasis3(a, b, c) {
+ var x1 = a.x, y1 = a.y, r1 = a.r,
+ x2 = b.x, y2 = b.y, r2 = b.r,
+ x3 = c.x, y3 = c.y, r3 = c.r,
+ a2 = x1 - x2,
+ a3 = x1 - x3,
+ b2 = y1 - y2,
+ b3 = y1 - y3,
+ c2 = r2 - r1,
+ c3 = r3 - r1,
+ d1 = x1 * x1 + y1 * y1 - r1 * r1,
+ d2 = d1 - x2 * x2 - y2 * y2 + r2 * r2,
+ d3 = d1 - x3 * x3 - y3 * y3 + r3 * r3,
+ ab = a3 * b2 - a2 * b3,
+ xa = (b2 * d3 - b3 * d2) / (ab * 2) - x1,
+ xb = (b3 * c2 - b2 * c3) / ab,
+ ya = (a3 * d2 - a2 * d3) / (ab * 2) - y1,
+ yb = (a2 * c3 - a3 * c2) / ab,
+ A = xb * xb + yb * yb - 1,
+ B = 2 * (r1 + xa * xb + ya * yb),
+ C = xa * xa + ya * ya - r1 * r1,
+ r = -(A ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B);
+ return {
+ x: x1 + xa + xb * r,
+ y: y1 + ya + yb * r,
+ r: r
+ };
+}
diff --git a/node_modules/d3-hierarchy/src/pack/index.js b/node_modules/d3-hierarchy/src/pack/index.js
new file mode 100644
index 00000000..6ef2d7c9
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/pack/index.js
@@ -0,0 +1,79 @@
+import {packEnclose} from "./siblings.js";
+import {optional} from "../accessors.js";
+import constant, {constantZero} from "../constant.js";
+
+function defaultRadius(d) {
+ return Math.sqrt(d.value);
+}
+
+export default function() {
+ var radius = null,
+ dx = 1,
+ dy = 1,
+ padding = constantZero;
+
+ function pack(root) {
+ root.x = dx / 2, root.y = dy / 2;
+ if (radius) {
+ root.eachBefore(radiusLeaf(radius))
+ .eachAfter(packChildren(padding, 0.5))
+ .eachBefore(translateChild(1));
+ } else {
+ root.eachBefore(radiusLeaf(defaultRadius))
+ .eachAfter(packChildren(constantZero, 1))
+ .eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))
+ .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));
+ }
+ return root;
+ }
+
+ pack.radius = function(x) {
+ return arguments.length ? (radius = optional(x), pack) : radius;
+ };
+
+ pack.size = function(x) {
+ return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy];
+ };
+
+ pack.padding = function(x) {
+ return arguments.length ? (padding = typeof x === "function" ? x : constant(+x), pack) : padding;
+ };
+
+ return pack;
+}
+
+function radiusLeaf(radius) {
+ return function(node) {
+ if (!node.children) {
+ node.r = Math.max(0, +radius(node) || 0);
+ }
+ };
+}
+
+function packChildren(padding, k) {
+ return function(node) {
+ if (children = node.children) {
+ var children,
+ i,
+ n = children.length,
+ r = padding(node) * k || 0,
+ e;
+
+ if (r) for (i = 0; i < n; ++i) children[i].r += r;
+ e = packEnclose(children);
+ if (r) for (i = 0; i < n; ++i) children[i].r -= r;
+ node.r = e + r;
+ }
+ };
+}
+
+function translateChild(k) {
+ return function(node) {
+ var parent = node.parent;
+ node.r *= k;
+ if (parent) {
+ node.x = parent.x + k * node.x;
+ node.y = parent.y + k * node.y;
+ }
+ };
+}
diff --git a/node_modules/d3-hierarchy/src/pack/siblings.js b/node_modules/d3-hierarchy/src/pack/siblings.js
new file mode 100644
index 00000000..05047cfd
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/pack/siblings.js
@@ -0,0 +1,119 @@
+import array from "../array.js";
+import enclose from "./enclose.js";
+
+function place(b, a, c) {
+ var dx = b.x - a.x, x, a2,
+ dy = b.y - a.y, y, b2,
+ d2 = dx * dx + dy * dy;
+ if (d2) {
+ a2 = a.r + c.r, a2 *= a2;
+ b2 = b.r + c.r, b2 *= b2;
+ if (a2 > b2) {
+ x = (d2 + b2 - a2) / (2 * d2);
+ y = Math.sqrt(Math.max(0, b2 / d2 - x * x));
+ c.x = b.x - x * dx - y * dy;
+ c.y = b.y - x * dy + y * dx;
+ } else {
+ x = (d2 + a2 - b2) / (2 * d2);
+ y = Math.sqrt(Math.max(0, a2 / d2 - x * x));
+ c.x = a.x + x * dx - y * dy;
+ c.y = a.y + x * dy + y * dx;
+ }
+ } else {
+ c.x = a.x + c.r;
+ c.y = a.y;
+ }
+}
+
+function intersects(a, b) {
+ var dr = a.r + b.r - 1e-6, dx = b.x - a.x, dy = b.y - a.y;
+ return dr > 0 && dr * dr > dx * dx + dy * dy;
+}
+
+function score(node) {
+ var a = node._,
+ b = node.next._,
+ ab = a.r + b.r,
+ dx = (a.x * b.r + b.x * a.r) / ab,
+ dy = (a.y * b.r + b.y * a.r) / ab;
+ return dx * dx + dy * dy;
+}
+
+function Node(circle) {
+ this._ = circle;
+ this.next = null;
+ this.previous = null;
+}
+
+export function packEnclose(circles) {
+ if (!(n = (circles = array(circles)).length)) return 0;
+
+ var a, b, c, n, aa, ca, i, j, k, sj, sk;
+
+ // Place the first circle.
+ a = circles[0], a.x = 0, a.y = 0;
+ if (!(n > 1)) return a.r;
+
+ // Place the second circle.
+ b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0;
+ if (!(n > 2)) return a.r + b.r;
+
+ // Place the third circle.
+ place(b, a, c = circles[2]);
+
+ // Initialize the front-chain using the first three circles a, b and c.
+ a = new Node(a), b = new Node(b), c = new Node(c);
+ a.next = c.previous = b;
+ b.next = a.previous = c;
+ c.next = b.previous = a;
+
+ // Attempt to place each remaining circle…
+ pack: for (i = 3; i < n; ++i) {
+ place(a._, b._, c = circles[i]), c = new Node(c);
+
+ // Find the closest intersecting circle on the front-chain, if any.
+ // “Closeness†is determined by linear distance along the front-chain.
+ // “Ahead†or “behind†is likewise determined by linear distance.
+ j = b.next, k = a.previous, sj = b._.r, sk = a._.r;
+ do {
+ if (sj <= sk) {
+ if (intersects(j._, c._)) {
+ b = j, a.next = b, b.previous = a, --i;
+ continue pack;
+ }
+ sj += j._.r, j = j.next;
+ } else {
+ if (intersects(k._, c._)) {
+ a = k, a.next = b, b.previous = a, --i;
+ continue pack;
+ }
+ sk += k._.r, k = k.previous;
+ }
+ } while (j !== k.next);
+
+ // Success! Insert the new circle c between a and b.
+ c.previous = a, c.next = b, a.next = b.previous = b = c;
+
+ // Compute the new closest circle pair to the centroid.
+ aa = score(a);
+ while ((c = c.next) !== b) {
+ if ((ca = score(c)) < aa) {
+ a = c, aa = ca;
+ }
+ }
+ b = a.next;
+ }
+
+ // Compute the enclosing circle of the front chain.
+ a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a);
+
+ // Translate the circles to put the enclosing circle around the origin.
+ for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
+
+ return c.r;
+}
+
+export default function(circles) {
+ packEnclose(circles);
+ return circles;
+}
diff --git a/node_modules/d3-hierarchy/src/partition.js b/node_modules/d3-hierarchy/src/partition.js
new file mode 100644
index 00000000..0165ef73
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/partition.js
@@ -0,0 +1,52 @@
+import roundNode from "./treemap/round.js";
+import treemapDice from "./treemap/dice.js";
+
+export default function() {
+ var dx = 1,
+ dy = 1,
+ padding = 0,
+ round = false;
+
+ function partition(root) {
+ var n = root.height + 1;
+ root.x0 =
+ root.y0 = padding;
+ root.x1 = dx;
+ root.y1 = dy / n;
+ root.eachBefore(positionNode(dy, n));
+ if (round) root.eachBefore(roundNode);
+ return root;
+ }
+
+ function positionNode(dy, n) {
+ return function(node) {
+ if (node.children) {
+ treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n);
+ }
+ var x0 = node.x0,
+ y0 = node.y0,
+ x1 = node.x1 - padding,
+ y1 = node.y1 - padding;
+ if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
+ if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
+ node.x0 = x0;
+ node.y0 = y0;
+ node.x1 = x1;
+ node.y1 = y1;
+ };
+ }
+
+ partition.round = function(x) {
+ return arguments.length ? (round = !!x, partition) : round;
+ };
+
+ partition.size = function(x) {
+ return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy];
+ };
+
+ partition.padding = function(x) {
+ return arguments.length ? (padding = +x, partition) : padding;
+ };
+
+ return partition;
+}
diff --git a/node_modules/d3-hierarchy/src/stratify.js b/node_modules/d3-hierarchy/src/stratify.js
new file mode 100644
index 00000000..a6676c25
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/stratify.js
@@ -0,0 +1,75 @@
+import {required} from "./accessors.js";
+import {Node, computeHeight} from "./hierarchy/index.js";
+
+var preroot = {depth: -1},
+ ambiguous = {};
+
+function defaultId(d) {
+ return d.id;
+}
+
+function defaultParentId(d) {
+ return d.parentId;
+}
+
+export default function() {
+ var id = defaultId,
+ parentId = defaultParentId;
+
+ function stratify(data) {
+ var nodes = Array.from(data),
+ n = nodes.length,
+ d,
+ i,
+ root,
+ parent,
+ node,
+ nodeId,
+ nodeKey,
+ nodeByKey = new Map;
+
+ for (i = 0; i < n; ++i) {
+ d = nodes[i], node = nodes[i] = new Node(d);
+ if ((nodeId = id(d, i, data)) != null && (nodeId += "")) {
+ nodeKey = node.id = nodeId;
+ nodeByKey.set(nodeKey, nodeByKey.has(nodeKey) ? ambiguous : node);
+ }
+ if ((nodeId = parentId(d, i, data)) != null && (nodeId += "")) {
+ node.parent = nodeId;
+ }
+ }
+
+ for (i = 0; i < n; ++i) {
+ node = nodes[i];
+ if (nodeId = node.parent) {
+ parent = nodeByKey.get(nodeId);
+ if (!parent) throw new Error("missing: " + nodeId);
+ if (parent === ambiguous) throw new Error("ambiguous: " + nodeId);
+ if (parent.children) parent.children.push(node);
+ else parent.children = [node];
+ node.parent = parent;
+ } else {
+ if (root) throw new Error("multiple roots");
+ root = node;
+ }
+ }
+
+ if (!root) throw new Error("no root");
+ root.parent = preroot;
+ root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
+ root.parent = null;
+ if (n > 0) throw new Error("cycle");
+
+ return root;
+ }
+
+ stratify.id = function(x) {
+ return arguments.length ? (id = required(x), stratify) : id;
+ };
+
+ stratify.parentId = function(x) {
+ return arguments.length ? (parentId = required(x), stratify) : parentId;
+ };
+
+ return stratify;
+}
diff --git a/node_modules/d3-hierarchy/src/tree.js b/node_modules/d3-hierarchy/src/tree.js
new file mode 100644
index 00000000..dc4275e4
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/tree.js
@@ -0,0 +1,237 @@
+import {Node} from "./hierarchy/index.js";
+
+function defaultSeparation(a, b) {
+ return a.parent === b.parent ? 1 : 2;
+}
+
+// function radialSeparation(a, b) {
+// return (a.parent === b.parent ? 1 : 2) / a.depth;
+// }
+
+// This function is used to traverse the left contour of a subtree (or
+// subforest). It returns the successor of v on this contour. This successor is
+// either given by the leftmost child of v or by the thread of v. The function
+// returns null if and only if v is on the highest level of its subtree.
+function nextLeft(v) {
+ var children = v.children;
+ return children ? children[0] : v.t;
+}
+
+// This function works analogously to nextLeft.
+function nextRight(v) {
+ var children = v.children;
+ return children ? children[children.length - 1] : v.t;
+}
+
+// Shifts the current subtree rooted at w+. This is done by increasing
+// prelim(w+) and mod(w+) by shift.
+function moveSubtree(wm, wp, shift) {
+ var change = shift / (wp.i - wm.i);
+ wp.c -= change;
+ wp.s += shift;
+ wm.c += change;
+ wp.z += shift;
+ wp.m += shift;
+}
+
+// All other shifts, applied to the smaller subtrees between w- and w+, are
+// performed by this function. To prepare the shifts, we have to adjust
+// change(w+), shift(w+), and change(w-).
+function executeShifts(v) {
+ var shift = 0,
+ change = 0,
+ children = v.children,
+ i = children.length,
+ w;
+ while (--i >= 0) {
+ w = children[i];
+ w.z += shift;
+ w.m += shift;
+ shift += w.s + (change += w.c);
+ }
+}
+
+// If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise,
+// returns the specified (default) ancestor.
+function nextAncestor(vim, v, ancestor) {
+ return vim.a.parent === v.parent ? vim.a : ancestor;
+}
+
+function TreeNode(node, i) {
+ this._ = node;
+ this.parent = null;
+ this.children = null;
+ this.A = null; // default ancestor
+ this.a = this; // ancestor
+ this.z = 0; // prelim
+ this.m = 0; // mod
+ this.c = 0; // change
+ this.s = 0; // shift
+ this.t = null; // thread
+ this.i = i; // number
+}
+
+TreeNode.prototype = Object.create(Node.prototype);
+
+function treeRoot(root) {
+ var tree = new TreeNode(root, 0),
+ node,
+ nodes = [tree],
+ child,
+ children,
+ i,
+ n;
+
+ while (node = nodes.pop()) {
+ if (children = node._.children) {
+ node.children = new Array(n = children.length);
+ for (i = n - 1; i >= 0; --i) {
+ nodes.push(child = node.children[i] = new TreeNode(children[i], i));
+ child.parent = node;
+ }
+ }
+ }
+
+ (tree.parent = new TreeNode(null, 0)).children = [tree];
+ return tree;
+}
+
+// Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
+export default function() {
+ var separation = defaultSeparation,
+ dx = 1,
+ dy = 1,
+ nodeSize = null;
+
+ function tree(root) {
+ var t = treeRoot(root);
+
+ // Compute the layout using Buchheim et al.’s algorithm.
+ t.eachAfter(firstWalk), t.parent.m = -t.z;
+ t.eachBefore(secondWalk);
+
+ // If a fixed node size is specified, scale x and y.
+ if (nodeSize) root.eachBefore(sizeNode);
+
+ // If a fixed tree size is specified, scale x and y based on the extent.
+ // Compute the left-most, right-most, and depth-most nodes for extents.
+ else {
+ var left = root,
+ right = root,
+ bottom = root;
+ root.eachBefore(function(node) {
+ if (node.x < left.x) left = node;
+ if (node.x > right.x) right = node;
+ if (node.depth > bottom.depth) bottom = node;
+ });
+ var s = left === right ? 1 : separation(left, right) / 2,
+ tx = s - left.x,
+ kx = dx / (right.x + s + tx),
+ ky = dy / (bottom.depth || 1);
+ root.eachBefore(function(node) {
+ node.x = (node.x + tx) * kx;
+ node.y = node.depth * ky;
+ });
+ }
+
+ return root;
+ }
+
+ // Computes a preliminary x-coordinate for v. Before that, FIRST WALK is
+ // applied recursively to the children of v, as well as the function
+ // APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the
+ // node v is placed to the midpoint of its outermost children.
+ function firstWalk(v) {
+ var children = v.children,
+ siblings = v.parent.children,
+ w = v.i ? siblings[v.i - 1] : null;
+ if (children) {
+ executeShifts(v);
+ var midpoint = (children[0].z + children[children.length - 1].z) / 2;
+ if (w) {
+ v.z = w.z + separation(v._, w._);
+ v.m = v.z - midpoint;
+ } else {
+ v.z = midpoint;
+ }
+ } else if (w) {
+ v.z = w.z + separation(v._, w._);
+ }
+ v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
+ }
+
+ // Computes all real x-coordinates by summing up the modifiers recursively.
+ function secondWalk(v) {
+ v._.x = v.z + v.parent.m;
+ v.m += v.parent.m;
+ }
+
+ // The core of the algorithm. Here, a new subtree is combined with the
+ // previous subtrees. Threads are used to traverse the inside and outside
+ // contours of the left and right subtree up to the highest common level. The
+ // vertices used for the traversals are vi+, vi-, vo-, and vo+, where the
+ // superscript o means outside and i means inside, the subscript - means left
+ // subtree and + means right subtree. For summing up the modifiers along the
+ // contour, we use respective variables si+, si-, so-, and so+. Whenever two
+ // nodes of the inside contours conflict, we compute the left one of the
+ // greatest uncommon ancestors using the function ANCESTOR and call MOVE
+ // SUBTREE to shift the subtree and prepare the shifts of smaller subtrees.
+ // Finally, we add a new thread (if necessary).
+ function apportion(v, w, ancestor) {
+ if (w) {
+ var vip = v,
+ vop = v,
+ vim = w,
+ vom = vip.parent.children[0],
+ sip = vip.m,
+ sop = vop.m,
+ sim = vim.m,
+ som = vom.m,
+ shift;
+ while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) {
+ vom = nextLeft(vom);
+ vop = nextRight(vop);
+ vop.a = v;
+ shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
+ if (shift > 0) {
+ moveSubtree(nextAncestor(vim, v, ancestor), v, shift);
+ sip += shift;
+ sop += shift;
+ }
+ sim += vim.m;
+ sip += vip.m;
+ som += vom.m;
+ sop += vop.m;
+ }
+ if (vim && !nextRight(vop)) {
+ vop.t = vim;
+ vop.m += sim - sop;
+ }
+ if (vip && !nextLeft(vom)) {
+ vom.t = vip;
+ vom.m += sip - som;
+ ancestor = v;
+ }
+ }
+ return ancestor;
+ }
+
+ function sizeNode(node) {
+ node.x *= dx;
+ node.y = node.depth * dy;
+ }
+
+ tree.separation = function(x) {
+ return arguments.length ? (separation = x, tree) : separation;
+ };
+
+ tree.size = function(x) {
+ return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]);
+ };
+
+ tree.nodeSize = function(x) {
+ return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null);
+ };
+
+ return tree;
+}
diff --git a/node_modules/d3-hierarchy/src/treemap/binary.js b/node_modules/d3-hierarchy/src/treemap/binary.js
new file mode 100644
index 00000000..a9395dc2
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/treemap/binary.js
@@ -0,0 +1,46 @@
+export default function(parent, x0, y0, x1, y1) {
+ var nodes = parent.children,
+ i, n = nodes.length,
+ sum, sums = new Array(n + 1);
+
+ for (sums[0] = sum = i = 0; i < n; ++i) {
+ sums[i + 1] = sum += nodes[i].value;
+ }
+
+ partition(0, n, parent.value, x0, y0, x1, y1);
+
+ function partition(i, j, value, x0, y0, x1, y1) {
+ if (i >= j - 1) {
+ var node = nodes[i];
+ node.x0 = x0, node.y0 = y0;
+ node.x1 = x1, node.y1 = y1;
+ return;
+ }
+
+ var valueOffset = sums[i],
+ valueTarget = (value / 2) + valueOffset,
+ k = i + 1,
+ hi = j - 1;
+
+ while (k < hi) {
+ var mid = k + hi >>> 1;
+ if (sums[mid] < valueTarget) k = mid + 1;
+ else hi = mid;
+ }
+
+ if ((valueTarget - sums[k - 1]) < (sums[k] - valueTarget) && i + 1 < k) --k;
+
+ var valueLeft = sums[k] - valueOffset,
+ valueRight = value - valueLeft;
+
+ if ((x1 - x0) > (y1 - y0)) {
+ var xk = value ? (x0 * valueRight + x1 * valueLeft) / value : x1;
+ partition(i, k, valueLeft, x0, y0, xk, y1);
+ partition(k, j, valueRight, xk, y0, x1, y1);
+ } else {
+ var yk = value ? (y0 * valueRight + y1 * valueLeft) / value : y1;
+ partition(i, k, valueLeft, x0, y0, x1, yk);
+ partition(k, j, valueRight, x0, yk, x1, y1);
+ }
+ }
+}
diff --git a/node_modules/d3-hierarchy/src/treemap/dice.js b/node_modules/d3-hierarchy/src/treemap/dice.js
new file mode 100644
index 00000000..605c1f66
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/treemap/dice.js
@@ -0,0 +1,12 @@
+export default function(parent, x0, y0, x1, y1) {
+ var nodes = parent.children,
+ node,
+ i = -1,
+ n = nodes.length,
+ k = parent.value && (x1 - x0) / parent.value;
+
+ while (++i < n) {
+ node = nodes[i], node.y0 = y0, node.y1 = y1;
+ node.x0 = x0, node.x1 = x0 += node.value * k;
+ }
+}
diff --git a/node_modules/d3-hierarchy/src/treemap/index.js b/node_modules/d3-hierarchy/src/treemap/index.js
new file mode 100644
index 00000000..ccc42c9d
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/treemap/index.js
@@ -0,0 +1,94 @@
+import roundNode from "./round.js";
+import squarify from "./squarify.js";
+import {required} from "../accessors.js";
+import constant, {constantZero} from "../constant.js";
+
+export default function() {
+ var tile = squarify,
+ round = false,
+ dx = 1,
+ dy = 1,
+ paddingStack = [0],
+ paddingInner = constantZero,
+ paddingTop = constantZero,
+ paddingRight = constantZero,
+ paddingBottom = constantZero,
+ paddingLeft = constantZero;
+
+ function treemap(root) {
+ root.x0 =
+ root.y0 = 0;
+ root.x1 = dx;
+ root.y1 = dy;
+ root.eachBefore(positionNode);
+ paddingStack = [0];
+ if (round) root.eachBefore(roundNode);
+ return root;
+ }
+
+ function positionNode(node) {
+ var p = paddingStack[node.depth],
+ x0 = node.x0 + p,
+ y0 = node.y0 + p,
+ x1 = node.x1 - p,
+ y1 = node.y1 - p;
+ if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
+ if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
+ node.x0 = x0;
+ node.y0 = y0;
+ node.x1 = x1;
+ node.y1 = y1;
+ if (node.children) {
+ p = paddingStack[node.depth + 1] = paddingInner(node) / 2;
+ x0 += paddingLeft(node) - p;
+ y0 += paddingTop(node) - p;
+ x1 -= paddingRight(node) - p;
+ y1 -= paddingBottom(node) - p;
+ if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
+ if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
+ tile(node, x0, y0, x1, y1);
+ }
+ }
+
+ treemap.round = function(x) {
+ return arguments.length ? (round = !!x, treemap) : round;
+ };
+
+ treemap.size = function(x) {
+ return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy];
+ };
+
+ treemap.tile = function(x) {
+ return arguments.length ? (tile = required(x), treemap) : tile;
+ };
+
+ treemap.padding = function(x) {
+ return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner();
+ };
+
+ treemap.paddingInner = function(x) {
+ return arguments.length ? (paddingInner = typeof x === "function" ? x : constant(+x), treemap) : paddingInner;
+ };
+
+ treemap.paddingOuter = function(x) {
+ return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop();
+ };
+
+ treemap.paddingTop = function(x) {
+ return arguments.length ? (paddingTop = typeof x === "function" ? x : constant(+x), treemap) : paddingTop;
+ };
+
+ treemap.paddingRight = function(x) {
+ return arguments.length ? (paddingRight = typeof x === "function" ? x : constant(+x), treemap) : paddingRight;
+ };
+
+ treemap.paddingBottom = function(x) {
+ return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant(+x), treemap) : paddingBottom;
+ };
+
+ treemap.paddingLeft = function(x) {
+ return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant(+x), treemap) : paddingLeft;
+ };
+
+ return treemap;
+}
diff --git a/node_modules/d3-hierarchy/src/treemap/resquarify.js b/node_modules/d3-hierarchy/src/treemap/resquarify.js
new file mode 100644
index 00000000..de720473
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/treemap/resquarify.js
@@ -0,0 +1,36 @@
+import treemapDice from "./dice.js";
+import treemapSlice from "./slice.js";
+import {phi, squarifyRatio} from "./squarify.js";
+
+export default (function custom(ratio) {
+
+ function resquarify(parent, x0, y0, x1, y1) {
+ if ((rows = parent._squarify) && (rows.ratio === ratio)) {
+ var rows,
+ row,
+ nodes,
+ i,
+ j = -1,
+ n,
+ m = rows.length,
+ value = parent.value;
+
+ while (++j < m) {
+ row = rows[j], nodes = row.children;
+ for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value;
+ if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += (y1 - y0) * row.value / value : y1);
+ else treemapSlice(row, x0, y0, value ? x0 += (x1 - x0) * row.value / value : x1, y1);
+ value -= row.value;
+ }
+ } else {
+ parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1);
+ rows.ratio = ratio;
+ }
+ }
+
+ resquarify.ratio = function(x) {
+ return custom((x = +x) > 1 ? x : 1);
+ };
+
+ return resquarify;
+})(phi);
diff --git a/node_modules/d3-hierarchy/src/treemap/round.js b/node_modules/d3-hierarchy/src/treemap/round.js
new file mode 100644
index 00000000..7ac45ec2
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/treemap/round.js
@@ -0,0 +1,6 @@
+export default function(node) {
+ node.x0 = Math.round(node.x0);
+ node.y0 = Math.round(node.y0);
+ node.x1 = Math.round(node.x1);
+ node.y1 = Math.round(node.y1);
+}
diff --git a/node_modules/d3-hierarchy/src/treemap/slice.js b/node_modules/d3-hierarchy/src/treemap/slice.js
new file mode 100644
index 00000000..1022bfad
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/treemap/slice.js
@@ -0,0 +1,12 @@
+export default function(parent, x0, y0, x1, y1) {
+ var nodes = parent.children,
+ node,
+ i = -1,
+ n = nodes.length,
+ k = parent.value && (y1 - y0) / parent.value;
+
+ while (++i < n) {
+ node = nodes[i], node.x0 = x0, node.x1 = x1;
+ node.y0 = y0, node.y1 = y0 += node.value * k;
+ }
+}
diff --git a/node_modules/d3-hierarchy/src/treemap/sliceDice.js b/node_modules/d3-hierarchy/src/treemap/sliceDice.js
new file mode 100644
index 00000000..545ad42b
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/treemap/sliceDice.js
@@ -0,0 +1,6 @@
+import dice from "./dice.js";
+import slice from "./slice.js";
+
+export default function(parent, x0, y0, x1, y1) {
+ (parent.depth & 1 ? slice : dice)(parent, x0, y0, x1, y1);
+}
diff --git a/node_modules/d3-hierarchy/src/treemap/squarify.js b/node_modules/d3-hierarchy/src/treemap/squarify.js
new file mode 100644
index 00000000..f8010703
--- /dev/null
+++ b/node_modules/d3-hierarchy/src/treemap/squarify.js
@@ -0,0 +1,66 @@
+import treemapDice from "./dice.js";
+import treemapSlice from "./slice.js";
+
+export var phi = (1 + Math.sqrt(5)) / 2;
+
+export function squarifyRatio(ratio, parent, x0, y0, x1, y1) {
+ var rows = [],
+ nodes = parent.children,
+ row,
+ nodeValue,
+ i0 = 0,
+ i1 = 0,
+ n = nodes.length,
+ dx, dy,
+ value = parent.value,
+ sumValue,
+ minValue,
+ maxValue,
+ newRatio,
+ minRatio,
+ alpha,
+ beta;
+
+ while (i0 < n) {
+ dx = x1 - x0, dy = y1 - y0;
+
+ // Find the next non-empty node.
+ do sumValue = nodes[i1++].value; while (!sumValue && i1 < n);
+ minValue = maxValue = sumValue;
+ alpha = Math.max(dy / dx, dx / dy) / (value * ratio);
+ beta = sumValue * sumValue * alpha;
+ minRatio = Math.max(maxValue / beta, beta / minValue);
+
+ // Keep adding nodes while the aspect ratio maintains or improves.
+ for (; i1 < n; ++i1) {
+ sumValue += nodeValue = nodes[i1].value;
+ if (nodeValue < minValue) minValue = nodeValue;
+ if (nodeValue > maxValue) maxValue = nodeValue;
+ beta = sumValue * sumValue * alpha;
+ newRatio = Math.max(maxValue / beta, beta / minValue);
+ if (newRatio > minRatio) { sumValue -= nodeValue; break; }
+ minRatio = newRatio;
+ }
+
+ // Position and record the row orientation.
+ rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)});
+ if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1);
+ else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1);
+ value -= sumValue, i0 = i1;
+ }
+
+ return rows;
+}
+
+export default (function custom(ratio) {
+
+ function squarify(parent, x0, y0, x1, y1) {
+ squarifyRatio(ratio, parent, x0, y0, x1, y1);
+ }
+
+ squarify.ratio = function(x) {
+ return custom((x = +x) > 1 ? x : 1);
+ };
+
+ return squarify;
+})(phi);
diff --git a/node_modules/d3-interpolate/LICENSE b/node_modules/d3-interpolate/LICENSE
new file mode 100644
index 00000000..721bd22e
--- /dev/null
+++ b/node_modules/d3-interpolate/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2010-2016 Mike Bostock
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the author nor the names of contributors may be used to
+ endorse or promote products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node_modules/d3-interpolate/README.md b/node_modules/d3-interpolate/README.md
new file mode 100644
index 00000000..a7e72322
--- /dev/null
+++ b/node_modules/d3-interpolate/README.md
@@ -0,0 +1,258 @@
+# d3-interpolate
+
+This module provides a variety of interpolation methods for blending between two values. Values may be numbers, colors, strings, arrays, or even deeply-nested objects. For example:
+
+```js
+var i = d3.interpolateNumber(10, 20);
+i(0.0); // 10
+i(0.2); // 12
+i(0.5); // 15
+i(1.0); // 20
+```
+
+The returned function `i` is called an *interpolator*. Given a starting value *a* and an ending value *b*, it takes a parameter *t* in the domain [0, 1] and returns the corresponding interpolated value between *a* and *b*. An interpolator typically returns a value equivalent to *a* at *t* = 0 and a value equivalent to *b* at *t* = 1.
+
+You can interpolate more than just numbers. To find the perceptual midpoint between steelblue and brown:
+
+```js
+d3.interpolateLab("steelblue", "brown")(0.5); // "rgb(142, 92, 109)"
+```
+
+Here’s a more elaborate example demonstrating type inference used by [interpolate](#interpolate):
+
+```js
+var i = d3.interpolate({colors: ["red", "blue"]}, {colors: ["white", "black"]});
+i(0.0); // {colors: ["rgb(255, 0, 0)", "rgb(0, 0, 255)"]}
+i(0.5); // {colors: ["rgb(255, 128, 128)", "rgb(0, 0, 128)"]}
+i(1.0); // {colors: ["rgb(255, 255, 255)", "rgb(0, 0, 0)"]}
+```
+
+Note that the generic value interpolator detects not only nested objects and arrays, but also color strings and numbers embedded in strings!
+
+## Installing
+
+If you use NPM, `npm install d3-interpolate`. Otherwise, download the [latest release](https://github.com/d3/d3-interpolate/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-interpolate.v2.min.js) or as part of [D3](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported.
+
+In vanilla, a `d3` global is exported. (If using [color interpolation](#color-spaces), also load [d3-color](https://github.com/d3/d3-color).)
+
+```html
+
+
+
+```
+
+## API Reference
+
+# d3.interpolate(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/value.js), [Examples](https://observablehq.com/@d3/d3-interpolate)
+
+Returns an interpolator between the two arbitrary values *a* and *b*. The interpolator implementation is based on the type of the end value *b*, using the following algorithm:
+
+1. If *b* is null, undefined or a boolean, use the constant *b*.
+2. If *b* is a number, use [interpolateNumber](#interpolateNumber).
+3. If *b* is a [color](https://github.com/d3/d3-color/blob/master/README.md#color) or a string coercible to a color, use [interpolateRgb](#interpolateRgb).
+4. If *b* is a [date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date), use [interpolateDate](#interpolateDate).
+5. If *b* is a string, use [interpolateString](#interpolateString).
+6. If *b* is a [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) of numbers, use [interpolateNumberArray](#interpolateNumberArray).
+7. If *b* is a generic [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray), use [interpolateArray](#interpolateArray).
+8. If *b* is coercible to a number, use [interpolateNumber](#interpolateNumber).
+9. Use [interpolateObject](#interpolateObject).
+
+Based on the chosen interpolator, *a* is coerced to the suitable corresponding type.
+
+# d3.interpolateNumber(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/number.js), [Examples](https://observablehq.com/@d3/d3-interpolatenumber)
+
+Returns an interpolator between the two numbers *a* and *b*. The returned interpolator is equivalent to:
+
+```js
+function interpolator(t) {
+ return a * (1 - t) + b * t;
+}
+```
+
+Caution: avoid interpolating to or from the number zero when the interpolator is used to generate a string. When very small values are stringified, they may be converted to scientific notation, which is an invalid attribute or style property value in older browsers. For example, the number `0.0000001` is converted to the string `"1e-7"`. This is particularly noticeable with interpolating opacity. To avoid scientific notation, start or end the transition at 1e-6: the smallest value that is not stringified in scientific notation.
+
+# d3.interpolateRound(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/round.js), [Examples](https://observablehq.com/@d3/d3-interpolatenumber)
+
+Returns an interpolator between the two numbers *a* and *b*; the interpolator is similar to [interpolateNumber](#interpolateNumber), except it will round the resulting value to the nearest integer.
+
+# d3.interpolateString(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/string.js), [Examples](https://observablehq.com/@d3/d3-interpolatestring)
+
+Returns an interpolator between the two strings *a* and *b*. The string interpolator finds numbers embedded in *a* and *b*, where each number is of the form understood by JavaScript. A few examples of numbers that will be detected within a string: `-1`, `42`, `3.14159`, and `6.0221413e+23`.
+
+For each number embedded in *b*, the interpolator will attempt to find a corresponding number in *a*. If a corresponding number is found, a numeric interpolator is created using [interpolateNumber](#interpolateNumber). The remaining parts of the string *b* are used as a template: the static parts of the string *b* remain constant for the interpolation, with the interpolated numeric values embedded in the template.
+
+For example, if *a* is `"300 12px sans-serif"`, and *b* is `"500 36px Comic-Sans"`, two embedded numbers are found. The remaining static parts (of string *b*) are a space between the two numbers (`" "`), and the suffix (`"px Comic-Sans"`). The result of the interpolator at *t* = 0.5 is `"400 24px Comic-Sans"`.
+
+# d3.interpolateDate(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/date.js), [Examples](https://observablehq.com/@d3/d3-interpolatedate)
+
+Returns an interpolator between the two [dates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) *a* and *b*.
+
+Note: **no defensive copy** of the returned date is created; the same Date instance is returned for every evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of [animated transitions](https://github.com/d3/d3-transition).
+
+# d3.interpolateArray(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/array.js), [Examples](https://observablehq.com/@d3/d3-interpolateobject)
+
+Returns an interpolator between the two arrays *a* and *b*. If *b* is a typed array (e.g., Float64Array), [interpolateNumberArray](#interpolateNumberArray) is called instead.
+
+Internally, an array template is created that is the same length as *b*. For each element in *b*, if there exists a corresponding element in *a*, a generic interpolator is created for the two elements using [interpolate](#interpolate). If there is no such element, the static value from *b* is used in the template. Then, for the given parameter *t*, the template’s embedded interpolators are evaluated. The updated array template is then returned.
+
+For example, if *a* is the array `[0, 1]` and *b* is the array `[1, 10, 100]`, then the result of the interpolator for *t* = 0.5 is the array `[0.5, 5.5, 100]`.
+
+Note: **no defensive copy** of the template array is created; modifications of the returned array may adversely affect subsequent evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of [animated transitions](https://github.com/d3/d3-transition).
+
+# d3.interpolateNumberArray(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/numberArray.js), [Examples](https://observablehq.com/@d3/d3-interpolatenumberarray)
+
+Returns an interpolator between the two arrays of numbers *a* and *b*. Internally, an array template is created that is the same type and length as *b*. For each element in *b*, if there exists a corresponding element in *a*, the values are directly interpolated in the array template. If there is no such element, the static value from *b* is copied. The updated array template is then returned.
+
+Note: For performance reasons, **no defensive copy** is made of the template array and the arguments *a* and *b*; modifications of these arrays may affect subsequent evaluation of the interpolator.
+
+# d3.interpolateObject(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/object.js), [Examples](https://observablehq.com/@d3/d3-interpolateobject)
+
+Returns an interpolator between the two objects *a* and *b*. Internally, an object template is created that has the same properties as *b*. For each property in *b*, if there exists a corresponding property in *a*, a generic interpolator is created for the two elements using [interpolate](#interpolate). If there is no such property, the static value from *b* is used in the template. Then, for the given parameter *t*, the template's embedded interpolators are evaluated and the updated object template is then returned.
+
+For example, if *a* is the object `{x: 0, y: 1}` and *b* is the object `{x: 1, y: 10, z: 100}`, the result of the interpolator for *t* = 0.5 is the object `{x: 0.5, y: 5.5, z: 100}`.
+
+Object interpolation is particularly useful for *dataspace interpolation*, where data is interpolated rather than attribute values. For example, you can interpolate an object which describes an arc in a pie chart, and then use [d3.arc](https://github.com/d3/d3-shape/blob/master/README.md#arc) to compute the new SVG path data.
+
+Note: **no defensive copy** of the template object is created; modifications of the returned object may adversely affect subsequent evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of [animated transitions](https://github.com/d3/d3-transition).
+
+# d3.interpolateTransformCss(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/transform/index.js#L62), [Examples](https://observablehq.com/@d3/d3-interpolatetransformcss)
+
+Returns an interpolator between the two 2D CSS transforms represented by *a* and *b*. Each transform is decomposed to a standard representation of translate, rotate, *x*-skew and scale; these component transformations are then interpolated. This behavior is standardized by CSS: see [matrix decomposition for animation](http://www.w3.org/TR/css3-2d-transforms/#matrix-decomposition).
+
+# d3.interpolateTransformSvg(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/transform/index.js#L63), [Examples](https://observablehq.com/@d3/d3-interpolatetransformcss)
+
+Returns an interpolator between the two 2D SVG transforms represented by *a* and *b*. Each transform is decomposed to a standard representation of translate, rotate, *x*-skew and scale; these component transformations are then interpolated. This behavior is standardized by CSS: see [matrix decomposition for animation](http://www.w3.org/TR/css3-2d-transforms/#matrix-decomposition).
+
+# d3.interpolateZoom(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/zoom.js), [Examples](https://observablehq.com/@d3/d3-interpolatezoom)
+
+Returns an interpolator between the two views *a* and *b* of a two-dimensional plane, based on [“Smooth and efficient zooming and panningâ€](http://www.win.tue.nl/~vanwijk/zoompan.pdf) by Jarke J. van Wijk and Wim A.A. Nuij. Each view is defined as an array of three numbers: *cx*, *cy* and *width*. The first two coordinates *cx*, *cy* represent the center of the viewport; the last coordinate *width* represents the size of the viewport.
+
+The returned interpolator exposes a *duration* property which encodes the recommended transition duration in milliseconds. This duration is based on the path length of the curved trajectory through *x,y* space. If you want a slower or faster transition, multiply this by an arbitrary scale factor (V as described in the original paper).
+
+# *interpolateZoom*.rho(rho) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/zoom.js)
+
+Given a [zoom interpolator](#interpolateZoom), returns a new zoom interpolator using the specified curvature *rho*. When *rho* is close to 0, the interpolator is almost linear. The default curvature is sqrt(2).
+
+# d3.interpolateDiscrete(values) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/discrete.js), [Examples](https://observablehq.com/@d3/d3-interpolatediscrete)
+
+Returns a discrete interpolator for the given array of *values*. The returned interpolator maps *t* in [0, 1 / *n*) to *values*[0], *t* in [1 / *n*, 2 / *n*) to *values*[1], and so on, where *n* = *values*.length. In effect, this is a lightweight [quantize scale](https://github.com/d3/d3-scale/blob/master/README.md#quantize-scales) with a fixed domain of [0, 1].
+
+### Sampling
+
+# d3.quantize(interpolator, n) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/d3-quantize)
+
+Returns *n* uniformly-spaced samples from the specified *interpolator*, where *n* is an integer greater than one. The first sample is always at *t* = 0, and the last sample is always at *t* = 1. This can be useful in generating a fixed number of samples from a given interpolator, such as to derive the range of a [quantize scale](https://github.com/d3/d3-scale/blob/master/README.md#quantize-scales) from a [continuous interpolator](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#interpolateWarm).
+
+Caution: this method will not work with interpolators that do not return defensive copies of their output, such as [d3.interpolateArray](#interpolateArray), [d3.interpolateDate](#interpolateDate) and [d3.interpolateObject](#interpolateObject). For those interpolators, you must wrap the interpolator and create a copy for each returned value.
+
+### Color Spaces
+
+# d3.interpolateRgb(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/rgb.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Renders the edges of the Delaunay triangulation to the specified *context*. The specified *context* must implement the *context*.moveTo and *context*.lineTo methods from the [CanvasPathMethods API](https://www.w3.org/TR/2dcontext/#canvaspathmethods). If a *context* is not specified, an SVG path string is returned instead.
+
+# delaunay.renderHull([context]) [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+
+
+Renders the convex hull of the Delaunay triangulation to the specified *context*. The specified *context* must implement the *context*.moveTo and *context*.lineTo methods from the [CanvasPathMethods API](https://www.w3.org/TR/2dcontext/#canvaspathmethods). If a *context* is not specified, an SVG path string is returned instead.
+
+# delaunay.renderTriangle(i[, context]) [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+
+
+Renders triangle *i* of the Delaunay triangulation to the specified *context*. The specified *context* must implement the *context*.moveTo, *context*.lineTo and *context*.closePath methods from the [CanvasPathMethods API](https://www.w3.org/TR/2dcontext/#canvaspathmethods). If a *context* is not specified, an SVG path string is returned instead.
+
+# delaunay.renderPoints(\[context\]\[, radius\]) [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+Renders the input points of the Delaunay triangulation to the specified *context* as circles with the specified *radius*. If *radius* is not specified, it defaults to 2. The specified *context* must implement the *context*.moveTo and *context*.arc methods from the [CanvasPathMethods API](https://www.w3.org/TR/2dcontext/#canvaspathmethods). If a *context* is not specified, an SVG path string is returned instead.
+
+# delaunay.hullPolygon() [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+Returns the closed polygon [[*x0*, *y0*], [*x1*, *y1*], …, [*x0*, *y0*]] representing the convex hull.
+
+# delaunay.trianglePolygons() [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+Returns an iterable over the [polygons for each triangle](#delaunay_trianglePolygon), in order.
+
+# delaunay.trianglePolygon(i) [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+Returns the closed polygon [[*x0*, *y0*], [*x1*, *y1*], [*x2*, *y2*], [*x0*, *y0*]] representing the triangle *i*.
+
+# delaunay.update() [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+Updates the triangulation after the points have been modified in-place.
+
+# delaunay.voronoi([bounds]) [<>](https://github.com/d3/d3-delaunay/blob/master/src/delaunay.js "Source")
+
+Returns the [Voronoi diagram](#voronoi) for the associated [points](#delaunay_points). When rendering, the diagram will be clipped to the specified *bounds* = [*xmin*, *ymin*, *xmax*, *ymax*]. If *bounds* is not specified, it defaults to [0, 0, 960, 500]. See [To Infinity and Back Again](https://observablehq.com/@mbostock/to-infinity-and-back-again) for an interactive explanation of Voronoi cell clipping.
+
+The Voronoi diagram is returned even in degenerate cases where no triangulation exists — namely 0, 1 or 2 points, and collinear points.
+
+### Voronoi
+
+# voronoi.delaunay
+
+The Voronoi diagram’s associated [Delaunay triangulation](#delaunay).
+
+# voronoi.circumcenters
+
+The [circumcenters](http://mathworld.wolfram.com/Circumcenter.html) of the Delaunay triangles as a Float64Array [*cx0*, *cy0*, *cx1*, *cy1*, …]. Each contiguous pair of coordinates *cx*, *cy* is the circumcenter for the corresponding triangle. These circumcenters form the coordinates of the Voronoi cell polygons.
+
+# voronoi.vectors
+
+A Float64Array [*vx0*, *vy0*, *wx0*, *wy0*, …] where each non-zero quadruple describes an open (infinite) cell on the outer hull, giving the directions of two open half-lines.
+
+# voronoi.xmin
+# voronoi.ymin
+# voronoi.xmax
+# voronoi.ymax
+
+The bounds of the viewport [*xmin*, *ymin*, *xmax*, *ymax*] for rendering the Voronoi diagram. These values only affect the rendering methods ([*voronoi*.render](#voronoi_render), [*voronoi*.renderBounds](#voronoi_renderBounds), [*cell*.render](#cell_render)).
+
+# voronoi.contains(i, x, y) [<>](https://github.com/d3/d3-delaunay/blob/master/src/cell.js "Source")
+
+Returns true if the cell with the specified index *i* contains the specified point ⟨*x*, *y*⟩. (This method is not affected by the associated Voronoi diagram’s viewport [bounds](#voronoi_xmin).)
+
+# voronoi.neighbors(i) [<>](https://github.com/d3/d3-delaunay/blob/master/src/voronoi.js "Source")
+
+Returns an iterable over the indexes of the cells that share a common edge with the specified cell *i*. Voronoi neighbors are always neighbors on the Delaunay graph, but the converse is false when the common edge has been clipped out by the Voronoi diagram’s viewport.
+
+# voronoi.render([context]) [<>](https://github.com/d3/d3-delaunay/blob/master/src/voronoi.js "Source")
+
+
+
+Renders the mesh of Voronoi cells to the specified *context*. The specified *context* must implement the *context*.moveTo and *context*.lineTo methods from the [CanvasPathMethods API](https://www.w3.org/TR/2dcontext/#canvaspathmethods). If a *context* is not specified, an SVG path string is returned instead.
+
+# voronoi.renderBounds([context]) [<>](https://github.com/d3/d3-delaunay/blob/master/src/voronoi.js "Source")
+
+
+
+Renders the viewport extent to the specified *context*. The specified *context* must implement the *context*.rect method from the [CanvasPathMethods API](https://www.w3.org/TR/2dcontext/#canvaspathmethods). Equivalent to *context*.rect(*voronoi*.xmin, *voronoi*.ymin, *voronoi*.xmax - *voronoi*.xmin, *voronoi*.ymax - *voronoi*.ymin). If a *context* is not specified, an SVG path string is returned instead.
+
+# voronoi.renderCell(i[, context]) [<>](https://github.com/d3/d3-delaunay/blob/master/src/voronoi.js "Source")
+
+
+
+Renders the cell with the specified index *i* to the specified *context*. The specified *context* must implement the *context*.moveTo , *context*.lineTo and *context*.closePath methods from the [CanvasPathMethods API](https://www.w3.org/TR/2dcontext/#canvaspathmethods). If a *context* is not specified, an SVG path string is returned instead.
+
+# voronoi.cellPolygons() [<>](https://github.com/d3/d3-delaunay/blob/master/src/voronoi.js "Source")
+
+Returns an iterable over the non-empty [polygons for each cell](#voronoi_cellPolygon), with the cell index as property.
+
+# voronoi.cellPolygon(i) [<>](https://github.com/d3/d3-delaunay/blob/master/src/voronoi.js "Source")
+
+Returns the convex, closed polygon [[*x0*, *y0*], [*x1*, *y1*], …, [*x0*, *y0*]] representing the cell for the specified point *i*.
+
+# voronoi.update() [<>](https://github.com/d3/d3-delaunay/blob/master/src/voronoi.js "Source")
+
+Updates the Voronoi diagram and underlying triangulation after the points have been modified in-place — useful for Lloyd’s relaxation.
+
diff --git a/node_modules/d3-delaunay/dist/d3-delaunay.js b/node_modules/d3-delaunay/dist/d3-delaunay.js
new file mode 100644
index 00000000..6ab61648
--- /dev/null
+++ b/node_modules/d3-delaunay/dist/d3-delaunay.js
@@ -0,0 +1,1123 @@
+// https://github.com/d3/d3-delaunay v5.3.0 Copyright 2020 Mike Bostock
+// https://github.com/mapbox/delaunator v4.0.1. Copyright 2019 Mapbox, Inc.
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+typeof define === 'function' && define.amd ? define(['exports'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}));
+}(this, function (exports) { 'use strict';
+
+const EPSILON = Math.pow(2, -52);
+const EDGE_STACK = new Uint32Array(512);
+
+class Delaunator {
+
+ static from(points, getX = defaultGetX, getY = defaultGetY) {
+ const n = points.length;
+ const coords = new Float64Array(n * 2);
+
+ for (let i = 0; i < n; i++) {
+ const p = points[i];
+ coords[2 * i] = getX(p);
+ coords[2 * i + 1] = getY(p);
+ }
+
+ return new Delaunator(coords);
+ }
+
+ constructor(coords) {
+ const n = coords.length >> 1;
+ if (n > 0 && typeof coords[0] !== 'number') throw new Error('Expected coords to contain numbers.');
+
+ this.coords = coords;
+
+ // arrays that will store the triangulation graph
+ const maxTriangles = Math.max(2 * n - 5, 0);
+ this._triangles = new Uint32Array(maxTriangles * 3);
+ this._halfedges = new Int32Array(maxTriangles * 3);
+
+ // temporary arrays for tracking the edges of the advancing convex hull
+ this._hashSize = Math.ceil(Math.sqrt(n));
+ this._hullPrev = new Uint32Array(n); // edge to prev edge
+ this._hullNext = new Uint32Array(n); // edge to next edge
+ this._hullTri = new Uint32Array(n); // edge to adjacent triangle
+ this._hullHash = new Int32Array(this._hashSize).fill(-1); // angular edge hash
+
+ // temporary arrays for sorting points
+ this._ids = new Uint32Array(n);
+ this._dists = new Float64Array(n);
+
+ this.update();
+ }
+
+ update() {
+ const {coords, _hullPrev: hullPrev, _hullNext: hullNext, _hullTri: hullTri, _hullHash: hullHash} = this;
+ const n = coords.length >> 1;
+
+ // populate an array of point indices; calculate input data bbox
+ let minX = Infinity;
+ let minY = Infinity;
+ let maxX = -Infinity;
+ let maxY = -Infinity;
+
+ for (let i = 0; i < n; i++) {
+ const x = coords[2 * i];
+ const y = coords[2 * i + 1];
+ if (x < minX) minX = x;
+ if (y < minY) minY = y;
+ if (x > maxX) maxX = x;
+ if (y > maxY) maxY = y;
+ this._ids[i] = i;
+ }
+ const cx = (minX + maxX) / 2;
+ const cy = (minY + maxY) / 2;
+
+ let minDist = Infinity;
+ let i0, i1, i2;
+
+ // pick a seed point close to the center
+ for (let i = 0; i < n; i++) {
+ const d = dist(cx, cy, coords[2 * i], coords[2 * i + 1]);
+ if (d < minDist) {
+ i0 = i;
+ minDist = d;
+ }
+ }
+ const i0x = coords[2 * i0];
+ const i0y = coords[2 * i0 + 1];
+
+ minDist = Infinity;
+
+ // find the point closest to the seed
+ for (let i = 0; i < n; i++) {
+ if (i === i0) continue;
+ const d = dist(i0x, i0y, coords[2 * i], coords[2 * i + 1]);
+ if (d < minDist && d > 0) {
+ i1 = i;
+ minDist = d;
+ }
+ }
+ let i1x = coords[2 * i1];
+ let i1y = coords[2 * i1 + 1];
+
+ let minRadius = Infinity;
+
+ // find the third point which forms the smallest circumcircle with the first two
+ for (let i = 0; i < n; i++) {
+ if (i === i0 || i === i1) continue;
+ const r = circumradius(i0x, i0y, i1x, i1y, coords[2 * i], coords[2 * i + 1]);
+ if (r < minRadius) {
+ i2 = i;
+ minRadius = r;
+ }
+ }
+ let i2x = coords[2 * i2];
+ let i2y = coords[2 * i2 + 1];
+
+ if (minRadius === Infinity) {
+ // order collinear points by dx (or dy if all x are identical)
+ // and return the list as a hull
+ for (let i = 0; i < n; i++) {
+ this._dists[i] = (coords[2 * i] - coords[0]) || (coords[2 * i + 1] - coords[1]);
+ }
+ quicksort(this._ids, this._dists, 0, n - 1);
+ const hull = new Uint32Array(n);
+ let j = 0;
+ for (let i = 0, d0 = -Infinity; i < n; i++) {
+ const id = this._ids[i];
+ if (this._dists[id] > d0) {
+ hull[j++] = id;
+ d0 = this._dists[id];
+ }
+ }
+ this.hull = hull.subarray(0, j);
+ this.triangles = new Uint32Array(0);
+ this.halfedges = new Uint32Array(0);
+ return;
+ }
+
+ // swap the order of the seed points for counter-clockwise orientation
+ if (orient(i0x, i0y, i1x, i1y, i2x, i2y)) {
+ const i = i1;
+ const x = i1x;
+ const y = i1y;
+ i1 = i2;
+ i1x = i2x;
+ i1y = i2y;
+ i2 = i;
+ i2x = x;
+ i2y = y;
+ }
+
+ const center = circumcenter(i0x, i0y, i1x, i1y, i2x, i2y);
+ this._cx = center.x;
+ this._cy = center.y;
+
+ for (let i = 0; i < n; i++) {
+ this._dists[i] = dist(coords[2 * i], coords[2 * i + 1], center.x, center.y);
+ }
+
+ // sort the points by distance from the seed triangle circumcenter
+ quicksort(this._ids, this._dists, 0, n - 1);
+
+ // set up the seed triangle as the starting hull
+ this._hullStart = i0;
+ let hullSize = 3;
+
+ hullNext[i0] = hullPrev[i2] = i1;
+ hullNext[i1] = hullPrev[i0] = i2;
+ hullNext[i2] = hullPrev[i1] = i0;
+
+ hullTri[i0] = 0;
+ hullTri[i1] = 1;
+ hullTri[i2] = 2;
+
+ hullHash.fill(-1);
+ hullHash[this._hashKey(i0x, i0y)] = i0;
+ hullHash[this._hashKey(i1x, i1y)] = i1;
+ hullHash[this._hashKey(i2x, i2y)] = i2;
+
+ this.trianglesLen = 0;
+ this._addTriangle(i0, i1, i2, -1, -1, -1);
+
+ for (let k = 0, xp, yp; k < this._ids.length; k++) {
+ const i = this._ids[k];
+ const x = coords[2 * i];
+ const y = coords[2 * i + 1];
+
+ // skip near-duplicate points
+ if (k > 0 && Math.abs(x - xp) <= EPSILON && Math.abs(y - yp) <= EPSILON) continue;
+ xp = x;
+ yp = y;
+
+ // skip seed triangle points
+ if (i === i0 || i === i1 || i === i2) continue;
+
+ // find a visible edge on the convex hull using edge hash
+ let start = 0;
+ for (let j = 0, key = this._hashKey(x, y); j < this._hashSize; j++) {
+ start = hullHash[(key + j) % this._hashSize];
+ if (start !== -1 && start !== hullNext[start]) break;
+ }
+
+ start = hullPrev[start];
+ let e = start, q;
+ while (q = hullNext[e], !orient(x, y, coords[2 * e], coords[2 * e + 1], coords[2 * q], coords[2 * q + 1])) {
+ e = q;
+ if (e === start) {
+ e = -1;
+ break;
+ }
+ }
+ if (e === -1) continue; // likely a near-duplicate point; skip it
+
+ // add the first triangle from the point
+ let t = this._addTriangle(e, i, hullNext[e], -1, -1, hullTri[e]);
+
+ // recursively flip triangles from the point until they satisfy the Delaunay condition
+ hullTri[i] = this._legalize(t + 2);
+ hullTri[e] = t; // keep track of boundary triangles on the hull
+ hullSize++;
+
+ // walk forward through the hull, adding more triangles and flipping recursively
+ let n = hullNext[e];
+ while (q = hullNext[n], orient(x, y, coords[2 * n], coords[2 * n + 1], coords[2 * q], coords[2 * q + 1])) {
+ t = this._addTriangle(n, i, q, hullTri[i], -1, hullTri[n]);
+ hullTri[i] = this._legalize(t + 2);
+ hullNext[n] = n; // mark as removed
+ hullSize--;
+ n = q;
+ }
+
+ // walk backward from the other side, adding more triangles and flipping
+ if (e === start) {
+ while (q = hullPrev[e], orient(x, y, coords[2 * q], coords[2 * q + 1], coords[2 * e], coords[2 * e + 1])) {
+ t = this._addTriangle(q, i, e, -1, hullTri[e], hullTri[q]);
+ this._legalize(t + 2);
+ hullTri[q] = t;
+ hullNext[e] = e; // mark as removed
+ hullSize--;
+ e = q;
+ }
+ }
+
+ // update the hull indices
+ this._hullStart = hullPrev[i] = e;
+ hullNext[e] = hullPrev[n] = i;
+ hullNext[i] = n;
+
+ // save the two new edges in the hash table
+ hullHash[this._hashKey(x, y)] = i;
+ hullHash[this._hashKey(coords[2 * e], coords[2 * e + 1])] = e;
+ }
+
+ this.hull = new Uint32Array(hullSize);
+ for (let i = 0, e = this._hullStart; i < hullSize; i++) {
+ this.hull[i] = e;
+ e = hullNext[e];
+ }
+
+ // trim typed triangle mesh arrays
+ this.triangles = this._triangles.subarray(0, this.trianglesLen);
+ this.halfedges = this._halfedges.subarray(0, this.trianglesLen);
+ }
+
+ _hashKey(x, y) {
+ return Math.floor(pseudoAngle(x - this._cx, y - this._cy) * this._hashSize) % this._hashSize;
+ }
+
+ _legalize(a) {
+ const {_triangles: triangles, _halfedges: halfedges, coords} = this;
+
+ let i = 0;
+ let ar = 0;
+
+ // recursion eliminated with a fixed-size stack
+ while (true) {
+ const b = halfedges[a];
+
+ /* if the pair of triangles doesn't satisfy the Delaunay condition
+ * (p1 is inside the circumcircle of [p0, pl, pr]), flip them,
+ * then do the same check/flip recursively for the new pair of triangles
+ *
+ * pl pl
+ * /||\ / \
+ * al/ || \bl al/ \a
+ * / || \ / \
+ * / a||b \ flip /___ar___\
+ * p0\ || /p1 => p0\---bl---/p1
+ * \ || / \ /
+ * ar\ || /br b\ /br
+ * \||/ \ /
+ * pr pr
+ */
+ const a0 = a - a % 3;
+ ar = a0 + (a + 2) % 3;
+
+ if (b === -1) { // convex hull edge
+ if (i === 0) break;
+ a = EDGE_STACK[--i];
+ continue;
+ }
+
+ const b0 = b - b % 3;
+ const al = a0 + (a + 1) % 3;
+ const bl = b0 + (b + 2) % 3;
+
+ const p0 = triangles[ar];
+ const pr = triangles[a];
+ const pl = triangles[al];
+ const p1 = triangles[bl];
+
+ const illegal = inCircle(
+ coords[2 * p0], coords[2 * p0 + 1],
+ coords[2 * pr], coords[2 * pr + 1],
+ coords[2 * pl], coords[2 * pl + 1],
+ coords[2 * p1], coords[2 * p1 + 1]);
+
+ if (illegal) {
+ triangles[a] = p1;
+ triangles[b] = p0;
+
+ const hbl = halfedges[bl];
+
+ // edge swapped on the other side of the hull (rare); fix the halfedge reference
+ if (hbl === -1) {
+ let e = this._hullStart;
+ do {
+ if (this._hullTri[e] === bl) {
+ this._hullTri[e] = a;
+ break;
+ }
+ e = this._hullPrev[e];
+ } while (e !== this._hullStart);
+ }
+ this._link(a, hbl);
+ this._link(b, halfedges[ar]);
+ this._link(ar, bl);
+
+ const br = b0 + (b + 1) % 3;
+
+ // don't worry about hitting the cap: it can only happen on extremely degenerate input
+ if (i < EDGE_STACK.length) {
+ EDGE_STACK[i++] = br;
+ }
+ } else {
+ if (i === 0) break;
+ a = EDGE_STACK[--i];
+ }
+ }
+
+ return ar;
+ }
+
+ _link(a, b) {
+ this._halfedges[a] = b;
+ if (b !== -1) this._halfedges[b] = a;
+ }
+
+ // add a new triangle given vertex indices and adjacent half-edge ids
+ _addTriangle(i0, i1, i2, a, b, c) {
+ const t = this.trianglesLen;
+
+ this._triangles[t] = i0;
+ this._triangles[t + 1] = i1;
+ this._triangles[t + 2] = i2;
+
+ this._link(t, a);
+ this._link(t + 1, b);
+ this._link(t + 2, c);
+
+ this.trianglesLen += 3;
+
+ return t;
+ }
+}
+
+// monotonically increases with real angle, but doesn't need expensive trigonometry
+function pseudoAngle(dx, dy) {
+ const p = dx / (Math.abs(dx) + Math.abs(dy));
+ return (dy > 0 ? 3 - p : 1 + p) / 4; // [0..1]
+}
+
+function dist(ax, ay, bx, by) {
+ const dx = ax - bx;
+ const dy = ay - by;
+ return dx * dx + dy * dy;
+}
+
+// return 2d orientation sign if we're confident in it through J. Shewchuk's error bound check
+function orientIfSure(px, py, rx, ry, qx, qy) {
+ const l = (ry - py) * (qx - px);
+ const r = (rx - px) * (qy - py);
+ return Math.abs(l - r) >= 3.3306690738754716e-16 * Math.abs(l + r) ? l - r : 0;
+}
+
+// a more robust orientation test that's stable in a given triangle (to fix robustness issues)
+function orient(rx, ry, qx, qy, px, py) {
+ const sign = orientIfSure(px, py, rx, ry, qx, qy) ||
+ orientIfSure(rx, ry, qx, qy, px, py) ||
+ orientIfSure(qx, qy, px, py, rx, ry);
+ return sign < 0;
+}
+
+function inCircle(ax, ay, bx, by, cx, cy, px, py) {
+ const dx = ax - px;
+ const dy = ay - py;
+ const ex = bx - px;
+ const ey = by - py;
+ const fx = cx - px;
+ const fy = cy - py;
+
+ const ap = dx * dx + dy * dy;
+ const bp = ex * ex + ey * ey;
+ const cp = fx * fx + fy * fy;
+
+ return dx * (ey * cp - bp * fy) -
+ dy * (ex * cp - bp * fx) +
+ ap * (ex * fy - ey * fx) < 0;
+}
+
+function circumradius(ax, ay, bx, by, cx, cy) {
+ const dx = bx - ax;
+ const dy = by - ay;
+ const ex = cx - ax;
+ const ey = cy - ay;
+
+ const bl = dx * dx + dy * dy;
+ const cl = ex * ex + ey * ey;
+ const d = 0.5 / (dx * ey - dy * ex);
+
+ const x = (ey * bl - dy * cl) * d;
+ const y = (dx * cl - ex * bl) * d;
+
+ return x * x + y * y;
+}
+
+function circumcenter(ax, ay, bx, by, cx, cy) {
+ const dx = bx - ax;
+ const dy = by - ay;
+ const ex = cx - ax;
+ const ey = cy - ay;
+
+ const bl = dx * dx + dy * dy;
+ const cl = ex * ex + ey * ey;
+ const d = 0.5 / (dx * ey - dy * ex);
+
+ const x = ax + (ey * bl - dy * cl) * d;
+ const y = ay + (dx * cl - ex * bl) * d;
+
+ return {x, y};
+}
+
+function quicksort(ids, dists, left, right) {
+ if (right - left <= 20) {
+ for (let i = left + 1; i <= right; i++) {
+ const temp = ids[i];
+ const tempDist = dists[temp];
+ let j = i - 1;
+ while (j >= left && dists[ids[j]] > tempDist) ids[j + 1] = ids[j--];
+ ids[j + 1] = temp;
+ }
+ } else {
+ const median = (left + right) >> 1;
+ let i = left + 1;
+ let j = right;
+ swap(ids, median, i);
+ if (dists[ids[left]] > dists[ids[right]]) swap(ids, left, right);
+ if (dists[ids[i]] > dists[ids[right]]) swap(ids, i, right);
+ if (dists[ids[left]] > dists[ids[i]]) swap(ids, left, i);
+
+ const temp = ids[i];
+ const tempDist = dists[temp];
+ while (true) {
+ do i++; while (dists[ids[i]] < tempDist);
+ do j--; while (dists[ids[j]] > tempDist);
+ if (j < i) break;
+ swap(ids, i, j);
+ }
+ ids[left + 1] = ids[j];
+ ids[j] = temp;
+
+ if (right - i + 1 >= j - left) {
+ quicksort(ids, dists, i, right);
+ quicksort(ids, dists, left, j - 1);
+ } else {
+ quicksort(ids, dists, left, j - 1);
+ quicksort(ids, dists, i, right);
+ }
+ }
+}
+
+function swap(arr, i, j) {
+ const tmp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = tmp;
+}
+
+function defaultGetX(p) {
+ return p[0];
+}
+function defaultGetY(p) {
+ return p[1];
+}
+
+const epsilon = 1e-6;
+
+class Path {
+ constructor() {
+ this._x0 = this._y0 = // start of current subpath
+ this._x1 = this._y1 = null; // end of current subpath
+ this._ = "";
+ }
+ moveTo(x, y) {
+ this._ += `M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}`;
+ }
+ closePath() {
+ if (this._x1 !== null) {
+ this._x1 = this._x0, this._y1 = this._y0;
+ this._ += "Z";
+ }
+ }
+ lineTo(x, y) {
+ this._ += `L${this._x1 = +x},${this._y1 = +y}`;
+ }
+ arc(x, y, r) {
+ x = +x, y = +y, r = +r;
+ const x0 = x + r;
+ const y0 = y;
+ if (r < 0) throw new Error("negative radius");
+ if (this._x1 === null) this._ += `M${x0},${y0}`;
+ else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) this._ += "L" + x0 + "," + y0;
+ if (!r) return;
+ this._ += `A${r},${r},0,1,1,${x - r},${y}A${r},${r},0,1,1,${this._x1 = x0},${this._y1 = y0}`;
+ }
+ rect(x, y, w, h) {
+ this._ += `M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}h${+w}v${+h}h${-w}Z`;
+ }
+ value() {
+ return this._ || null;
+ }
+}
+
+class Polygon {
+ constructor() {
+ this._ = [];
+ }
+ moveTo(x, y) {
+ this._.push([x, y]);
+ }
+ closePath() {
+ this._.push(this._[0].slice());
+ }
+ lineTo(x, y) {
+ this._.push([x, y]);
+ }
+ value() {
+ return this._.length ? this._ : null;
+ }
+}
+
+class Voronoi {
+ constructor(delaunay, [xmin, ymin, xmax, ymax] = [0, 0, 960, 500]) {
+ if (!((xmax = +xmax) >= (xmin = +xmin)) || !((ymax = +ymax) >= (ymin = +ymin))) throw new Error("invalid bounds");
+ this.delaunay = delaunay;
+ this._circumcenters = new Float64Array(delaunay.points.length * 2);
+ this.vectors = new Float64Array(delaunay.points.length * 2);
+ this.xmax = xmax, this.xmin = xmin;
+ this.ymax = ymax, this.ymin = ymin;
+ this._init();
+ }
+ update() {
+ this.delaunay.update();
+ this._init();
+ return this;
+ }
+ _init() {
+ const {delaunay: {points, hull, triangles}, vectors} = this;
+
+ // Compute circumcenters.
+ const circumcenters = this.circumcenters = this._circumcenters.subarray(0, triangles.length / 3 * 2);
+ for (let i = 0, j = 0, n = triangles.length, x, y; i < n; i += 3, j += 2) {
+ const t1 = triangles[i] * 2;
+ const t2 = triangles[i + 1] * 2;
+ const t3 = triangles[i + 2] * 2;
+ const x1 = points[t1];
+ const y1 = points[t1 + 1];
+ const x2 = points[t2];
+ const y2 = points[t2 + 1];
+ const x3 = points[t3];
+ const y3 = points[t3 + 1];
+
+ const dx = x2 - x1;
+ const dy = y2 - y1;
+ const ex = x3 - x1;
+ const ey = y3 - y1;
+ const bl = dx * dx + dy * dy;
+ const cl = ex * ex + ey * ey;
+ const ab = (dx * ey - dy * ex) * 2;
+
+ if (!ab) {
+ // degenerate case (collinear diagram)
+ x = (x1 + x3) / 2 - 1e8 * ey;
+ y = (y1 + y3) / 2 + 1e8 * ex;
+ }
+ else if (Math.abs(ab) < 1e-8) {
+ // almost equal points (degenerate triangle)
+ x = (x1 + x3) / 2;
+ y = (y1 + y3) / 2;
+ } else {
+ const d = 1 / ab;
+ x = x1 + (ey * bl - dy * cl) * d;
+ y = y1 + (dx * cl - ex * bl) * d;
+ }
+ circumcenters[j] = x;
+ circumcenters[j + 1] = y;
+ }
+
+ // Compute exterior cell rays.
+ let h = hull[hull.length - 1];
+ let p0, p1 = h * 4;
+ let x0, x1 = points[2 * h];
+ let y0, y1 = points[2 * h + 1];
+ vectors.fill(0);
+ for (let i = 0; i < hull.length; ++i) {
+ h = hull[i];
+ p0 = p1, x0 = x1, y0 = y1;
+ p1 = h * 4, x1 = points[2 * h], y1 = points[2 * h + 1];
+ vectors[p0 + 2] = vectors[p1] = y0 - y1;
+ vectors[p0 + 3] = vectors[p1 + 1] = x1 - x0;
+ }
+ }
+ render(context) {
+ const buffer = context == null ? context = new Path : undefined;
+ const {delaunay: {halfedges, inedges, hull}, circumcenters, vectors} = this;
+ if (hull.length <= 1) return null;
+ for (let i = 0, n = halfedges.length; i < n; ++i) {
+ const j = halfedges[i];
+ if (j < i) continue;
+ const ti = Math.floor(i / 3) * 2;
+ const tj = Math.floor(j / 3) * 2;
+ const xi = circumcenters[ti];
+ const yi = circumcenters[ti + 1];
+ const xj = circumcenters[tj];
+ const yj = circumcenters[tj + 1];
+ this._renderSegment(xi, yi, xj, yj, context);
+ }
+ let h0, h1 = hull[hull.length - 1];
+ for (let i = 0; i < hull.length; ++i) {
+ h0 = h1, h1 = hull[i];
+ const t = Math.floor(inedges[h1] / 3) * 2;
+ const x = circumcenters[t];
+ const y = circumcenters[t + 1];
+ const v = h0 * 4;
+ const p = this._project(x, y, vectors[v + 2], vectors[v + 3]);
+ if (p) this._renderSegment(x, y, p[0], p[1], context);
+ }
+ return buffer && buffer.value();
+ }
+ renderBounds(context) {
+ const buffer = context == null ? context = new Path : undefined;
+ context.rect(this.xmin, this.ymin, this.xmax - this.xmin, this.ymax - this.ymin);
+ return buffer && buffer.value();
+ }
+ renderCell(i, context) {
+ const buffer = context == null ? context = new Path : undefined;
+ const points = this._clip(i);
+ if (points === null || !points.length) return;
+ context.moveTo(points[0], points[1]);
+ let n = points.length;
+ while (points[0] === points[n-2] && points[1] === points[n-1] && n > 1) n -= 2;
+ for (let i = 2; i < n; i += 2) {
+ if (points[i] !== points[i-2] || points[i+1] !== points[i-1])
+ context.lineTo(points[i], points[i + 1]);
+ }
+ context.closePath();
+ return buffer && buffer.value();
+ }
+ *cellPolygons() {
+ const {delaunay: {points}} = this;
+ for (let i = 0, n = points.length / 2; i < n; ++i) {
+ const cell = this.cellPolygon(i);
+ if (cell) cell.index = i, yield cell;
+ }
+ }
+ cellPolygon(i) {
+ const polygon = new Polygon;
+ this.renderCell(i, polygon);
+ return polygon.value();
+ }
+ _renderSegment(x0, y0, x1, y1, context) {
+ let S;
+ const c0 = this._regioncode(x0, y0);
+ const c1 = this._regioncode(x1, y1);
+ if (c0 === 0 && c1 === 0) {
+ context.moveTo(x0, y0);
+ context.lineTo(x1, y1);
+ } else if (S = this._clipSegment(x0, y0, x1, y1, c0, c1)) {
+ context.moveTo(S[0], S[1]);
+ context.lineTo(S[2], S[3]);
+ }
+ }
+ contains(i, x, y) {
+ if ((x = +x, x !== x) || (y = +y, y !== y)) return false;
+ return this.delaunay._step(i, x, y) === i;
+ }
+ *neighbors(i) {
+ const ci = this._clip(i);
+ if (ci) for (const j of this.delaunay.neighbors(i)) {
+ const cj = this._clip(j);
+ // find the common edge
+ if (cj) loop: for (let ai = 0, li = ci.length; ai < li; ai += 2) {
+ for (let aj = 0, lj = cj.length; aj < lj; aj += 2) {
+ if (ci[ai] == cj[aj]
+ && ci[ai + 1] == cj[aj + 1]
+ && ci[(ai + 2) % li] == cj[(aj + lj - 2) % lj]
+ && ci[(ai + 3) % li] == cj[(aj + lj - 1) % lj]
+ ) {
+ yield j;
+ break loop;
+ }
+ }
+ }
+ }
+ }
+ _cell(i) {
+ const {circumcenters, delaunay: {inedges, halfedges, triangles}} = this;
+ const e0 = inedges[i];
+ if (e0 === -1) return null; // coincident point
+ const points = [];
+ let e = e0;
+ do {
+ const t = Math.floor(e / 3);
+ points.push(circumcenters[t * 2], circumcenters[t * 2 + 1]);
+ e = e % 3 === 2 ? e - 2 : e + 1;
+ if (triangles[e] !== i) break; // bad triangulation
+ e = halfedges[e];
+ } while (e !== e0 && e !== -1);
+ return points;
+ }
+ _clip(i) {
+ // degenerate case (1 valid point: return the box)
+ if (i === 0 && this.delaunay.hull.length === 1) {
+ return [this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax, this.xmin, this.ymin];
+ }
+ const points = this._cell(i);
+ if (points === null) return null;
+ const {vectors: V} = this;
+ const v = i * 4;
+ return V[v] || V[v + 1]
+ ? this._clipInfinite(i, points, V[v], V[v + 1], V[v + 2], V[v + 3])
+ : this._clipFinite(i, points);
+ }
+ _clipFinite(i, points) {
+ const n = points.length;
+ let P = null;
+ let x0, y0, x1 = points[n - 2], y1 = points[n - 1];
+ let c0, c1 = this._regioncode(x1, y1);
+ let e0, e1;
+ for (let j = 0; j < n; j += 2) {
+ x0 = x1, y0 = y1, x1 = points[j], y1 = points[j + 1];
+ c0 = c1, c1 = this._regioncode(x1, y1);
+ if (c0 === 0 && c1 === 0) {
+ e0 = e1, e1 = 0;
+ if (P) P.push(x1, y1);
+ else P = [x1, y1];
+ } else {
+ let S, sx0, sy0, sx1, sy1;
+ if (c0 === 0) {
+ if ((S = this._clipSegment(x0, y0, x1, y1, c0, c1)) === null) continue;
+ [sx0, sy0, sx1, sy1] = S;
+ } else {
+ if ((S = this._clipSegment(x1, y1, x0, y0, c1, c0)) === null) continue;
+ [sx1, sy1, sx0, sy0] = S;
+ e0 = e1, e1 = this._edgecode(sx0, sy0);
+ if (e0 && e1) this._edge(i, e0, e1, P, P.length);
+ if (P) P.push(sx0, sy0);
+ else P = [sx0, sy0];
+ }
+ e0 = e1, e1 = this._edgecode(sx1, sy1);
+ if (e0 && e1) this._edge(i, e0, e1, P, P.length);
+ if (P) P.push(sx1, sy1);
+ else P = [sx1, sy1];
+ }
+ }
+ if (P) {
+ e0 = e1, e1 = this._edgecode(P[0], P[1]);
+ if (e0 && e1) this._edge(i, e0, e1, P, P.length);
+ } else if (this.contains(i, (this.xmin + this.xmax) / 2, (this.ymin + this.ymax) / 2)) {
+ return [this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax, this.xmin, this.ymin];
+ }
+ return P;
+ }
+ _clipSegment(x0, y0, x1, y1, c0, c1) {
+ while (true) {
+ if (c0 === 0 && c1 === 0) return [x0, y0, x1, y1];
+ if (c0 & c1) return null;
+ let x, y, c = c0 || c1;
+ if (c & 0b1000) x = x0 + (x1 - x0) * (this.ymax - y0) / (y1 - y0), y = this.ymax;
+ else if (c & 0b0100) x = x0 + (x1 - x0) * (this.ymin - y0) / (y1 - y0), y = this.ymin;
+ else if (c & 0b0010) y = y0 + (y1 - y0) * (this.xmax - x0) / (x1 - x0), x = this.xmax;
+ else y = y0 + (y1 - y0) * (this.xmin - x0) / (x1 - x0), x = this.xmin;
+ if (c0) x0 = x, y0 = y, c0 = this._regioncode(x0, y0);
+ else x1 = x, y1 = y, c1 = this._regioncode(x1, y1);
+ }
+ }
+ _clipInfinite(i, points, vx0, vy0, vxn, vyn) {
+ let P = Array.from(points), p;
+ if (p = this._project(P[0], P[1], vx0, vy0)) P.unshift(p[0], p[1]);
+ if (p = this._project(P[P.length - 2], P[P.length - 1], vxn, vyn)) P.push(p[0], p[1]);
+ if (P = this._clipFinite(i, P)) {
+ for (let j = 0, n = P.length, c0, c1 = this._edgecode(P[n - 2], P[n - 1]); j < n; j += 2) {
+ c0 = c1, c1 = this._edgecode(P[j], P[j + 1]);
+ if (c0 && c1) j = this._edge(i, c0, c1, P, j), n = P.length;
+ }
+ } else if (this.contains(i, (this.xmin + this.xmax) / 2, (this.ymin + this.ymax) / 2)) {
+ P = [this.xmin, this.ymin, this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax];
+ }
+ return P;
+ }
+ _edge(i, e0, e1, P, j) {
+ while (e0 !== e1) {
+ let x, y;
+ switch (e0) {
+ case 0b0101: e0 = 0b0100; continue; // top-left
+ case 0b0100: e0 = 0b0110, x = this.xmax, y = this.ymin; break; // top
+ case 0b0110: e0 = 0b0010; continue; // top-right
+ case 0b0010: e0 = 0b1010, x = this.xmax, y = this.ymax; break; // right
+ case 0b1010: e0 = 0b1000; continue; // bottom-right
+ case 0b1000: e0 = 0b1001, x = this.xmin, y = this.ymax; break; // bottom
+ case 0b1001: e0 = 0b0001; continue; // bottom-left
+ case 0b0001: e0 = 0b0101, x = this.xmin, y = this.ymin; break; // left
+ }
+ if ((P[j] !== x || P[j + 1] !== y) && this.contains(i, x, y)) {
+ P.splice(j, 0, x, y), j += 2;
+ }
+ }
+ if (P.length > 4) {
+ for (let i = 0; i < P.length; i+= 2) {
+ const j = (i + 2) % P.length, k = (i + 4) % P.length;
+ if (P[i] === P[j] && P[j] === P[k]
+ || P[i + 1] === P[j + 1] && P[j + 1] === P[k + 1])
+ P.splice(j, 2), i -= 2;
+ }
+ }
+ return j;
+ }
+ _project(x0, y0, vx, vy) {
+ let t = Infinity, c, x, y;
+ if (vy < 0) { // top
+ if (y0 <= this.ymin) return null;
+ if ((c = (this.ymin - y0) / vy) < t) y = this.ymin, x = x0 + (t = c) * vx;
+ } else if (vy > 0) { // bottom
+ if (y0 >= this.ymax) return null;
+ if ((c = (this.ymax - y0) / vy) < t) y = this.ymax, x = x0 + (t = c) * vx;
+ }
+ if (vx > 0) { // right
+ if (x0 >= this.xmax) return null;
+ if ((c = (this.xmax - x0) / vx) < t) x = this.xmax, y = y0 + (t = c) * vy;
+ } else if (vx < 0) { // left
+ if (x0 <= this.xmin) return null;
+ if ((c = (this.xmin - x0) / vx) < t) x = this.xmin, y = y0 + (t = c) * vy;
+ }
+ return [x, y];
+ }
+ _edgecode(x, y) {
+ return (x === this.xmin ? 0b0001
+ : x === this.xmax ? 0b0010 : 0b0000)
+ | (y === this.ymin ? 0b0100
+ : y === this.ymax ? 0b1000 : 0b0000);
+ }
+ _regioncode(x, y) {
+ return (x < this.xmin ? 0b0001
+ : x > this.xmax ? 0b0010 : 0b0000)
+ | (y < this.ymin ? 0b0100
+ : y > this.ymax ? 0b1000 : 0b0000);
+ }
+}
+
+const tau = 2 * Math.PI, pow = Math.pow;
+
+function pointX(p) {
+ return p[0];
+}
+
+function pointY(p) {
+ return p[1];
+}
+
+// A triangulation is collinear if all its triangles have a non-null area
+function collinear(d) {
+ const {triangles, coords} = d;
+ for (let i = 0; i < triangles.length; i += 3) {
+ const a = 2 * triangles[i],
+ b = 2 * triangles[i + 1],
+ c = 2 * triangles[i + 2],
+ cross = (coords[c] - coords[a]) * (coords[b + 1] - coords[a + 1])
+ - (coords[b] - coords[a]) * (coords[c + 1] - coords[a + 1]);
+ if (cross > 1e-10) return false;
+ }
+ return true;
+}
+
+function jitter(x, y, r) {
+ return [x + Math.sin(x + y) * r, y + Math.cos(x - y) * r];
+}
+
+class Delaunay {
+ static from(points, fx = pointX, fy = pointY, that) {
+ return new Delaunay("length" in points
+ ? flatArray(points, fx, fy, that)
+ : Float64Array.from(flatIterable(points, fx, fy, that)));
+ }
+ constructor(points) {
+ this._delaunator = new Delaunator(points);
+ this.inedges = new Int32Array(points.length / 2);
+ this._hullIndex = new Int32Array(points.length / 2);
+ this.points = this._delaunator.coords;
+ this._init();
+ }
+ update() {
+ this._delaunator.update();
+ this._init();
+ return this;
+ }
+ _init() {
+ const d = this._delaunator, points = this.points;
+
+ // check for collinear
+ if (d.hull && d.hull.length > 2 && collinear(d)) {
+ this.collinear = Int32Array.from({length: points.length/2}, (_,i) => i)
+ .sort((i, j) => points[2 * i] - points[2 * j] || points[2 * i + 1] - points[2 * j + 1]); // for exact neighbors
+ const e = this.collinear[0], f = this.collinear[this.collinear.length - 1],
+ bounds = [ points[2 * e], points[2 * e + 1], points[2 * f], points[2 * f + 1] ],
+ r = 1e-8 * Math.hypot(bounds[3] - bounds[1], bounds[2] - bounds[0]);
+ for (let i = 0, n = points.length / 2; i < n; ++i) {
+ const p = jitter(points[2 * i], points[2 * i + 1], r);
+ points[2 * i] = p[0];
+ points[2 * i + 1] = p[1];
+ }
+ this._delaunator = new Delaunator(points);
+ } else {
+ delete this.collinear;
+ }
+
+ const halfedges = this.halfedges = this._delaunator.halfedges;
+ const hull = this.hull = this._delaunator.hull;
+ const triangles = this.triangles = this._delaunator.triangles;
+ const inedges = this.inedges.fill(-1);
+ const hullIndex = this._hullIndex.fill(-1);
+
+ // Compute an index from each point to an (arbitrary) incoming halfedge
+ // Used to give the first neighbor of each point; for this reason,
+ // on the hull we give priority to exterior halfedges
+ for (let e = 0, n = halfedges.length; e < n; ++e) {
+ const p = triangles[e % 3 === 2 ? e - 2 : e + 1];
+ if (halfedges[e] === -1 || inedges[p] === -1) inedges[p] = e;
+ }
+ for (let i = 0, n = hull.length; i < n; ++i) {
+ hullIndex[hull[i]] = i;
+ }
+
+ // degenerate case: 1 or 2 (distinct) points
+ if (hull.length <= 2 && hull.length > 0) {
+ this.triangles = new Int32Array(3).fill(-1);
+ this.halfedges = new Int32Array(3).fill(-1);
+ this.triangles[0] = hull[0];
+ this.triangles[1] = hull[1];
+ this.triangles[2] = hull[1];
+ inedges[hull[0]] = 1;
+ if (hull.length === 2) inedges[hull[1]] = 0;
+ }
+ }
+ voronoi(bounds) {
+ return new Voronoi(this, bounds);
+ }
+ *neighbors(i) {
+ const {inedges, hull, _hullIndex, halfedges, triangles, collinear} = this;
+
+ // degenerate case with several collinear points
+ if (collinear) {
+ const l = collinear.indexOf(i);
+ if (l > 0) yield collinear[l - 1];
+ if (l < collinear.length - 1) yield collinear[l + 1];
+ return;
+ }
+
+ const e0 = inedges[i];
+ if (e0 === -1) return; // coincident point
+ let e = e0, p0 = -1;
+ do {
+ yield p0 = triangles[e];
+ e = e % 3 === 2 ? e - 2 : e + 1;
+ if (triangles[e] !== i) return; // bad triangulation
+ e = halfedges[e];
+ if (e === -1) {
+ const p = hull[(_hullIndex[i] + 1) % hull.length];
+ if (p !== p0) yield p;
+ return;
+ }
+ } while (e !== e0);
+ }
+ find(x, y, i = 0) {
+ if ((x = +x, x !== x) || (y = +y, y !== y)) return -1;
+ const i0 = i;
+ let c;
+ while ((c = this._step(i, x, y)) >= 0 && c !== i && c !== i0) i = c;
+ return c;
+ }
+ _step(i, x, y) {
+ const {inedges, hull, _hullIndex, halfedges, triangles, points} = this;
+ if (inedges[i] === -1 || !points.length) return (i + 1) % (points.length >> 1);
+ let c = i;
+ let dc = pow(x - points[i * 2], 2) + pow(y - points[i * 2 + 1], 2);
+ const e0 = inedges[i];
+ let e = e0;
+ do {
+ let t = triangles[e];
+ const dt = pow(x - points[t * 2], 2) + pow(y - points[t * 2 + 1], 2);
+ if (dt < dc) dc = dt, c = t;
+ e = e % 3 === 2 ? e - 2 : e + 1;
+ if (triangles[e] !== i) break; // bad triangulation
+ e = halfedges[e];
+ if (e === -1) {
+ e = hull[(_hullIndex[i] + 1) % hull.length];
+ if (e !== t) {
+ if (pow(x - points[e * 2], 2) + pow(y - points[e * 2 + 1], 2) < dc) return e;
+ }
+ break;
+ }
+ } while (e !== e0);
+ return c;
+ }
+ render(context) {
+ const buffer = context == null ? context = new Path : undefined;
+ const {points, halfedges, triangles} = this;
+ for (let i = 0, n = halfedges.length; i < n; ++i) {
+ const j = halfedges[i];
+ if (j < i) continue;
+ const ti = triangles[i] * 2;
+ const tj = triangles[j] * 2;
+ context.moveTo(points[ti], points[ti + 1]);
+ context.lineTo(points[tj], points[tj + 1]);
+ }
+ this.renderHull(context);
+ return buffer && buffer.value();
+ }
+ renderPoints(context, r = 2) {
+ const buffer = context == null ? context = new Path : undefined;
+ const {points} = this;
+ for (let i = 0, n = points.length; i < n; i += 2) {
+ const x = points[i], y = points[i + 1];
+ context.moveTo(x + r, y);
+ context.arc(x, y, r, 0, tau);
+ }
+ return buffer && buffer.value();
+ }
+ renderHull(context) {
+ const buffer = context == null ? context = new Path : undefined;
+ const {hull, points} = this;
+ const h = hull[0] * 2, n = hull.length;
+ context.moveTo(points[h], points[h + 1]);
+ for (let i = 1; i < n; ++i) {
+ const h = 2 * hull[i];
+ context.lineTo(points[h], points[h + 1]);
+ }
+ context.closePath();
+ return buffer && buffer.value();
+ }
+ hullPolygon() {
+ const polygon = new Polygon;
+ this.renderHull(polygon);
+ return polygon.value();
+ }
+ renderTriangle(i, context) {
+ const buffer = context == null ? context = new Path : undefined;
+ const {points, triangles} = this;
+ const t0 = triangles[i *= 3] * 2;
+ const t1 = triangles[i + 1] * 2;
+ const t2 = triangles[i + 2] * 2;
+ context.moveTo(points[t0], points[t0 + 1]);
+ context.lineTo(points[t1], points[t1 + 1]);
+ context.lineTo(points[t2], points[t2 + 1]);
+ context.closePath();
+ return buffer && buffer.value();
+ }
+ *trianglePolygons() {
+ const {triangles} = this;
+ for (let i = 0, n = triangles.length / 3; i < n; ++i) {
+ yield this.trianglePolygon(i);
+ }
+ }
+ trianglePolygon(i) {
+ const polygon = new Polygon;
+ this.renderTriangle(i, polygon);
+ return polygon.value();
+ }
+}
+
+function flatArray(points, fx, fy, that) {
+ const n = points.length;
+ const array = new Float64Array(n * 2);
+ for (let i = 0; i < n; ++i) {
+ const p = points[i];
+ array[i * 2] = fx.call(that, p, i, points);
+ array[i * 2 + 1] = fy.call(that, p, i, points);
+ }
+ return array;
+}
+
+function* flatIterable(points, fx, fy, that) {
+ let i = 0;
+ for (const p of points) {
+ yield fx.call(that, p, i, points);
+ yield fy.call(that, p, i, points);
+ ++i;
+ }
+}
+
+exports.Delaunay = Delaunay;
+exports.Voronoi = Voronoi;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-delaunay/dist/d3-delaunay.min.js b/node_modules/d3-delaunay/dist/d3-delaunay.min.js
new file mode 100644
index 00000000..2473bdf2
--- /dev/null
+++ b/node_modules/d3-delaunay/dist/d3-delaunay.min.js
@@ -0,0 +1,3 @@
+// https://github.com/d3/d3-delaunay v5.3.0 Copyright 2020 Mike Bostock
+// https://github.com/mapbox/delaunator v4.0.1. Copyright 2019 Mapbox, Inc.
+!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((t=t||self).d3=t.d3||{})}(this,function(t){"use strict";const i=Math.pow(2,-52),e=new Uint32Array(512);class n{static from(t,i=u,e=_){const s=t.length,h=new Float64Array(2*s);for(let n=0;n>1;if(i>0&&"number"!=typeof t[0])throw new Error("Expected coords to contain numbers.");this.coords=t;const e=Math.max(2*i-5,0);this._triangles=new Uint32Array(3*e),this._halfedges=new Int32Array(3*e),this._hashSize=Math.ceil(Math.sqrt(i)),this._hullPrev=new Uint32Array(i),this._hullNext=new Uint32Array(i),this._hullTri=new Uint32Array(i),this._hullHash=new Int32Array(this._hashSize).fill(-1),this._ids=new Uint32Array(i),this._dists=new Float64Array(i),this.update()}update(){const{coords:t,_hullPrev:e,_hullNext:n,_hullTri:h,_hullHash:r}=this,c=t.length>>1;let u=1/0,_=1/0,f=-1/0,d=-1/0;for(let i=0;i=h-e?(a(t,i,s,n),a(t,i,e,h-1)):(a(t,i,e,h-1),a(t,i,s,n))}}function c(t,i,e){const n=t[i];t[i]=t[e],t[e]=n}function u(t){return t[0]}function _(t){return t[1]}const f=1e-6;class d{constructor(){this._x0=this._y0=this._x1=this._y1=null,this._=""}moveTo(t,i){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+i}`}closePath(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")}lineTo(t,i){this._+=`L${this._x1=+t},${this._y1=+i}`}arc(t,i,e){const n=(t=+t)+(e=+e),s=i=+i;if(e<0)throw new Error("negative radius");null===this._x1?this._+=`M${n},${s}`:(Math.abs(this._x1-n)>f||Math.abs(this._y1-s)>f)&&(this._+="L"+n+","+s),e&&(this._+=`A${e},${e},0,1,1,${t-e},${i}A${e},${e},0,1,1,${this._x1=n},${this._y1=s}`)}rect(t,i,e,n){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+i}h${+e}v${+n}h${-e}Z`}value(){return this._||null}}class g{constructor(){this._=[]}moveTo(t,i){this._.push([t,i])}closePath(){this._.push(this._[0].slice())}lineTo(t,i){this._.push([t,i])}value(){return this._.length?this._:null}}class y{constructor(t,[i,e,n,s]=[0,0,960,500]){if(!((n=+n)>=(i=+i)&&(s=+s)>=(e=+e)))throw new Error("invalid bounds");this.delaunay=t,this._circumcenters=new Float64Array(2*t.points.length),this.vectors=new Float64Array(2*t.points.length),this.xmax=n,this.xmin=i,this.ymax=s,this.ymin=e,this._init()}update(){return this.delaunay.update(),this._init(),this}_init(){const{delaunay:{points:t,hull:i,triangles:e},vectors:n}=this,s=this.circumcenters=this._circumcenters.subarray(0,e.length/3*2);for(let i,n,h=0,l=0,r=e.length;h4)for(let t=0;t2&&function(t){const{triangles:i,coords:e}=t;for(let t=0;t
](https://observablehq.com/@d3/force-directed-graph)[
](https://observablehq.com/d/c55a5839a5bb7c73)
+
+You can also use d3-drag to implement custom user interface elements, such as a slider. But the drag behavior isn’t just for moving elements around; there are a variety of ways to respond to a drag gesture. For example, you can use it to lasso elements in a scatterplot, or to paint lines on a canvas:
+
+[
](https://observablehq.com/@d3/draw-me)
+
+The drag behavior can be combined with other behaviors, such as [d3-zoom](https://github.com/d3/d3-zoom) for zooming.
+
+[
](https://observablehq.com/@d3/drag-zoom)
+
+The drag behavior is agnostic about the DOM, so you can use it with SVG, HTML or even Canvas! And you can extend it with advanced selection techniques, such as a Voronoi overlay or a closest-target search:
+
+[
](https://observablehq.com/@d3/circle-dragging-iii)[
](https://observablehq.com/@d3/circle-dragging-ii)
+
+Best of all, the drag behavior automatically unifies mouse and touch input, and avoids browser idiosyncrasies. When [Pointer Events](https://www.w3.org/TR/pointerevents/) are more widely available, the drag behavior will support those, too.
+
+## Installing
+
+If you use NPM, `npm install d3-drag`. Otherwise, download the [latest release](https://github.com/d3/d3-drag/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-drag.v2.min.js) or as part of [D3](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:
+
+```html
+
+
+
+
+```
+
+[Try d3-drag in your browser.](https://observablehq.com/collection/@d3/d3-drag)
+
+## API Reference
+
+This table describes how the drag behavior interprets native events:
+
+| Event | Listening Element | Drag Event | Default Prevented? |
+| ------------ | ----------------- | ---------- | ------------------ |
+| mousedownⵠ| selection | start | no¹ |
+| mousemove² | window¹ | drag | yes |
+| mouseup² | window¹ | end | yes |
+| dragstart² | window | - | yes |
+| selectstart² | window | - | yes |
+| click³ | window | - | yes |
+| touchstart | selection | start | noâ´ |
+| touchmove | selection | drag | yes |
+| touchend | selection | end | noâ´ |
+| touchcancel | selection | end | noâ´ |
+
+The propagation of all consumed events is [immediately stopped](https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation). If you want to prevent some events from initiating a drag gesture, use [*drag*.filter](#drag_filter).
+
+¹ Necessary to capture events outside an iframe; see [#9](https://github.com/d3/d3-drag/issues/9).
+
² Only applies during an active, mouse-based gesture; see [#9](https://github.com/d3/d3-drag/issues/9).
+
³ Only applies immediately after some mouse-based gestures; see [*drag*.clickDistance](#drag_clickDistance).
+
â´ Necessary to allow [click emulation](https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html#//apple_ref/doc/uid/TP40006511-SW7) on touch input; see [#9](https://github.com/d3/d3-drag/issues/9).
+
âµ Ignored if within 500ms of a touch gesture ending; assumes [click emulation](https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html#//apple_ref/doc/uid/TP40006511-SW7).
+
+# d3.drag() · [Source](https://github.com/d3/d3-drag/blob/master/src/drag.js), [Examples](https://observablehq.com/collection/@d3/d3-drag)
+
+Creates a new drag behavior. The returned behavior, [*drag*](#_drag), is both an object and a function, and is typically applied to selected elements via [*selection*.call](https://github.com/d3/d3-selection#selection_call).
+
+# drag(selection) · [Source](https://github.com/d3/d3-drag/blob/master/src/drag.js), [Examples](https://observablehq.com/collection/@d3/d3-drag)
+
+Applies this drag behavior to the specified [*selection*](https://github.com/d3/d3-selection). This function is typically not invoked directly, and is instead invoked via [*selection*.call](https://github.com/d3/d3-selection#selection_call). For example, to instantiate a drag behavior and apply it to a selection:
+
+```js
+d3.selectAll(".node").call(d3.drag().on("start", started));
+```
+
+Internally, the drag behavior uses [*selection*.on](https://github.com/d3/d3-selection#selection_on) to bind the necessary event listeners for dragging. The listeners use the name `.drag`, so you can subsequently unbind the drag behavior as follows:
+
+```js
+selection.on(".drag", null);
+```
+
+Applying the drag behavior also sets the [-webkit-tap-highlight-color](https://developer.apple.com/library/mac/documentation/AppleApplications/Reference/SafariWebContent/AdjustingtheTextSize/AdjustingtheTextSize.html#//apple_ref/doc/uid/TP40006510-SW5) style to transparent, disabling the tap highlight on iOS. If you want a different tap highlight color, remove or re-apply this style after applying the drag behavior.
+
+# drag.container([container]) · [Source](https://github.com/d3/d3-drag/blob/master/src/drag.js), [Examples](https://observablehq.com/collection/@d3/d3-drag)
+
+If *container* is specified, sets the container accessor to the specified object or function and returns the drag behavior. If *container* is not specified, returns the current container accessor, which defaults to:
+
+```js
+function container() {
+ return this.parentNode;
+}
+```
+
+The *container* of a drag gesture determines the coordinate system of subsequent [drag events](#drag-events), affecting *event*.x and *event*.y. The element returned by the container accessor is subsequently passed to [d3.pointer](https://github.com/d3/d3-selection#pointer) to determine the local coordinates of the pointer.
+
+The default container accessor returns the parent node of the element in the originating selection (see [*drag*](#_drag)) that received the initiating input event. This is often appropriate when dragging SVG or HTML elements, since those elements are typically positioned relative to a parent. For dragging graphical elements with a Canvas, however, you may want to redefine the container as the initiating element itself:
+
+```js
+function container() {
+ return this;
+}
+```
+
+Alternatively, the container may be specified as the element directly, such as `drag.container(canvas)`.
+
+
+# drag.filter([filter]) · [Source](https://github.com/d3/d3-drag/blob/master/src/drag.js), [Examples](https://observablehq.com/d/c55a5839a5bb7c73)
+
+If *filter* is specified, sets the event filter to the specified function and returns the drag behavior. If *filter* is not specified, returns the current filter, which defaults to:
+
+```js
+function filter(event) {
+ return !event.ctrlKey && !event.button;
+}
+```
+
+If the filter returns falsey, the initiating event is ignored and no drag gestures are started. Thus, the filter determines which input events are ignored; the default filter ignores mousedown events on secondary buttons, since those buttons are typically intended for other purposes, such as the context menu.
+
+# drag.touchable([touchable]) · [Source](https://github.com/d3/d3-drag/blob/master/src/drag.js), [Examples](https://observablehq.com/d/c55a5839a5bb7c73)
+
+If *touchable* is specified, sets the touch support detector to the specified function and returns the drag behavior. If *touchable* is not specified, returns the current touch support detector, which defaults to:
+
+```js
+function touchable() {
+ return navigator.maxTouchPoints || ("ontouchstart" in this);
+}
+```
+
+Touch event listeners are only registered if the detector returns truthy for the corresponding element when the drag behavior is [applied](#_drag). The default detector works well for most browsers that are capable of touch input, but not all; Chrome’s mobile device emulator, for example, fails detection.
+
+# drag.subject([subject]) · [Source](https://github.com/d3/d3-drag/blob/master/src/drag.js), [Examples](https://observablehq.com/collection/@d3/d3-drag)
+
+If *subject* is specified, sets the subject accessor to the specified object or function and returns the drag behavior. If *subject* is not specified, returns the current subject accessor, which defaults to:
+
+```js
+function subject(event, d) {
+ return d == null ? {x: event.x, y: event.y} : d;
+}
+```
+
+The *subject* of a drag gesture represents *the thing being dragged*. It is computed when an initiating input event is received, such as a mousedown or touchstart, immediately before the drag gesture starts. The subject is then exposed as *event*.subject on subsequent [drag events](#drag-events) for this gesture.
+
+The default subject is the [datum](https://github.com/d3/d3-selection#selection_datum) of the element in the originating selection (see [*drag*](#_drag)) that received the initiating input event; if this datum is undefined, an object representing the coordinates of the pointer is created. When dragging circle elements in SVG, the default subject is thus the datum of the circle being dragged. With [Canvas](https://html.spec.whatwg.org/multipage/scripting.html#the-canvas-element), the default subject is the canvas element’s datum (regardless of where on the canvas you click). In this case, a custom subject accessor would be more appropriate, such as one that picks the closest circle to the mouse within a given search *radius*:
+
+```js
+function subject(event) {
+ var n = circles.length,
+ i,
+ dx,
+ dy,
+ d2,
+ s2 = radius * radius,
+ circle,
+ subject;
+
+ for (i = 0; i < n; ++i) {
+ circle = circles[i];
+ dx = event.x - circle.x;
+ dy = event.y - circle.y;
+ d2 = dx * dx + dy * dy;
+ if (d2 < s2) subject = circle, s2 = d2;
+ }
+
+ return subject;
+}
+```
+
+(If necessary, the above can be accelerated using [*quadtree*.find](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_find), [*simulation*.find](https://github.com/d3/d3-force/blob/master/README.md#simulation_find) or [*delaunay*.find](https://github.com/d3/d3-delaunay/blob/master/README.md#delaunay_find).)
+
+The returned subject should be an object that exposes `x` and `y` properties, so that the relative position of the subject and the pointer can be preserved during the drag gesture. If the subject is null or undefined, no drag gesture is started for this pointer; however, other starting touches may yet start drag gestures. See also [*drag*.filter](#drag_filter).
+
+The subject of a drag gesture may not be changed after the gesture starts. The subject accessor is invoked with the same context and arguments as [*selection*.on](https://github.com/d3/d3-selection#selection_on) listeners: the current event (`event`) and datum `d`, with the `this` context as the current DOM element. During the evaluation of the subject accessor, `event` is a beforestart [drag event](#drag-events). Use *event*.sourceEvent to access the initiating input event and *event*.identifier to access the touch identifier. The *event*.x and *event*.y are relative to the [container](#drag_container), and are computed using [d3.pointer](https://github.com/d3/d3-selection#pointer).
+
+# drag.clickDistance([distance]) · [Source](https://github.com/d3/d3-drag/blob/master/src/drag.js)
+
+If *distance* is specified, sets the maximum distance that the mouse can move between mousedown and mouseup that will trigger a subsequent click event. If at any point between mousedown and mouseup the mouse is greater than or equal to *distance* from its position on mousedown, the click event following mouseup will be suppressed. If *distance* is not specified, returns the current distance threshold, which defaults to zero. The distance threshold is measured in client coordinates ([*event*.clientX](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/clientX) and [*event*.clientY](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/clientY)).
+
+# drag.on(typenames, [listener]) · [Source](https://github.com/d3/d3-drag/blob/master/src/drag.js)
+
+If *listener* is specified, sets the event *listener* for the specified *typenames* and returns the drag behavior. If an event listener was already registered for the same type and name, the existing listener is removed before the new listener is added. If *listener* is null, removes the current event listeners for the specified *typenames*, if any. If *listener* is not specified, returns the first currently-assigned listener matching the specified *typenames*, if any. When a specified event is dispatched, each *listener* will be invoked with the same context and arguments as [*selection*.on](https://github.com/d3/d3-selection#selection_on) listeners: the current event (`event`) and datum `d`, with the `this` context as the current DOM element.
+
+The *typenames* is a string containing one or more *typename* separated by whitespace. Each *typename* is a *type*, optionally followed by a period (`.`) and a *name*, such as `drag.foo` and `drag.bar`; the name allows multiple listeners to be registered for the same *type*. The *type* must be one of the following:
+
+* `start` - after a new pointer becomes active (on mousedown or touchstart).
+* `drag` - after an active pointer moves (on mousemove or touchmove).
+* `end` - after an active pointer becomes inactive (on mouseup, touchend or touchcancel).
+
+See [*dispatch*.on](https://github.com/d3/d3-dispatch#dispatch_on) for more.
+
+Changes to registered listeners via *drag*.on during a drag gesture *do not affect* the current drag gesture. Instead, you must use [*event*.on](#event_on), which also allows you to register temporary event listeners for the current drag gesture. **Separate events are dispatched for each active pointer** during a drag gesture. For example, if simultaneously dragging multiple subjects with multiple fingers, a start event is dispatched for each finger, even if both fingers start touching simultaneously. See [Drag Events](#drag-events) for more.
+
+# d3.dragDisable(window) · [Source](https://github.com/d3/d3-drag/blob/master/src/nodrag.js)
+
+Prevents native drag-and-drop and text selection on the specified *window*. As an alternative to preventing the default action of mousedown events (see [#9](https://github.com/d3/d3-drag/issues/9)), this method prevents undesirable default actions following mousedown. In supported browsers, this means capturing dragstart and selectstart events, preventing the associated default actions, and immediately stopping their propagation. In browsers that do not support selection events, the user-select CSS property is set to none on the document element. This method is intended to be called on mousedown, followed by [d3.dragEnable](#dragEnable) on mouseup.
+
+# d3.dragEnable(window[, noclick]) · [Source](https://github.com/d3/d3-drag/blob/master/src/nodrag.js)
+
+Allows native drag-and-drop and text selection on the specified *window*; undoes the effect of [d3.dragDisable](#dragDisable). This method is intended to be called on mouseup, preceded by [d3.dragDisable](#dragDisable) on mousedown. If *noclick* is true, this method also temporarily suppresses click events. The suppression of click events expires after a zero-millisecond timeout, such that it only suppress the click event that would immediately follow the current mouseup event, if any.
+
+### Drag Events
+
+When a [drag event listener](#drag_on) is invoked, it receives the current drag event as its first argument. The *event* object exposes several fields:
+
+* `target` - the associated [drag behavior](#drag).
+* `type` - the string “startâ€, “drag†or “endâ€; see [*drag*.on](#drag_on).
+* `subject` - the drag subject, defined by [*drag*.subject](#drag_subject).
+* `x` - the new *x*-coordinate of the subject; see [*drag*.container](#drag_container).
+* `y` - the new *y*-coordinate of the subject; see [*drag*.container](#drag_container).
+* `dx` - the change in *x*-coordinate since the previous drag event.
+* `dy` - the change in *y*-coordinate since the previous drag event.
+* `identifier` - the string “mouseâ€, or a numeric [touch identifier](https://www.w3.org/TR/touch-events/#widl-Touch-identifier).
+* `active` - the number of currently active drag gestures (on start and end, not including this one).
+* `sourceEvent` - the underlying input event, such as mousemove or touchmove.
+
+The *event*.active field is useful for detecting the first start event and the last end event in a sequence of concurrent drag gestures: it is zero when the first drag gesture starts, and zero when the last drag gesture ends.
+
+The *event* object also exposes the [*event*.on](#event_on) method.
+
+# event.on(typenames, [listener]) · [Source](https://github.com/d3/d3-drag/blob/master/src/event.js)
+
+Equivalent to [*drag*.on](#drag_on), but only applies to the current drag gesture. Before the drag gesture starts, a [copy](https://github.com/d3/d3-dispatch#dispatch_copy) of the current drag [event listeners](#drag_on) is made. This copy is bound to the current drag gesture and modified by *event*.on. This is useful for temporary listeners that only receive events for the current drag gesture. For example, this start event listener registers temporary drag and end event listeners as closures:
+
+```js
+function started(event) {
+ var circle = d3.select(this).classed("dragging", true);
+
+ event.on("drag", dragged).on("end", ended);
+
+ function dragged(event, d) {
+ circle.raise().attr("cx", d.x = event.x).attr("cy", d.y = event.y);
+ }
+
+ function ended() {
+ circle.classed("dragging", false);
+ }
+}
+```
diff --git a/node_modules/d3-drag/dist/d3-drag.js b/node_modules/d3-drag/dist/d3-drag.js
new file mode 100644
index 00000000..b63be970
--- /dev/null
+++ b/node_modules/d3-drag/dist/d3-drag.js
@@ -0,0 +1,266 @@
+// https://d3js.org/d3-drag/ v2.0.0 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-dispatch'), require('d3-selection')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-dispatch', 'd3-selection'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}, global.d3, global.d3));
+}(this, function (exports, d3Dispatch, d3Selection) { 'use strict';
+
+function nopropagation(event) {
+ event.stopImmediatePropagation();
+}
+
+function noevent(event) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+}
+
+function nodrag(view) {
+ var root = view.document.documentElement,
+ selection = d3Selection.select(view).on("dragstart.drag", noevent, true);
+ if ("onselectstart" in root) {
+ selection.on("selectstart.drag", noevent, true);
+ } else {
+ root.__noselect = root.style.MozUserSelect;
+ root.style.MozUserSelect = "none";
+ }
+}
+
+function yesdrag(view, noclick) {
+ var root = view.document.documentElement,
+ selection = d3Selection.select(view).on("dragstart.drag", null);
+ if (noclick) {
+ selection.on("click.drag", noevent, true);
+ setTimeout(function() { selection.on("click.drag", null); }, 0);
+ }
+ if ("onselectstart" in root) {
+ selection.on("selectstart.drag", null);
+ } else {
+ root.style.MozUserSelect = root.__noselect;
+ delete root.__noselect;
+ }
+}
+
+var constant = x => () => x;
+
+function DragEvent(type, {
+ sourceEvent,
+ subject,
+ target,
+ identifier,
+ active,
+ x, y, dx, dy,
+ dispatch
+}) {
+ Object.defineProperties(this, {
+ type: {value: type, enumerable: true, configurable: true},
+ sourceEvent: {value: sourceEvent, enumerable: true, configurable: true},
+ subject: {value: subject, enumerable: true, configurable: true},
+ target: {value: target, enumerable: true, configurable: true},
+ identifier: {value: identifier, enumerable: true, configurable: true},
+ active: {value: active, enumerable: true, configurable: true},
+ x: {value: x, enumerable: true, configurable: true},
+ y: {value: y, enumerable: true, configurable: true},
+ dx: {value: dx, enumerable: true, configurable: true},
+ dy: {value: dy, enumerable: true, configurable: true},
+ _: {value: dispatch}
+ });
+}
+
+DragEvent.prototype.on = function() {
+ var value = this._.on.apply(this._, arguments);
+ return value === this._ ? this : value;
+};
+
+// Ignore right-click, since that should open the context menu.
+function defaultFilter(event) {
+ return !event.ctrlKey && !event.button;
+}
+
+function defaultContainer() {
+ return this.parentNode;
+}
+
+function defaultSubject(event, d) {
+ return d == null ? {x: event.x, y: event.y} : d;
+}
+
+function defaultTouchable() {
+ return navigator.maxTouchPoints || ("ontouchstart" in this);
+}
+
+function drag() {
+ var filter = defaultFilter,
+ container = defaultContainer,
+ subject = defaultSubject,
+ touchable = defaultTouchable,
+ gestures = {},
+ listeners = d3Dispatch.dispatch("start", "drag", "end"),
+ active = 0,
+ mousedownx,
+ mousedowny,
+ mousemoving,
+ touchending,
+ clickDistance2 = 0;
+
+ function drag(selection) {
+ selection
+ .on("mousedown.drag", mousedowned)
+ .filter(touchable)
+ .on("touchstart.drag", touchstarted)
+ .on("touchmove.drag", touchmoved)
+ .on("touchend.drag touchcancel.drag", touchended)
+ .style("touch-action", "none")
+ .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
+ }
+
+ function mousedowned(event, d) {
+ if (touchending || !filter.call(this, event, d)) return;
+ var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
+ if (!gesture) return;
+ d3Selection.select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
+ nodrag(event.view);
+ nopropagation(event);
+ mousemoving = false;
+ mousedownx = event.clientX;
+ mousedowny = event.clientY;
+ gesture("start", event);
+ }
+
+ function mousemoved(event) {
+ noevent(event);
+ if (!mousemoving) {
+ var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny;
+ mousemoving = dx * dx + dy * dy > clickDistance2;
+ }
+ gestures.mouse("drag", event);
+ }
+
+ function mouseupped(event) {
+ d3Selection.select(event.view).on("mousemove.drag mouseup.drag", null);
+ yesdrag(event.view, mousemoving);
+ noevent(event);
+ gestures.mouse("end", event);
+ }
+
+ function touchstarted(event, d) {
+ if (!filter.call(this, event, d)) return;
+ var touches = event.changedTouches,
+ c = container.call(this, event, d),
+ n = touches.length, i, gesture;
+
+ for (i = 0; i < n; ++i) {
+ if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {
+ nopropagation(event);
+ gesture("start", event, touches[i]);
+ }
+ }
+ }
+
+ function touchmoved(event) {
+ var touches = event.changedTouches,
+ n = touches.length, i, gesture;
+
+ for (i = 0; i < n; ++i) {
+ if (gesture = gestures[touches[i].identifier]) {
+ noevent(event);
+ gesture("drag", event, touches[i]);
+ }
+ }
+ }
+
+ function touchended(event) {
+ var touches = event.changedTouches,
+ n = touches.length, i, gesture;
+
+ if (touchending) clearTimeout(touchending);
+ touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
+ for (i = 0; i < n; ++i) {
+ if (gesture = gestures[touches[i].identifier]) {
+ nopropagation(event);
+ gesture("end", event, touches[i]);
+ }
+ }
+ }
+
+ function beforestart(that, container, event, d, identifier, touch) {
+ var dispatch = listeners.copy(),
+ p = d3Selection.pointer(touch || event, container), dx, dy,
+ s;
+
+ if ((s = subject.call(that, new DragEvent("beforestart", {
+ sourceEvent: event,
+ target: drag,
+ identifier,
+ active,
+ x: p[0],
+ y: p[1],
+ dx: 0,
+ dy: 0,
+ dispatch
+ }), d)) == null) return;
+
+ dx = s.x - p[0] || 0;
+ dy = s.y - p[1] || 0;
+
+ return function gesture(type, event, touch) {
+ var p0 = p, n;
+ switch (type) {
+ case "start": gestures[identifier] = gesture, n = active++; break;
+ case "end": delete gestures[identifier], --active; // nobreak
+ case "drag": p = d3Selection.pointer(touch || event, container), n = active; break;
+ }
+ dispatch.call(
+ type,
+ that,
+ new DragEvent(type, {
+ sourceEvent: event,
+ subject: s,
+ target: drag,
+ identifier,
+ active: n,
+ x: p[0] + dx,
+ y: p[1] + dy,
+ dx: p[0] - p0[0],
+ dy: p[1] - p0[1],
+ dispatch
+ }),
+ d
+ );
+ };
+ }
+
+ drag.filter = function(_) {
+ return arguments.length ? (filter = typeof _ === "function" ? _ : constant(!!_), drag) : filter;
+ };
+
+ drag.container = function(_) {
+ return arguments.length ? (container = typeof _ === "function" ? _ : constant(_), drag) : container;
+ };
+
+ drag.subject = function(_) {
+ return arguments.length ? (subject = typeof _ === "function" ? _ : constant(_), drag) : subject;
+ };
+
+ drag.touchable = function(_) {
+ return arguments.length ? (touchable = typeof _ === "function" ? _ : constant(!!_), drag) : touchable;
+ };
+
+ drag.on = function() {
+ var value = listeners.on.apply(listeners, arguments);
+ return value === listeners ? drag : value;
+ };
+
+ drag.clickDistance = function(_) {
+ return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
+ };
+
+ return drag;
+}
+
+exports.drag = drag;
+exports.dragDisable = nodrag;
+exports.dragEnable = yesdrag;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-drag/dist/d3-drag.min.js b/node_modules/d3-drag/dist/d3-drag.min.js
new file mode 100644
index 00000000..a489e35e
--- /dev/null
+++ b/node_modules/d3-drag/dist/d3-drag.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-drag/ v2.0.0 Copyright 2020 Mike Bostock
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-dispatch"),require("d3-selection")):"function"==typeof define&&define.amd?define(["exports","d3-dispatch","d3-selection"],t):t((e=e||self).d3=e.d3||{},e.d3,e.d3)}(this,function(e,t,n){"use strict";function o(e){e.stopImmediatePropagation()}function r(e){e.preventDefault(),e.stopImmediatePropagation()}function i(e){var t=e.document.documentElement,o=n.select(e).on("dragstart.drag",r,!0);"onselectstart"in t?o.on("selectstart.drag",r,!0):(t.__noselect=t.style.MozUserSelect,t.style.MozUserSelect="none")}function a(e,t){var o=e.document.documentElement,i=n.select(e).on("dragstart.drag",null);t&&(i.on("click.drag",r,!0),setTimeout(function(){i.on("click.drag",null)},0)),"onselectstart"in o?i.on("selectstart.drag",null):(o.style.MozUserSelect=o.__noselect,delete o.__noselect)}var u=e=>()=>e;function c(e,{sourceEvent:t,subject:n,target:o,identifier:r,active:i,x:a,y:u,dx:c,dy:l,dispatch:s}){Object.defineProperties(this,{type:{value:e,enumerable:!0,configurable:!0},sourceEvent:{value:t,enumerable:!0,configurable:!0},subject:{value:n,enumerable:!0,configurable:!0},target:{value:o,enumerable:!0,configurable:!0},identifier:{value:r,enumerable:!0,configurable:!0},active:{value:i,enumerable:!0,configurable:!0},x:{value:a,enumerable:!0,configurable:!0},y:{value:u,enumerable:!0,configurable:!0},dx:{value:c,enumerable:!0,configurable:!0},dy:{value:l,enumerable:!0,configurable:!0},_:{value:s}})}function l(e){return!e.ctrlKey&&!e.button}function s(){return this.parentNode}function d(e,t){return null==t?{x:e.x,y:e.y}:t}function f(){return navigator.maxTouchPoints||"ontouchstart"in this}c.prototype.on=function(){var e=this._.on.apply(this._,arguments);return e===this._?this:e},e.drag=function(){var e,g,h,v,m=l,p=s,b=d,y=f,x={},_=t.dispatch("start","drag","end"),w=0,j=0;function E(e){e.on("mousedown.drag",T).filter(y).on("touchstart.drag",P).on("touchmove.drag",q).on("touchend.drag touchcancel.drag",z).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function T(t,r){if(!v&&m.call(this,t,r)){var a=D(this,p.call(this,t,r),t,r,"mouse");a&&(n.select(t.view).on("mousemove.drag",k,!0).on("mouseup.drag",M,!0),i(t.view),o(t),h=!1,e=t.clientX,g=t.clientY,a("start",t))}}function k(t){if(r(t),!h){var n=t.clientX-e,o=t.clientY-g;h=n*n+o*o>j}x.mouse("drag",t)}function M(e){n.select(e.view).on("mousemove.drag mouseup.drag",null),a(e.view,h),r(e),x.mouse("end",e)}function P(e,t){if(m.call(this,e,t)){var n,r,i=e.changedTouches,a=p.call(this,e,t),u=i.length;for(n=0;n () => x;
diff --git a/node_modules/d3-drag/src/drag.js b/node_modules/d3-drag/src/drag.js
new file mode 100644
index 00000000..3b84e0f2
--- /dev/null
+++ b/node_modules/d3-drag/src/drag.js
@@ -0,0 +1,192 @@
+import {dispatch} from "d3-dispatch";
+import {select, pointer} from "d3-selection";
+import nodrag, {yesdrag} from "./nodrag.js";
+import noevent, {nopropagation} from "./noevent.js";
+import constant from "./constant.js";
+import DragEvent from "./event.js";
+
+// Ignore right-click, since that should open the context menu.
+function defaultFilter(event) {
+ return !event.ctrlKey && !event.button;
+}
+
+function defaultContainer() {
+ return this.parentNode;
+}
+
+function defaultSubject(event, d) {
+ return d == null ? {x: event.x, y: event.y} : d;
+}
+
+function defaultTouchable() {
+ return navigator.maxTouchPoints || ("ontouchstart" in this);
+}
+
+export default function() {
+ var filter = defaultFilter,
+ container = defaultContainer,
+ subject = defaultSubject,
+ touchable = defaultTouchable,
+ gestures = {},
+ listeners = dispatch("start", "drag", "end"),
+ active = 0,
+ mousedownx,
+ mousedowny,
+ mousemoving,
+ touchending,
+ clickDistance2 = 0;
+
+ function drag(selection) {
+ selection
+ .on("mousedown.drag", mousedowned)
+ .filter(touchable)
+ .on("touchstart.drag", touchstarted)
+ .on("touchmove.drag", touchmoved)
+ .on("touchend.drag touchcancel.drag", touchended)
+ .style("touch-action", "none")
+ .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
+ }
+
+ function mousedowned(event, d) {
+ if (touchending || !filter.call(this, event, d)) return;
+ var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
+ if (!gesture) return;
+ select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
+ nodrag(event.view);
+ nopropagation(event);
+ mousemoving = false;
+ mousedownx = event.clientX;
+ mousedowny = event.clientY;
+ gesture("start", event);
+ }
+
+ function mousemoved(event) {
+ noevent(event);
+ if (!mousemoving) {
+ var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny;
+ mousemoving = dx * dx + dy * dy > clickDistance2;
+ }
+ gestures.mouse("drag", event);
+ }
+
+ function mouseupped(event) {
+ select(event.view).on("mousemove.drag mouseup.drag", null);
+ yesdrag(event.view, mousemoving);
+ noevent(event);
+ gestures.mouse("end", event);
+ }
+
+ function touchstarted(event, d) {
+ if (!filter.call(this, event, d)) return;
+ var touches = event.changedTouches,
+ c = container.call(this, event, d),
+ n = touches.length, i, gesture;
+
+ for (i = 0; i < n; ++i) {
+ if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {
+ nopropagation(event);
+ gesture("start", event, touches[i]);
+ }
+ }
+ }
+
+ function touchmoved(event) {
+ var touches = event.changedTouches,
+ n = touches.length, i, gesture;
+
+ for (i = 0; i < n; ++i) {
+ if (gesture = gestures[touches[i].identifier]) {
+ noevent(event);
+ gesture("drag", event, touches[i]);
+ }
+ }
+ }
+
+ function touchended(event) {
+ var touches = event.changedTouches,
+ n = touches.length, i, gesture;
+
+ if (touchending) clearTimeout(touchending);
+ touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
+ for (i = 0; i < n; ++i) {
+ if (gesture = gestures[touches[i].identifier]) {
+ nopropagation(event);
+ gesture("end", event, touches[i]);
+ }
+ }
+ }
+
+ function beforestart(that, container, event, d, identifier, touch) {
+ var dispatch = listeners.copy(),
+ p = pointer(touch || event, container), dx, dy,
+ s;
+
+ if ((s = subject.call(that, new DragEvent("beforestart", {
+ sourceEvent: event,
+ target: drag,
+ identifier,
+ active,
+ x: p[0],
+ y: p[1],
+ dx: 0,
+ dy: 0,
+ dispatch
+ }), d)) == null) return;
+
+ dx = s.x - p[0] || 0;
+ dy = s.y - p[1] || 0;
+
+ return function gesture(type, event, touch) {
+ var p0 = p, n;
+ switch (type) {
+ case "start": gestures[identifier] = gesture, n = active++; break;
+ case "end": delete gestures[identifier], --active; // nobreak
+ case "drag": p = pointer(touch || event, container), n = active; break;
+ }
+ dispatch.call(
+ type,
+ that,
+ new DragEvent(type, {
+ sourceEvent: event,
+ subject: s,
+ target: drag,
+ identifier,
+ active: n,
+ x: p[0] + dx,
+ y: p[1] + dy,
+ dx: p[0] - p0[0],
+ dy: p[1] - p0[1],
+ dispatch
+ }),
+ d
+ );
+ };
+ }
+
+ drag.filter = function(_) {
+ return arguments.length ? (filter = typeof _ === "function" ? _ : constant(!!_), drag) : filter;
+ };
+
+ drag.container = function(_) {
+ return arguments.length ? (container = typeof _ === "function" ? _ : constant(_), drag) : container;
+ };
+
+ drag.subject = function(_) {
+ return arguments.length ? (subject = typeof _ === "function" ? _ : constant(_), drag) : subject;
+ };
+
+ drag.touchable = function(_) {
+ return arguments.length ? (touchable = typeof _ === "function" ? _ : constant(!!_), drag) : touchable;
+ };
+
+ drag.on = function() {
+ var value = listeners.on.apply(listeners, arguments);
+ return value === listeners ? drag : value;
+ };
+
+ drag.clickDistance = function(_) {
+ return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
+ };
+
+ return drag;
+}
diff --git a/node_modules/d3-drag/src/event.js b/node_modules/d3-drag/src/event.js
new file mode 100644
index 00000000..5f246fea
--- /dev/null
+++ b/node_modules/d3-drag/src/event.js
@@ -0,0 +1,28 @@
+export default function DragEvent(type, {
+ sourceEvent,
+ subject,
+ target,
+ identifier,
+ active,
+ x, y, dx, dy,
+ dispatch
+}) {
+ Object.defineProperties(this, {
+ type: {value: type, enumerable: true, configurable: true},
+ sourceEvent: {value: sourceEvent, enumerable: true, configurable: true},
+ subject: {value: subject, enumerable: true, configurable: true},
+ target: {value: target, enumerable: true, configurable: true},
+ identifier: {value: identifier, enumerable: true, configurable: true},
+ active: {value: active, enumerable: true, configurable: true},
+ x: {value: x, enumerable: true, configurable: true},
+ y: {value: y, enumerable: true, configurable: true},
+ dx: {value: dx, enumerable: true, configurable: true},
+ dy: {value: dy, enumerable: true, configurable: true},
+ _: {value: dispatch}
+ });
+}
+
+DragEvent.prototype.on = function() {
+ var value = this._.on.apply(this._, arguments);
+ return value === this._ ? this : value;
+};
diff --git a/node_modules/d3-drag/src/index.js b/node_modules/d3-drag/src/index.js
new file mode 100644
index 00000000..d2dd6019
--- /dev/null
+++ b/node_modules/d3-drag/src/index.js
@@ -0,0 +1,2 @@
+export {default as drag} from "./drag.js";
+export {default as dragDisable, yesdrag as dragEnable} from "./nodrag.js";
diff --git a/node_modules/d3-drag/src/nodrag.js b/node_modules/d3-drag/src/nodrag.js
new file mode 100644
index 00000000..eab81d3b
--- /dev/null
+++ b/node_modules/d3-drag/src/nodrag.js
@@ -0,0 +1,28 @@
+import {select} from "d3-selection";
+import noevent from "./noevent.js";
+
+export default function(view) {
+ var root = view.document.documentElement,
+ selection = select(view).on("dragstart.drag", noevent, true);
+ if ("onselectstart" in root) {
+ selection.on("selectstart.drag", noevent, true);
+ } else {
+ root.__noselect = root.style.MozUserSelect;
+ root.style.MozUserSelect = "none";
+ }
+}
+
+export function yesdrag(view, noclick) {
+ var root = view.document.documentElement,
+ selection = select(view).on("dragstart.drag", null);
+ if (noclick) {
+ selection.on("click.drag", noevent, true);
+ setTimeout(function() { selection.on("click.drag", null); }, 0);
+ }
+ if ("onselectstart" in root) {
+ selection.on("selectstart.drag", null);
+ } else {
+ root.style.MozUserSelect = root.__noselect;
+ delete root.__noselect;
+ }
+}
diff --git a/node_modules/d3-drag/src/noevent.js b/node_modules/d3-drag/src/noevent.js
new file mode 100644
index 00000000..b32552dc
--- /dev/null
+++ b/node_modules/d3-drag/src/noevent.js
@@ -0,0 +1,8 @@
+export function nopropagation(event) {
+ event.stopImmediatePropagation();
+}
+
+export default function(event) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+}
diff --git a/node_modules/d3-dsv/LICENSE b/node_modules/d3-dsv/LICENSE
new file mode 100644
index 00000000..3d0802c3
--- /dev/null
+++ b/node_modules/d3-dsv/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2013-2016 Mike Bostock
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the author nor the names of contributors may be used to
+ endorse or promote products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node_modules/d3-dsv/README.md b/node_modules/d3-dsv/README.md
new file mode 100644
index 00000000..c348489f
--- /dev/null
+++ b/node_modules/d3-dsv/README.md
@@ -0,0 +1,482 @@
+# d3-dsv
+
+This module provides a parser and formatter for delimiter-separated values, most commonly [comma-](https://en.wikipedia.org/wiki/Comma-separated_values) (CSV) or tab-separated values (TSV). These tabular formats are popular with spreadsheet programs such as Microsoft Excel, and are often more space-efficient than JSON. This implementation is based on [RFC 4180](http://tools.ietf.org/html/rfc4180).
+
+Comma (CSV) and tab (TSV) delimiters are built-in. For example, to parse:
+
+```js
+d3.csvParse("foo,bar\n1,2"); // [{foo: "1", bar: "2"}, columns: ["foo", "bar"]]
+d3.tsvParse("foo\tbar\n1\t2"); // [{foo: "1", bar: "2"}, columns: ["foo", "bar"]]
+```
+
+Or to format:
+
+```js
+d3.csvFormat([{foo: "1", bar: "2"}]); // "foo,bar\n1,2"
+d3.tsvFormat([{foo: "1", bar: "2"}]); // "foo\tbar\n1\t2"
+```
+
+To use a different delimiter, such as “|†for pipe-separated values, use [d3.dsvFormat](#dsvFormat):
+
+```js
+var psv = d3.dsvFormat("|");
+
+console.log(psv.parse("foo|bar\n1|2")); // [{foo: "1", bar: "2"}, columns: ["foo", "bar"]]
+```
+
+For easy loading of DSV files in a browser, see [d3-fetch](https://github.com/d3/d3-fetch)’s [d3.csv](https://github.com/d3/d3-fetch/blob/master/README.md#csv) and [d3.tsv](https://github.com/d3/d3-fetch/blob/master/README.md#tsv) methods.
+
+## Installing
+
+If you use NPM, `npm install d3-dsv`. Otherwise, download the [latest release](https://github.com/d3/d3-dsv/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-dsv.v1.min.js) or as part of [D3](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:
+
+```html
+
+
+```
+
+[Try d3-dsv in your browser.](https://tonicdev.com/npm/d3-dsv)
+
+## API Reference
+
+# d3.csvParse(string[, row]) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)(",").[parse](#dsv_parse). Note: requires unsafe-eval [content security policy](#content-security-policy).
+
+# d3.csvParseRows(string[, row]) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)(",").[parseRows](#dsv_parseRows).
+
+# d3.csvFormat(rows[, columns]) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)(",").[format](#dsv_format).
+
+# d3.csvFormatBody(rows[, columns]) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)(",").[formatBody](#dsv_formatBody).
+
+# d3.csvFormatRows(rows) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)(",").[formatRows](#dsv_formatRows).
+
+# d3.csvFormatRow(row) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)(",").[formatRow](#dsv_formatRow).
+
+# d3.csvFormatValue(value) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)(",").[formatValue](#dsv_formatValue).
+
+# d3.tsvParse(string[, row]) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)("\t").[parse](#dsv_parse). Note: requires unsafe-eval [content security policy](#content-security-policy).
+
+# d3.tsvParseRows(string[, row]) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)("\t").[parseRows](#dsv_parseRows).
+
+# d3.tsvFormat(rows[, columns]) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)("\t").[format](#dsv_format).
+
+# d3.tsvFormatBody(rows[, columns]) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)("\t").[formatBody](#dsv_formatBody).
+
+# d3.tsvFormatRows(rows) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)("\t").[formatRows](#dsv_formatRows).
+
+# d3.tsvFormatRow(row) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)("\t").[formatRow](#dsv_formatRow).
+
+# d3.tsvFormatValue(value) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js "Source")
+
+Equivalent to [dsvFormat](#dsvFormat)("\t").[formatValue](#dsv_formatValue).
+
+# d3.dsvFormat(delimiter) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js)
+
+Constructs a new DSV parser and formatter for the specified *delimiter*. The *delimiter* must be a single character (*i.e.*, a single 16-bit code unit); so, ASCII delimiters are fine, but emoji delimiters are not.
+
+# *dsv*.parse(string[, row]) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js "Source")
+
+Parses the specified *string*, which must be in the delimiter-separated values format with the appropriate delimiter, returning an array of objects representing the parsed rows.
+
+Unlike [*dsv*.parseRows](#dsv_parseRows), this method requires that the first line of the DSV content contains a delimiter-separated list of column names; these column names become the attributes on the returned objects. For example, consider the following CSV file:
+
+```
+Year,Make,Model,Length
+1997,Ford,E350,2.34
+2000,Mercury,Cougar,2.38
+```
+
+The resulting JavaScript array is:
+
+```js
+[
+ {"Year": "1997", "Make": "Ford", "Model": "E350", "Length": "2.34"},
+ {"Year": "2000", "Make": "Mercury", "Model": "Cougar", "Length": "2.38"}
+]
+```
+
+The returned array also exposes a `columns` property containing the column names in input order (in contrast to Object.keys, whose iteration order is arbitrary). For example:
+
+```js
+data.columns; // ["Year", "Make", "Model", "Length"]
+```
+
+If the column names are not unique, only the last value is returned for each name; to access all values, use [*dsv*.parseRows](#dsv_parseRows) instead (see [example](https://observablehq.com/@d3/parse-csv-with-duplicate-column-names)).
+
+If a *row* conversion function is not specified, field values are strings. For safety, there is no automatic conversion to numbers, dates, or other types. In some cases, JavaScript may coerce strings to numbers for you automatically (for example, using the `+` operator), but better is to specify a *row* conversion function. See [d3.autoType](#autoType) for a convenient *row* conversion function that infers and coerces common types like numbers and strings.
+
+If a *row* conversion function is specified, the specified function is invoked for each row, being passed an object representing the current row (`d`), the index (`i`) starting at zero for the first non-header row, and the array of column names. If the returned value is null or undefined, the row is skipped and will be omitted from the array returned by *dsv*.parse; otherwise, the returned value defines the corresponding row object. For example:
+
+```js
+var data = d3.csvParse(string, function(d) {
+ return {
+ year: new Date(+d.Year, 0, 1), // lowercase and convert "Year" to Date
+ make: d.Make, // lowercase
+ model: d.Model, // lowercase
+ length: +d.Length // lowercase and convert "Length" to number
+ };
+});
+```
+
+Note: using `+` rather than [parseInt](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseInt) or [parseFloat](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseFloat) is typically faster, though more restrictive. For example, `"30px"` when coerced using `+` returns `NaN`, while parseInt and parseFloat return `30`.
+
+Note: requires unsafe-eval [content security policy](#content-security-policy).
+
+# dsv.parseRows(string[, row]) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js "Source")
+
+Parses the specified *string*, which must be in the delimiter-separated values format with the appropriate delimiter, returning an array of arrays representing the parsed rows.
+
+Unlike [*dsv*.parse](#dsv_parse), this method treats the header line as a standard row, and should be used whenever DSV content does not contain a header. Each row is represented as an array rather than an object. Rows may have variable length. For example, consider the following CSV file, which notably lacks a header line:
+
+```
+1997,Ford,E350,2.34
+2000,Mercury,Cougar,2.38
+```
+
+The resulting JavaScript array is:
+
+```js
+[
+ ["1997", "Ford", "E350", "2.34"],
+ ["2000", "Mercury", "Cougar", "2.38"]
+]
+```
+
+If a *row* conversion function is not specified, field values are strings. For safety, there is no automatic conversion to numbers, dates, or other types. In some cases, JavaScript may coerce strings to numbers for you automatically (for example, using the `+` operator), but better is to specify a *row* conversion function. See [d3.autoType](#autoType) for a convenient *row* conversion function that infers and coerces common types like numbers and strings.
+
+If a *row* conversion function is specified, the specified function is invoked for each row, being passed an array representing the current row (`d`), the index (`i`) starting at zero for the first row, and the array of column names. If the returned value is null or undefined, the row is skipped and will be omitted from the array returned by *dsv*.parse; otherwise, the returned value defines the corresponding row object. For example:
+
+```js
+var data = d3.csvParseRows(string, function(d, i) {
+ return {
+ year: new Date(+d[0], 0, 1), // convert first colum column to Date
+ make: d[1],
+ model: d[2],
+ length: +d[3] // convert fourth column to number
+ };
+});
+```
+
+In effect, *row* is similar to applying a [map](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/map) and [filter](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter) operator to the returned rows.
+
+# dsv.format(rows[, columns]) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js "Source")
+
+Formats the specified array of object *rows* as delimiter-separated values, returning a string. This operation is the inverse of [*dsv*.parse](#dsv_parse). Each row will be separated by a newline (`\n`), and each column within each row will be separated by the delimiter (such as a comma, `,`). Values that contain either the delimiter, a double-quote (`"`) or a newline will be escaped using double-quotes.
+
+If *columns* is not specified, the list of column names that forms the header row is determined by the union of all properties on all objects in *rows*; the order of columns is nondeterministic. If *columns* is specified, it is an array of strings representing the column names. For example:
+
+```js
+var string = d3.csvFormat(data, ["year", "make", "model", "length"]);
+```
+
+All fields on each row object will be coerced to strings. If the field value is null or undefined, the empty string is used. If the field value is a Date, the [ECMAScript date-time string format](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-date-time-string-format) (a subset of ISO 8601) is used: for example, dates at UTC midnight are formatted as `YYYY-MM-DD`. For more control over which and how fields are formatted, first map *rows* to an array of array of string, and then use [*dsv*.formatRows](#dsv_formatRows).
+
+# dsv.formatBody(rows[, columns]) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js "Source")
+
+Equivalent to [*dsv*.format](#dsv_format), but omits the header row. This is useful, for example, when appending rows to an existing file.
+
+# dsv.formatRows(rows) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js "Source")
+
+Formats the specified array of array of string *rows* as delimiter-separated values, returning a string. This operation is the reverse of [*dsv*.parseRows](#dsv_parseRows). Each row will be separated by a newline (`\n`), and each column within each row will be separated by the delimiter (such as a comma, `,`). Values that contain either the delimiter, a double-quote (") or a newline will be escaped using double-quotes.
+
+To convert an array of objects to an array of arrays while explicitly specifying the columns, use [*array*.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). For example:
+
+```js
+var string = d3.csvFormatRows(data.map(function(d, i) {
+ return [
+ d.year.getFullYear(), // Assuming d.year is a Date object.
+ d.make,
+ d.model,
+ d.length
+ ];
+}));
+```
+
+If you like, you can also [*array*.concat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) this result with an array of column names to generate the first row:
+
+```js
+var string = d3.csvFormatRows([[
+ "year",
+ "make",
+ "model",
+ "length"
+ ]].concat(data.map(function(d, i) {
+ return [
+ d.year.getFullYear(), // Assuming d.year is a Date object.
+ d.make,
+ d.model,
+ d.length
+ ];
+})));
+```
+
+# dsv.formatRow(row) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js "Source")
+
+Formats a single array *row* of strings as delimiter-separated values, returning a string. Each column within the row will be separated by the delimiter (such as a comma, `,`). Values that contain either the delimiter, a double-quote (") or a newline will be escaped using double-quotes.
+
+# dsv.formatValue(value) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js "Source")
+
+Format a single *value* or string as a delimiter-separated value, returning a string. A value that contains either the delimiter, a double-quote (") or a newline will be escaped using double-quotes.
+
+# d3.autoType(object) [<>](https://github.com/d3/d3-dsv/blob/master/src/autoType.js "Source")
+
+Given an *object* (or array) representing a parsed row, infers the types of values on the *object* and coerces them accordingly, returning the mutated *object*. This function is intended to be used as a *row* accessor function in conjunction with [*dsv*.parse](#dsv_parse) and [*dsv*.parseRows](#dsv_parseRow). For example, consider the following CSV file:
+
+```
+Year,Make,Model,Length
+1997,Ford,E350,2.34
+2000,Mercury,Cougar,2.38
+```
+
+When used with [d3.csvParse](#csvParse),
+
+```js
+d3.csvParse(string, d3.autoType)
+```
+
+the resulting JavaScript array is:
+
+```js
+[
+ {"Year": 1997, "Make": "Ford", "Model": "E350", "Length": 2.34},
+ {"Year": 2000, "Make": "Mercury", "Model": "Cougar", "Length": 2.38}
+]
+```
+
+Type inference works as follows. For each *value* in the given *object*, the [trimmed](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) value is computed; the value is then re-assigned as follows:
+
+1. If empty, then `null`.
+1. If exactly `"true"`, then `true`.
+1. If exactly `"false"`, then `false`.
+1. If exactly `"NaN"`, then `NaN`.
+1. Otherwise, if [coercible to a number](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-tonumber-applied-to-the-string-type), then a number.
+1. Otherwise, if a [date-only or date-time string](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-date-time-string-format), then a Date.
+1. Otherwise, a string (the original untrimmed value).
+
+Values with leading zeroes may be coerced to numbers; for example `"08904"` coerces to `8904`. However, extra characters such as commas or units (*e.g.*, `"$1.00"`, `"(123)"`, `"1,234"` or `"32px"`) will prevent number coercion, resulting in a string.
+
+Date strings must be in ECMAScript’s subset of the [ISO 8601 format](https://en.wikipedia.org/wiki/ISO_8601). When a date-only string such as YYYY-MM-DD is specified, the inferred time is midnight UTC; however, if a date-time string such as YYYY-MM-DDTHH:MM is specified without a time zone, it is assumed to be local time.
+
+Automatic type inference is primarily intended to provide safe, predictable behavior in conjunction with [*dsv*.format](#dsv_format) and [*dsv*.formatRows](#dsv_formatRows) for common JavaScript types. If you need different behavior, you should implement your own row accessor function.
+
+For more, see [the d3.autoType notebook](https://observablehq.com/@d3/d3-autotype).
+
+### Content Security Policy
+
+If a [content security policy](http://www.w3.org/TR/CSP/) is in place, note that [*dsv*.parse](#dsv_parse) requires `unsafe-eval` in the `script-src` directive, due to the (safe) use of dynamic code generation for fast parsing. (See [source](https://github.com/d3/d3-dsv/blob/master/src/dsv.js).) Alternatively, use [*dsv*.parseRows](#dsv_parseRows).
+
+### Byte-Order Marks
+
+DSV files sometimes begin with a [byte order mark (BOM)](https://en.wikipedia.org/wiki/Byte_order_mark); saving a spreadsheet in CSV UTF-8 format from Microsoft Excel, for example, will include a BOM. On the web this is not usually a problem because the [UTF-8 decode algorithm](https://encoding.spec.whatwg.org/#utf-8-decode) specified in the Encoding standard removes the BOM. Node.js, on the other hand, [does not remove the BOM](https://github.com/nodejs/node-v0.x-archive/issues/1918) when decoding UTF-8.
+
+If the BOM is not removed, the first character of the text is a zero-width non-breaking space. So if a CSV file with a BOM is parsed by [d3.csvParse](#csvParse), the first column’s name will begin with a zero-width non-breaking space. This can be hard to spot since this character is usually invisible when printed.
+
+To remove the BOM before parsing, consider using [strip-bom](https://www.npmjs.com/package/strip-bom).
+
+## Command Line Reference
+
+### dsv2dsv
+
+# dsv2dsv [options…] [file]
+
+Converts the specified DSV input *file* to DSV (typically with a different delimiter or encoding). If *file* is not specified, defaults to reading from stdin. For example, to convert to CSV to TSV:
+
+```
+csv2tsv < example.csv > example.tsv
+```
+
+To convert windows-1252 CSV to utf-8 CSV:
+
+```
+dsv2dsv --input-encoding windows-1252 < latin1.csv > utf8.csv
+```
+
+# dsv2dsv -h
+
# dsv2dsv --help
+
+Output usage information.
+
+# dsv2dsv -V
+
# dsv2dsv --version
+
+Output the version number.
+
+# dsv2dsv -o file
+
# dsv2dsv --out file
+
+Specify the output file name. Defaults to “-†for stdout.
+
+# dsv2dsv -r delimiter
+
# dsv2dsv --input-delimiter delimiter
+
+Specify the input delimiter character. Defaults to “,†for reading CSV. (You can enter a tab on the command line by typing ⌃V.)
+
+# dsv2dsv --input-encoding encoding
+
+Specify the input character encoding. Defaults to “utf8â€.
+
+# dsv2dsv -w delimiter
+
# dsv2dsv --output-delimiter delimiter
+
+Specify the output delimiter character. Defaults to “,†for writing CSV. (You can enter a tab on the command line by typing ⌃V.)
+
+# dsv2dsv --output-encoding encoding
+
+Specify the output character encoding. Defaults to “utf8â€.
+
+# csv2tsv [options…] [file]
+
+Equivalent to [dsv2dsv](#dsv2dsv), but the [output delimiter](#dsv2dsv_output_delimiter) defaults to the tab character (\t).
+
+# tsv2csv [options…] [file]
+
+Equivalent to [dsv2dsv](#dsv2dsv), but the [input delimiter](#dsv2dsv_output_delimiter) defaults to the tab character (\t).
+
+### dsv2json
+
+# dsv2json [options…] [file]
+
+Converts the specified DSV input *file* to JSON. If *file* is not specified, defaults to reading from stdin. For example, to convert to CSV to JSON:
+
+```
+csv2json < example.csv > example.json
+```
+
+Or to convert CSV to a newline-delimited JSON stream:
+
+```
+csv2json -n < example.csv > example.ndjson
+```
+
+# dsv2json -h
+
# dsv2json --help
+
+Output usage information.
+
+# dsv2json -V
+
# dsv2json --version
+
+Output the version number.
+
+# dsv2json -o file
+
# dsv2json --out file
+
+Specify the output file name. Defaults to “-†for stdout.
+
+# dsv2json -a
+
# dsv2json --auto-type
+
+Use type inference when parsing rows. See d3.autoType for how it works.
+
+# dsv2json -r delimiter
+
# dsv2json --input-delimiter delimiter
+
+Specify the input delimiter character. Defaults to “,†for reading CSV. (You can enter a tab on the command line by typing ⌃V.)
+
+# dsv2json --input-encoding encoding
+
+Specify the input character encoding. Defaults to “utf8â€.
+
+# dsv2json -r encoding
+
# dsv2json --output-encoding encoding
+
+Specify the output character encoding. Defaults to “utf8â€.
+
+# dsv2json -n
+
# dsv2json --newline-delimited
+
+Output [newline-delimited JSON](https://github.com/mbostock/ndjson-cli) instead of a single JSON array.
+
+# csv2json [options…] [file]
+
+Equivalent to [dsv2json](#dsv2json).
+
+# tsv2json [options…] [file]
+
+Equivalent to [dsv2json](#dsv2json), but the [input delimiter](#dsv2json_input_delimiter) defaults to the tab character (\t).
+
+### json2dsv
+
+# json2dsv [options…] [file]
+
+Converts the specified JSON input *file* to DSV. If *file* is not specified, defaults to reading from stdin. For example, to convert to JSON to CSV:
+
+```
+json2csv < example.json > example.csv
+```
+
+Or to convert a newline-delimited JSON stream to CSV:
+
+```
+json2csv -n < example.ndjson > example.csv
+```
+
+# json2dsv -h
+
# json2dsv --help
+
+Output usage information.
+
+# json2dsv -V
+
# json2dsv --version
+
+Output the version number.
+
+# json2dsv -o file
+
# json2dsv --out file
+
+Specify the output file name. Defaults to “-†for stdout.
+
+# json2dsv --input-encoding encoding
+
+Specify the input character encoding. Defaults to “utf8â€.
+
+# json2dsv -w delimiter
+
# json2dsv --output-delimiter delimiter
+
+Specify the output delimiter character. Defaults to “,†for writing CSV. (You can enter a tab on the command line by typing ⌃V.)
+
+# json2dsv --output-encoding encoding
+
+Specify the output character encoding. Defaults to “utf8â€.
+
+# json2dsv -n
+
# json2dsv --newline-delimited
+
+Read [newline-delimited JSON](https://github.com/mbostock/ndjson-cli) instead of a single JSON array.
+
+# json2csv [options…] [file]
+
+Equivalent to [json2dsv](#json2dsv).
+
+# json2tsv [options…] [file]
+
+Equivalent to [json2dsv](#json2dsv), but the [output delimiter](#json2dsv_output_delimiter) defaults to the tab character (\t).
diff --git a/node_modules/d3-dsv/bin/dsv2dsv b/node_modules/d3-dsv/bin/dsv2dsv
new file mode 100644
index 00000000..63ca9caf
--- /dev/null
+++ b/node_modules/d3-dsv/bin/dsv2dsv
@@ -0,0 +1,32 @@
+#!/usr/bin/env node
+
+var os = require("os"),
+ rw = require("rw").dash,
+ path = require("path"),
+ iconv = require("iconv-lite"),
+ commander = require("commander"),
+ dsv = require("../");
+
+var program = path.basename(process.argv[1]),
+ defaultInDelimiter = program.slice(0, 3) === "tsv" ? "\t" : ",",
+ defaultOutDelimiter = program.slice(-3) === "tsv" ? "\t" : ",";
+
+commander
+ .version(require("../package.json").version)
+ .usage("[options] [file]")
+ .option("-o, --out =s?m=!0:(f=t.charCodeAt(l++))===o?v=!0:f===a&&(v=!0,t.charCodeAt(l)===o&&++l),t.slice(i+1,u-1).replace(/""/g,'"')}for(;l 9999 ? "+" + pad(year, 6)
+ : pad(year, 4);
+}
+
+function formatDate(date) {
+ var hours = date.getUTCHours(),
+ minutes = date.getUTCMinutes(),
+ seconds = date.getUTCSeconds(),
+ milliseconds = date.getUTCMilliseconds();
+ return isNaN(date) ? "Invalid Date"
+ : formatYear(date.getUTCFullYear(), 4) + "-" + pad(date.getUTCMonth() + 1, 2) + "-" + pad(date.getUTCDate(), 2)
+ + (milliseconds ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2) + "." + pad(milliseconds, 3) + "Z"
+ : seconds ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2) + "Z"
+ : minutes || hours ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + "Z"
+ : "");
+}
+
+export default function(delimiter) {
+ var reFormat = new RegExp("[\"" + delimiter + "\n\r]"),
+ DELIMITER = delimiter.charCodeAt(0);
+
+ function parse(text, f) {
+ var convert, columns, rows = parseRows(text, function(row, i) {
+ if (convert) return convert(row, i - 1);
+ columns = row, convert = f ? customConverter(row, f) : objectConverter(row);
+ });
+ rows.columns = columns || [];
+ return rows;
+ }
+
+ function parseRows(text, f) {
+ var rows = [], // output rows
+ N = text.length,
+ I = 0, // current character index
+ n = 0, // current line number
+ t, // current token
+ eof = N <= 0, // current token followed by EOF?
+ eol = false; // current token followed by EOL?
+
+ // Strip the trailing newline.
+ if (text.charCodeAt(N - 1) === NEWLINE) --N;
+ if (text.charCodeAt(N - 1) === RETURN) --N;
+
+ function token() {
+ if (eof) return EOF;
+ if (eol) return eol = false, EOL;
+
+ // Unescape quotes.
+ var i, j = I, c;
+ if (text.charCodeAt(j) === QUOTE) {
+ while (I++ < N && text.charCodeAt(I) !== QUOTE || text.charCodeAt(++I) === QUOTE);
+ if ((i = I) >= N) eof = true;
+ else if ((c = text.charCodeAt(I++)) === NEWLINE) eol = true;
+ else if (c === RETURN) { eol = true; if (text.charCodeAt(I) === NEWLINE) ++I; }
+ return text.slice(j + 1, i - 1).replace(/""/g, "\"");
+ }
+
+ // Find next delimiter or newline.
+ while (I < N) {
+ if ((c = text.charCodeAt(i = I++)) === NEWLINE) eol = true;
+ else if (c === RETURN) { eol = true; if (text.charCodeAt(I) === NEWLINE) ++I; }
+ else if (c !== DELIMITER) continue;
+ return text.slice(j, i);
+ }
+
+ // Return last token before EOF.
+ return eof = true, text.slice(j, N);
+ }
+
+ while ((t = token()) !== EOF) {
+ var row = [];
+ while (t !== EOL && t !== EOF) row.push(t), t = token();
+ if (f && (row = f(row, n++)) == null) continue;
+ rows.push(row);
+ }
+
+ return rows;
+ }
+
+ function preformatBody(rows, columns) {
+ return rows.map(function(row) {
+ return columns.map(function(column) {
+ return formatValue(row[column]);
+ }).join(delimiter);
+ });
+ }
+
+ function format(rows, columns) {
+ if (columns == null) columns = inferColumns(rows);
+ return [columns.map(formatValue).join(delimiter)].concat(preformatBody(rows, columns)).join("\n");
+ }
+
+ function formatBody(rows, columns) {
+ if (columns == null) columns = inferColumns(rows);
+ return preformatBody(rows, columns).join("\n");
+ }
+
+ function formatRows(rows) {
+ return rows.map(formatRow).join("\n");
+ }
+
+ function formatRow(row) {
+ return row.map(formatValue).join(delimiter);
+ }
+
+ function formatValue(value) {
+ return value == null ? ""
+ : value instanceof Date ? formatDate(value)
+ : reFormat.test(value += "") ? "\"" + value.replace(/"/g, "\"\"") + "\""
+ : value;
+ }
+
+ return {
+ parse: parse,
+ parseRows: parseRows,
+ format: format,
+ formatBody: formatBody,
+ formatRows: formatRows,
+ formatRow: formatRow,
+ formatValue: formatValue
+ };
+}
diff --git a/node_modules/d3-dsv/src/index.js b/node_modules/d3-dsv/src/index.js
new file mode 100644
index 00000000..0a63fff2
--- /dev/null
+++ b/node_modules/d3-dsv/src/index.js
@@ -0,0 +1,4 @@
+export {default as dsvFormat} from "./dsv.js";
+export {csvParse, csvParseRows, csvFormat, csvFormatBody, csvFormatRows, csvFormatRow, csvFormatValue} from "./csv.js";
+export {tsvParse, tsvParseRows, tsvFormat, tsvFormatBody, tsvFormatRows, tsvFormatRow, tsvFormatValue} from "./tsv.js";
+export {default as autoType} from "./autoType.js";
diff --git a/node_modules/d3-dsv/src/tsv.js b/node_modules/d3-dsv/src/tsv.js
new file mode 100644
index 00000000..38b16c21
--- /dev/null
+++ b/node_modules/d3-dsv/src/tsv.js
@@ -0,0 +1,11 @@
+import dsv from "./dsv.js";
+
+var tsv = dsv("\t");
+
+export var tsvParse = tsv.parse;
+export var tsvParseRows = tsv.parseRows;
+export var tsvFormat = tsv.format;
+export var tsvFormatBody = tsv.formatBody;
+export var tsvFormatRows = tsv.formatRows;
+export var tsvFormatRow = tsv.formatRow;
+export var tsvFormatValue = tsv.formatValue;
diff --git a/node_modules/d3-ease/LICENSE b/node_modules/d3-ease/LICENSE
new file mode 100644
index 00000000..6c05ba05
--- /dev/null
+++ b/node_modules/d3-ease/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2010-2016 Mike Bostock
+Copyright 2001 Robert Penner
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the author nor the names of contributors may be used to
+ endorse or promote products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node_modules/d3-ease/README.md b/node_modules/d3-ease/README.md
new file mode 100644
index 00000000..f2c86a8f
--- /dev/null
+++ b/node_modules/d3-ease/README.md
@@ -0,0 +1,241 @@
+# d3-ease
+
+*Easing* is a method of distorting time to control apparent motion in animation. It is most commonly used for [slow-in, slow-out](https://en.wikipedia.org/wiki/12_basic_principles_of_animation#Slow_In_and_Slow_Out). By easing time, [animated transitions](https://github.com/d3/d3-transition) are smoother and exhibit more plausible motion.
+
+The easing types in this module implement the [ease method](#ease_ease), which takes a normalized time *t* and returns the corresponding “eased†time *tʹ*. Both the normalized time and the eased time are typically in the range [0,1], where 0 represents the start of the animation and 1 represents the end; some easing types, such as [elastic](#easeElastic), may return eased times slightly outside this range. A good easing type should return 0 if *t* = 0 and 1 if *t* = 1. See the [easing explorer](https://observablehq.com/@d3/easing) for a visual demonstration.
+
+These easing types are largely based on work by [Robert Penner](http://robertpenner.com/easing/).
+
+## Installing
+
+If you use NPM, `npm install d3-ease`. Otherwise, download the [latest release](https://github.com/d3/d3-ease/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-ease.v1.min.js) or as part of [D3](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:
+
+```html
+
+
+```
+
+[Try d3-ease in your browser.](https://observablehq.com/@d3/easing-animations)
+
+## API Reference
+
+# ease(t)
+
+Given the specified normalized time *t*, typically in the range [0,1], returns the “eased†time *tʹ*, also typically in [0,1]. 0 represents the start of the animation and 1 represents the end. A good implementation returns 0 if *t* = 0 and 1 if *t* = 1. See the [easing explorer](https://observablehq.com/@d3/easing) for a visual demonstration. For example, to apply [cubic](#easeCubic) easing:
+
+```js
+var te = d3.easeCubic(t);
+```
+
+Similarly, to apply custom [elastic](#easeElastic) easing:
+
+```js
+// Before the animation starts, create your easing function.
+var customElastic = d3.easeElastic.period(0.4);
+
+// During the animation, apply the easing function.
+var te = customElastic(t);
+```
+
+# d3.easeLinear(t) [<>](https://github.com/d3/d3-ease/blob/master/src/linear.js "Source")
+
+Linear easing; the identity function; *linear*(*t*) returns *t*.
+
+[
](https://observablehq.com/@d3/easing#linear)
+
+# d3.easePolyIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/poly.js#L3 "Source")
+
+Polynomial easing; raises *t* to the specified [exponent](#poly_exponent). If the exponent is not specified, it defaults to 3, equivalent to [cubicIn](#easeCubicIn).
+
+[
](https://observablehq.com/@d3/easing#polyIn)
+
+# d3.easePolyOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/poly.js#L15 "Source")
+
+Reverse polynomial easing; equivalent to 1 - [polyIn](#easePolyIn)(1 - *t*). If the [exponent](#poly_exponent) is not specified, it defaults to 3, equivalent to [cubicOut](#easeCubicOut).
+
+[
](https://observablehq.com/@d3/easing#polyOut)
+
+# d3.easePoly(t) [<>](https://github.com/d3/d3-ease/blob/master/src/poly.js "Source")
+
# d3.easePolyInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/poly.js#L27 "Source")
+
+Symmetric polynomial easing; scales [polyIn](#easePolyIn) for *t* in [0, 0.5] and [polyOut](#easePolyOut) for *t* in [0.5, 1]. If the [exponent](#poly_exponent) is not specified, it defaults to 3, equivalent to [cubic](#easeCubic).
+
+[
](https://observablehq.com/@d3/easing#polyInOut)
+
+# poly.exponent(e) [<>](https://github.com/d3/d3-ease/blob/master/src/poly.js#L1 "Source")
+
+Returns a new polynomial easing with the specified exponent *e*. For example, to create equivalents of [linear](#easeLinear), [quad](#easeQuad), and [cubic](#easeCubic):
+
+```js
+var linear = d3.easePoly.exponent(1),
+ quad = d3.easePoly.exponent(2),
+ cubic = d3.easePoly.exponent(3);
+```
+
+# d3.easeQuadIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/quad.js#L1 "Source")
+
+Quadratic easing; equivalent to [polyIn](#easePolyIn).[exponent](#poly_exponent)(2).
+
+[
](https://observablehq.com/@d3/easing#quadIn)
+
+# d3.easeQuadOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/quad.js#L5 "Source")
+
+Reverse quadratic easing; equivalent to 1 - [quadIn](#easeQuadIn)(1 - *t*). Also equivalent to [polyOut](#easePolyOut).[exponent](#poly_exponent)(2).
+
+[
](https://observablehq.com/@d3/easing#quadOut)
+
+# d3.easeQuad(t) [<>](https://github.com/d3/d3-ease/blob/master/src/quad.js "Source")
+
# d3.easeQuadInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/quad.js#L9 "Source")
+
+Symmetric quadratic easing; scales [quadIn](#easeQuadIn) for *t* in [0, 0.5] and [quadOut](#easeQuadOut) for *t* in [0.5, 1]. Also equivalent to [poly](#easePoly).[exponent](#poly_exponent)(2).
+
+[
](https://observablehq.com/@d3/easing#quadInOut)
+
+# d3.easeCubicIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/cubic.js#L1 "Source")
+
+Cubic easing; equivalent to [polyIn](#easePolyIn).[exponent](#poly_exponent)(3).
+
+[
](https://observablehq.com/@d3/easing#cubicIn)
+
+# d3.easeCubicOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/cubic.js#L5 "Source")
+
+Reverse cubic easing; equivalent to 1 - [cubicIn](#easeCubicIn)(1 - *t*). Also equivalent to [polyOut](#easePolyOut).[exponent](#poly_exponent)(3).
+
+[
](https://observablehq.com/@d3/easing#cubicOut)
+
+# d3.easeCubic(t) [<>](https://github.com/d3/d3-ease/blob/master/src/cubic.js "Source")
+
# d3.easeCubicInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/cubic.js#L9 "Source")
+
+Symmetric cubic easing; scales [cubicIn](#easeCubicIn) for *t* in [0, 0.5] and [cubicOut](#easeCubicOut) for *t* in [0.5, 1]. Also equivalent to [poly](#easePoly).[exponent](#poly_exponent)(3).
+
+[
](https://observablehq.com/@d3/easing#cubicInOut)
+
+# d3.easeSinIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/sin.js#L4 "Source")
+
+Sinusoidal easing; returns sin(*t*).
+
+[
](https://observablehq.com/@d3/easing#sinIn)
+
+# d3.easeSinOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/sin.js#L8 "Source")
+
+Reverse sinusoidal easing; equivalent to 1 - [sinIn](#easeSinIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#sinOut)
+
+# d3.easeSin(t) [<>](https://github.com/d3/d3-ease/blob/master/src/sin.js "Source")
+
# d3.easeSinInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/sin.js#L12 "Source")
+
+Symmetric sinusoidal easing; scales [sinIn](#easeSinIn) for *t* in [0, 0.5] and [sinOut](#easeSinOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#sinInOut)
+
+# d3.easeExpIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/exp.js#L1 "Source")
+
+Exponential easing; raises 2 to the exponent 10 \* (*t* - 1).
+
+[
](https://observablehq.com/@d3/easing#expIn)
+
+# d3.easeExpOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/exp.js#L5 "Source")
+
+Reverse exponential easing; equivalent to 1 - [expIn](#easeExpIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#expOut)
+
+# d3.easeExp(t) [<>](https://github.com/d3/d3-ease/blob/master/src/exp.js "Source")
+
# d3.easeExpInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/exp.js#L9 "Source")
+
+Symmetric exponential easing; scales [expIn](#easeExpIn) for *t* in [0, 0.5] and [expOut](#easeExpOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#expInOut)
+
+# d3.easeCircleIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/circle.js#L1 "Source")
+
+Circular easing.
+
+[
](https://observablehq.com/@d3/easing#circleIn)
+
+# d3.easeCircleOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/circle.js#L5 "Source")
+
+Reverse circular easing; equivalent to 1 - [circleIn](#easeCircleIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#circleOut)
+
+# d3.easeCircle(t) [<>](https://github.com/d3/d3-ease/blob/master/src/circle.js "Source")
+
# d3.easeCircleInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/circle.js#L9 "Source")
+
+Symmetric circular easing; scales [circleIn](#easeCircleIn) for *t* in [0, 0.5] and [circleOut](#easeCircleOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#circleInOut)
+
+# d3.easeElasticIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js#L5 "Source")
+
+Elastic easing, like a rubber band. The [amplitude](#elastic_amplitude) and [period](#elastic_period) of the oscillation are configurable; if not specified, they default to 1 and 0.3, respectively.
+
+[
](https://observablehq.com/@d3/easing#elasticIn)
+
+# d3.easeElastic(t) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js "Source")
+
# d3.easeElasticOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js#L18 "Source")
+
+Reverse elastic easing; equivalent to 1 - [elasticIn](#easeElasticIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#elasticOut)
+
+# d3.easeElasticInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js#L31 "Source")
+
+Symmetric elastic easing; scales [elasticIn](#easeElasticIn) for *t* in [0, 0.5] and [elasticOut](#easeElasticOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#elasticInOut)
+
+# elastic.amplitude(a) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js#L40 "Source")
+
+Returns a new elastic easing with the specified amplitude *a*.
+
+# elastic.period(p) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js#L41 "Source")
+
+Returns a new elastic easing with the specified period *p*.
+
+# d3.easeBackIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/back.js#L3 "Source")
+
+[Anticipatory](https://en.wikipedia.org/wiki/12_basic_principles_of_animation#Anticipation) easing, like a dancer bending his knees before jumping off the floor. The degree of [overshoot](#back_overshoot) is configurable; if not specified, it defaults to 1.70158.
+
+[
](https://observablehq.com/@d3/easing#backIn)
+
+# d3.easeBackOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/back.js#L15 "Source")
+
+Reverse anticipatory easing; equivalent to 1 - [backIn](#easeBackIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#backOut)
+
+# d3.easeBack(t) [<>](https://github.com/d3/d3-ease/blob/master/src/back.js "Source")
+
# d3.easeBackInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/back.js#L27 "Source")
+
+Symmetric anticipatory easing; scales [backIn](#easeBackIn) for *t* in [0, 0.5] and [backOut](#easeBackOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#backInOut)
+
+# back.overshoot(s) [<>](https://github.com/d3/d3-ease/blob/master/src/back.js#L1 "Source")
+
+Returns a new back easing with the specified overshoot *s*.
+
+# d3.easeBounceIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/bounce.js#L12 "Source")
+
+Bounce easing, like a rubber ball.
+
+[
](https://observablehq.com/@d3/easing#bounceIn)
+
+# d3.easeBounce(t) [<>](https://github.com/d3/d3-ease/blob/master/src/bounce.js "Source")
+
# d3.easeBounceOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/bounce.js#L16 "Source")
+
+Reverse bounce easing; equivalent to 1 - [bounceIn](#easeBounceIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#bounceOut)
+
+# d3.easeBounceInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/bounce.js#L20 "Source")
+
+Symmetric bounce easing; scales [bounceIn](#easeBounceIn) for *t* in [0, 0.5] and [bounceOut](#easeBounceOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#bounceInOut)
diff --git a/node_modules/d3-ease/dist/d3-ease.js b/node_modules/d3-ease/dist/d3-ease.js
new file mode 100644
index 00000000..a8750ba7
--- /dev/null
+++ b/node_modules/d3-ease/dist/d3-ease.js
@@ -0,0 +1,262 @@
+// https://d3js.org/d3-ease/ v2.0.0 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+typeof define === 'function' && define.amd ? define(['exports'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}));
+}(this, function (exports) { 'use strict';
+
+const linear = t => +t;
+
+function quadIn(t) {
+ return t * t;
+}
+
+function quadOut(t) {
+ return t * (2 - t);
+}
+
+function quadInOut(t) {
+ return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
+}
+
+function cubicIn(t) {
+ return t * t * t;
+}
+
+function cubicOut(t) {
+ return --t * t * t + 1;
+}
+
+function cubicInOut(t) {
+ return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
+}
+
+var exponent = 3;
+
+var polyIn = (function custom(e) {
+ e = +e;
+
+ function polyIn(t) {
+ return Math.pow(t, e);
+ }
+
+ polyIn.exponent = custom;
+
+ return polyIn;
+})(exponent);
+
+var polyOut = (function custom(e) {
+ e = +e;
+
+ function polyOut(t) {
+ return 1 - Math.pow(1 - t, e);
+ }
+
+ polyOut.exponent = custom;
+
+ return polyOut;
+})(exponent);
+
+var polyInOut = (function custom(e) {
+ e = +e;
+
+ function polyInOut(t) {
+ return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
+ }
+
+ polyInOut.exponent = custom;
+
+ return polyInOut;
+})(exponent);
+
+var pi = Math.PI,
+ halfPi = pi / 2;
+
+function sinIn(t) {
+ return (+t === 1) ? 1 : 1 - Math.cos(t * halfPi);
+}
+
+function sinOut(t) {
+ return Math.sin(t * halfPi);
+}
+
+function sinInOut(t) {
+ return (1 - Math.cos(pi * t)) / 2;
+}
+
+// tpmt is two power minus ten times t scaled to [0,1]
+function tpmt(x) {
+ return (Math.pow(2, -10 * x) - 0.0009765625) * 1.0009775171065494;
+}
+
+function expIn(t) {
+ return tpmt(1 - +t);
+}
+
+function expOut(t) {
+ return 1 - tpmt(t);
+}
+
+function expInOut(t) {
+ return ((t *= 2) <= 1 ? tpmt(1 - t) : 2 - tpmt(t - 1)) / 2;
+}
+
+function circleIn(t) {
+ return 1 - Math.sqrt(1 - t * t);
+}
+
+function circleOut(t) {
+ return Math.sqrt(1 - --t * t);
+}
+
+function circleInOut(t) {
+ return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
+}
+
+var b1 = 4 / 11,
+ b2 = 6 / 11,
+ b3 = 8 / 11,
+ b4 = 3 / 4,
+ b5 = 9 / 11,
+ b6 = 10 / 11,
+ b7 = 15 / 16,
+ b8 = 21 / 22,
+ b9 = 63 / 64,
+ b0 = 1 / b1 / b1;
+
+function bounceIn(t) {
+ return 1 - bounceOut(1 - t);
+}
+
+function bounceOut(t) {
+ return (t = +t) < b1 ? b0 * t * t : t < b3 ? b0 * (t -= b2) * t + b4 : t < b6 ? b0 * (t -= b5) * t + b7 : b0 * (t -= b8) * t + b9;
+}
+
+function bounceInOut(t) {
+ return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
+}
+
+var overshoot = 1.70158;
+
+var backIn = (function custom(s) {
+ s = +s;
+
+ function backIn(t) {
+ return (t = +t) * t * (s * (t - 1) + t);
+ }
+
+ backIn.overshoot = custom;
+
+ return backIn;
+})(overshoot);
+
+var backOut = (function custom(s) {
+ s = +s;
+
+ function backOut(t) {
+ return --t * t * ((t + 1) * s + t) + 1;
+ }
+
+ backOut.overshoot = custom;
+
+ return backOut;
+})(overshoot);
+
+var backInOut = (function custom(s) {
+ s = +s;
+
+ function backInOut(t) {
+ return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
+ }
+
+ backInOut.overshoot = custom;
+
+ return backInOut;
+})(overshoot);
+
+var tau = 2 * Math.PI,
+ amplitude = 1,
+ period = 0.3;
+
+var elasticIn = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticIn(t) {
+ return a * tpmt(-(--t)) * Math.sin((s - t) / p);
+ }
+
+ elasticIn.amplitude = function(a) { return custom(a, p * tau); };
+ elasticIn.period = function(p) { return custom(a, p); };
+
+ return elasticIn;
+})(amplitude, period);
+
+var elasticOut = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticOut(t) {
+ return 1 - a * tpmt(t = +t) * Math.sin((t + s) / p);
+ }
+
+ elasticOut.amplitude = function(a) { return custom(a, p * tau); };
+ elasticOut.period = function(p) { return custom(a, p); };
+
+ return elasticOut;
+})(amplitude, period);
+
+var elasticInOut = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticInOut(t) {
+ return ((t = t * 2 - 1) < 0
+ ? a * tpmt(-t) * Math.sin((s - t) / p)
+ : 2 - a * tpmt(t) * Math.sin((s + t) / p)) / 2;
+ }
+
+ elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
+ elasticInOut.period = function(p) { return custom(a, p); };
+
+ return elasticInOut;
+})(amplitude, period);
+
+exports.easeBack = backInOut;
+exports.easeBackIn = backIn;
+exports.easeBackInOut = backInOut;
+exports.easeBackOut = backOut;
+exports.easeBounce = bounceOut;
+exports.easeBounceIn = bounceIn;
+exports.easeBounceInOut = bounceInOut;
+exports.easeBounceOut = bounceOut;
+exports.easeCircle = circleInOut;
+exports.easeCircleIn = circleIn;
+exports.easeCircleInOut = circleInOut;
+exports.easeCircleOut = circleOut;
+exports.easeCubic = cubicInOut;
+exports.easeCubicIn = cubicIn;
+exports.easeCubicInOut = cubicInOut;
+exports.easeCubicOut = cubicOut;
+exports.easeElastic = elasticOut;
+exports.easeElasticIn = elasticIn;
+exports.easeElasticInOut = elasticInOut;
+exports.easeElasticOut = elasticOut;
+exports.easeExp = expInOut;
+exports.easeExpIn = expIn;
+exports.easeExpInOut = expInOut;
+exports.easeExpOut = expOut;
+exports.easeLinear = linear;
+exports.easePoly = polyInOut;
+exports.easePolyIn = polyIn;
+exports.easePolyInOut = polyInOut;
+exports.easePolyOut = polyOut;
+exports.easeQuad = quadInOut;
+exports.easeQuadIn = quadIn;
+exports.easeQuadInOut = quadInOut;
+exports.easeQuadOut = quadOut;
+exports.easeSin = sinInOut;
+exports.easeSinIn = sinIn;
+exports.easeSinInOut = sinInOut;
+exports.easeSinOut = sinOut;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-ease/dist/d3-ease.min.js b/node_modules/d3-ease/dist/d3-ease.min.js
new file mode 100644
index 00000000..a44a0588
--- /dev/null
+++ b/node_modules/d3-ease/dist/d3-ease.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-ease/ v2.0.0 Copyright 2020 Mike Bostock
+!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n=n||self).d3=n.d3||{})}(this,function(n){"use strict";function e(n){return((n*=2)<=1?n*n:--n*(2-n)+1)/2}function t(n){return((n*=2)<=1?n*n*n:(n-=2)*n*n+2)/2}var u=function n(e){function t(n){return Math.pow(n,e)}return e=+e,t.exponent=n,t}(3),r=function n(e){function t(n){return 1-Math.pow(1-n,e)}return e=+e,t.exponent=n,t}(3),a=function n(e){function t(n){return((n*=2)<=1?Math.pow(n,e):2-Math.pow(2-n,e))/2}return e=+e,t.exponent=n,t}(3),o=Math.PI,i=o/2;function c(n){return(1-Math.cos(o*n))/2}function s(n){return 1.0009775171065494*(Math.pow(2,-10*n)-.0009765625)}function f(n){return((n*=2)<=1?s(1-n):2-s(n-1))/2}function h(n){return((n*=2)<=1?1-Math.sqrt(1-n*n):Math.sqrt(1-(n-=2)*n)+1)/2}var p=4/11,M=6/11,d=8/11,I=.75,l=9/11,O=10/11,x=.9375,v=21/22,m=63/64,y=1/p/p;function B(n){return(n=+n)
](http://bl.ocks.org/mbostock/ad70335eeef6d167bc36fd3c04378048)[
](http://bl.ocks.org/mbostock/95aa92e2f4e8345aaa55a4a94d41ce37)
+
+You can also simulate circles (disks) with collision, such as for [bubble charts](http://www.nytimes.com/interactive/2012/09/06/us/politics/convention-word-counts.html) or [beeswarm plots](http://bl.ocks.org/mbostock/6526445e2b44303eebf21da3b6627320):
+
+[
](http://bl.ocks.org/mbostock/31ce330646fa8bcb7289ff3b97aab3f5)[
](http://bl.ocks.org/mbostock/6526445e2b44303eebf21da3b6627320)
+
+You can even use it as a rudimentary physics engine, say to simulate cloth:
+
+[
](http://bl.ocks.org/mbostock/1b64ec067fcfc51e7471d944f51f1611)
+
+To use this module, create a [simulation](#simulation) for an array of [nodes](#simulation_nodes), and compose the desired [forces](#simulation_force). Then [listen](#simulation_on) for tick events to render the nodes as they update in your preferred graphics system, such as Canvas or SVG.
+
+## Installing
+
+If you use NPM, `npm install d3-force`. Otherwise, download the [latest release](https://github.com/d3/d3-force/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-force.v2.min.js) or as part of [D3](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3_force` global is exported:
+
+```html
+
+
+
+
+
+```
+
+[Try d3-force in your browser.](https://observablehq.com/collection/@d3/d3-force)
+
+## API Reference
+
+### Simulation
+
+# d3.forceSimulation([nodes]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js "Source")
+
+Creates a new simulation with the specified array of [*nodes*](#simulation_nodes) and no [forces](#simulation_force). If *nodes* is not specified, it defaults to the empty array. The simulator [starts](#simulation_restart) automatically; use [*simulation*.on](#simulation_on) to listen for tick events as the simulation runs. If you wish to run the simulation manually instead, call [*simulation*.stop](#simulation_stop), and then call [*simulation*.tick](#simulation_tick) as desired.
+
+# simulation.restart() [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L86 "Source")
+
+Restarts the simulation’s internal timer and returns the simulation. In conjunction with [*simulation*.alphaTarget](#simulation_alphaTarget) or [*simulation*.alpha](#simulation_alpha), this method can be used to “reheat†the simulation during interaction, such as when dragging a node, or to resume the simulation after temporarily pausing it with [*simulation*.stop](#simulation_stop).
+
+# simulation.stop() [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L90 "Source")
+
+Stops the simulation’s internal timer, if it is running, and returns the simulation. If the timer is already stopped, this method does nothing. This method is useful for running the simulation manually; see [*simulation*.tick](#simulation_tick).
+
+# simulation.tick([iterations]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L38 "Source")
+
+Manually steps the simulation by the specified number of *iterations*, and returns the simulation. If *iterations* is not specified, it defaults to 1 (single step).
+
+For each iteration, it increments the current [*alpha*](#simulation_alpha) by ([*alphaTarget*](#simulation_alphaTarget) - *alpha*) × [*alphaDecay*](#simulation_alphaDecay); then invokes each registered [force](#simulation_force), passing the new *alpha*; then decrements each [node](#simulation_nodes)’s velocity by *velocity* × [*velocityDecay*](#simulation_velocityDecay); lastly increments each node’s position by *velocity*.
+
+This method does not dispatch [events](#simulation_on); events are only dispatched by the internal timer when the simulation is started automatically upon [creation](#forceSimulation) or by calling [*simulation*.restart](#simulation_restart). The natural number of ticks when the simulation is started is ⌈*log*([*alphaMin*](#simulation_alphaMin)) / *log*(1 - [*alphaDecay*](#simulation_alphaDecay))⌉; by default, this is 300.
+
+This method can be used in conjunction with [*simulation*.stop](#simulation_stop) to compute a [static force layout](https://bl.ocks.org/mbostock/1667139). For large graphs, static layouts should be computed [in a web worker](https://bl.ocks.org/mbostock/01ab2e85e8727d6529d20391c0fd9a16) to avoid freezing the user interface.
+
+# simulation.nodes([nodes]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L94 "Source")
+
+If *nodes* is specified, sets the simulation’s nodes to the specified array of objects, initializing their positions and velocities if necessary, and then [re-initializes](#force_initialize) any bound [forces](#simulation_force); returns the simulation. If *nodes* is not specified, returns the simulation’s array of nodes as specified to the [constructor](#forceSimulation).
+
+Each *node* must be an object. The following properties are assigned by the simulation:
+
+* `index` - the node’s zero-based index into *nodes*
+* `x` - the node’s current *x*-position
+* `y` - the node’s current *y*-position
+* `vx` - the node’s current *x*-velocity
+* `vy` - the node’s current *y*-velocity
+
+The position ⟨*x*,*y*⟩ and velocity ⟨*vx*,*vy*⟩ may be subsequently modified by [forces](#forces) and by the simulation. If either *vx* or *vy* is NaN, the velocity is initialized to ⟨0,0⟩. If either *x* or *y* is NaN, the position is initialized in a [phyllotaxis arrangement](https://observablehq.com/@d3/force-layout-phyllotaxis), so chosen to ensure a deterministic, uniform distribution.
+
+To fix a node in a given position, you may specify two additional properties:
+
+* `fx` - the node’s fixed *x*-position
+* `fy` - the node’s fixed *y*-position
+
+At the end of each [tick](#simulation_tick), after the application of any forces, a node with a defined *node*.fx has *node*.x reset to this value and *node*.vx set to zero; likewise, a node with a defined *node*.fy has *node*.y reset to this value and *node*.vy set to zero. To unfix a node that was previously fixed, set *node*.fx and *node*.fy to null, or delete these properties.
+
+If the specified array of *nodes* is modified, such as when nodes are added to or removed from the simulation, this method must be called again with the new (or changed) array to notify the simulation and bound forces of the change; the simulation does not make a defensive copy of the specified array.
+
+# simulation.alpha([alpha]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L98 "Source")
+
+*alpha* is roughly analogous to temperature in [simulated annealing](https://en.wikipedia.org/wiki/Simulated_annealing#Overview). It decreases over time as the simulation “cools downâ€. When *alpha* reaches *alphaMin*, the simulation stops; see [*simulation*.restart](#simulation_restart).
+
+If *alpha* is specified, sets the current alpha to the specified number in the range [0,1] and returns this simulation. If *alpha* is not specified, returns the current alpha value, which defaults to 1.
+
+# simulation.alphaMin([min]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L102 "Source")
+
+If *min* is specified, sets the minimum *alpha* to the specified number in the range [0,1] and returns this simulation. If *min* is not specified, returns the current minimum *alpha* value, which defaults to 0.001. The simulation’s internal timer stops when the current [*alpha*](#simulation_alpha) is less than the minimum *alpha*. The default [alpha decay rate](#simulation_alphaDecay) of ~0.0228 corresponds to 300 iterations.
+
+# simulation.alphaDecay([decay]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L106 "Source")
+
+If *decay* is specified, sets the [*alpha*](#simulation_alpha) decay rate to the specified number in the range [0,1] and returns this simulation. If *decay* is not specified, returns the current *alpha* decay rate, which defaults to 0.0228… = 1 - *pow*(0.001, 1 / 300) where 0.001 is the default [minimum *alpha*](#simulation_alphaMin).
+
+The alpha decay rate determines how quickly the current alpha interpolates towards the desired [target *alpha*](#simulation_alphaTarget); since the default target *alpha* is zero, by default this controls how quickly the simulation cools. Higher decay rates cause the simulation to stabilize more quickly, but risk getting stuck in a local minimum; lower values cause the simulation to take longer to run, but typically converge on a better layout. To have the simulation run forever at the current *alpha*, set the *decay* rate to zero; alternatively, set a [target *alpha*](#simulation_alphaTarget) greater than the [minimum *alpha*](#simulation_alphaMin).
+
+# simulation.alphaTarget([target]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L110 "Source")
+
+If *target* is specified, sets the current target [*alpha*](#simulation_alpha) to the specified number in the range [0,1] and returns this simulation. If *target* is not specified, returns the current target alpha value, which defaults to 0.
+
+# simulation.velocityDecay([decay]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L114 "Source")
+
+If *decay* is specified, sets the velocity decay factor to the specified number in the range [0,1] and returns this simulation. If *decay* is not specified, returns the current velocity decay factor, which defaults to 0.4. The decay factor is akin to atmospheric friction; after the application of any forces during a [tick](#simulation_tick), each node’s velocity is multiplied by 1 - *decay*. As with lowering the [alpha decay rate](#simulation_alphaDecay), less velocity decay may converge on a better solution, but risks numerical instabilities and oscillation.
+
+# simulation.force(name[, force]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L118 "Source")
+
+If *force* is specified, assigns the [force](#forces) for the specified *name* and returns this simulation. If *force* is not specified, returns the force with the specified name, or undefined if there is no such force. (By default, new simulations have no forces.) For example, to create a new simulation to layout a graph, you might say:
+
+```js
+var simulation = d3.forceSimulation(nodes)
+ .force("charge", d3.forceManyBody())
+ .force("link", d3.forceLink(links))
+ .force("center", d3.forceCenter());
+```
+
+To remove the force with the given *name*, pass null as the *force*. For example, to remove the charge force:
+
+```js
+simulation.force("charge", null);
+```
+
+# simulation.find(x, y[, radius]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L122 "Source")
+
+Returns the node closest to the position ⟨*x*,*y*⟩ with the given search *radius*. If *radius* is not specified, it defaults to infinity. If there is no node within the search area, returns undefined.
+
+# simulation.randomSource([source]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js "Source"))
+
+If *source* is specified, sets the function used to generate random numbers; this should be a function that returns a number between 0 (inclusive) and 1 (exclusive). If *source* is not specified, returns this simulation’s current random source which defaults to a fixed-seed [linear congruential generator](https://en.wikipedia.org/wiki/Linear_congruential_generator). See also [*random*.source](https://github.com/d3/d3-random/blob/master/README.md#random_source).
+
+# simulation.on(typenames, [listener]) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L145 "Source")
+
+If *listener* is specified, sets the event *listener* for the specified *typenames* and returns this simulation. If an event listener was already registered for the same type and name, the existing listener is removed before the new listener is added. If *listener* is null, removes the current event listeners for the specified *typenames*, if any. If *listener* is not specified, returns the first currently-assigned listener matching the specified *typenames*, if any. When a specified event is dispatched, each *listener* will be invoked with the `this` context as the simulation.
+
+The *typenames* is a string containing one or more *typename* separated by whitespace. Each *typename* is a *type*, optionally followed by a period (`.`) and a *name*, such as `tick.foo` and `tick.bar`; the name allows multiple listeners to be registered for the same *type*. The *type* must be one of the following:
+
+* `tick` - after each tick of the simulation’s internal timer.
+* `end` - after the simulation’s timer stops when *alpha* < [*alphaMin*](#simulation_alphaMin).
+
+Note that *tick* events are not dispatched when [*simulation*.tick](#simulation_tick) is called manually; events are only dispatched by the internal timer and are intended for interactive rendering of the simulation. To affect the simulation, register [forces](#simulation_force) instead of modifying nodes’ positions or velocities inside a tick event listener.
+
+See [*dispatch*.on](https://github.com/d3/d3-dispatch#dispatch_on) for details.
+
+### Forces
+
+A *force* is simply a function that modifies nodes’ positions or velocities; in this context, a *force* can apply a classical physical force such as electrical charge or gravity, or it can resolve a geometric constraint, such as keeping nodes within a bounding box or keeping linked nodes a fixed distance apart. For example, a simple positioning force that moves nodes towards the origin ⟨0,0⟩ might be implemented as:
+
+```js
+function force(alpha) {
+ for (var i = 0, n = nodes.length, node, k = alpha * 0.1; i < n; ++i) {
+ node = nodes[i];
+ node.vx -= node.x * k;
+ node.vy -= node.y * k;
+ }
+}
+```
+
+Forces typically read the node’s current position ⟨*x*,*y*⟩ and then add to (or subtract from) the node’s velocity ⟨*vx*,*vy*⟩. However, forces may also “peek ahead†to the anticipated next position of the node, ⟨*x* + *vx*,*y* + *vy*⟩; this is necessary for resolving geometric constraints through [iterative relaxation](https://en.wikipedia.org/wiki/Relaxation_\(iterative_method\)). Forces may also modify the position directly, which is sometimes useful to avoid adding energy to the simulation, such as when recentering the simulation in the viewport.
+
+Simulations typically compose multiple forces as desired. This module provides several for your enjoyment:
+
+* [Centering](#centering)
+* [Collision](#collision)
+* [Links](#links)
+* [Many-Body](#many-body)
+* [Positioning](#positioning)
+
+Forces may optionally implement [*force*.initialize](#force_initialize) to receive the simulation’s array of nodes.
+
+# force(alpha) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L47 "Source")
+
+Applies this force, optionally observing the specified *alpha*. Typically, the force is applied to the array of nodes previously passed to [*force*.initialize](#force_initialize), however, some forces may apply to a subset of nodes, or behave differently. For example, [d3.forceLink](#links) applies to the source and target of each link.
+
+# force.initialize(nodes, random) [<>](https://github.com/d3/d3-force/blob/master/src/simulation.js#L77 "Source")
+
+Supplies the array of *nodes* and *random* source to this force. This method is called when a force is bound to a simulation via [*simulation*.force](#simulation_force) and when the simulation’s nodes change via [*simulation*.nodes](#simulation_nodes). A force may perform necessary work during initialization, such as evaluating per-node parameters, to avoid repeatedly performing work during each application of the force.
+
+#### Centering
+
+The centering force translates nodes uniformly so that the mean position of all nodes (the center of mass if all nodes have equal weight) is at the given position ⟨[*x*](#center_x),[*y*](#center_y)⟩. This force modifies the positions of nodes on each application; it does not modify velocities, as doing so would typically cause the nodes to overshoot and oscillate around the desired center. This force helps keeps nodes in the center of the viewport, and unlike the [positioning force](#positioning), it does not distort their relative positions.
+
+# d3.forceCenter([x, y]) [<>](https://github.com/d3/d3-force/blob/master/src/center.js "Source")
+
+Creates a new centering force with the specified [*x*-](#center_x) and [*y*-](#center_y) coordinates. If *x* and *y* are not specified, they default to ⟨0,0⟩.
+
+# center.x([x]) [<>](https://github.com/d3/d3-force/blob/master/src/center.js "Source")
+
+If *x* is specified, sets the *x*-coordinate of the centering position to the specified number and returns this force. If *x* is not specified, returns the current *x*-coordinate, which defaults to zero.
+
+# center.y([y]) [<>](https://github.com/d3/d3-force/blob/master/src/center.js "Source")
+
+If *y* is specified, sets the *y*-coordinate of the centering position to the specified number and returns this force. If *y* is not specified, returns the current *y*-coordinate, which defaults to zero.
+
+# center.strength([strength]) · [<>](https://github.com/d3/d3-force/blob/master/src/center.js "Source")
+
+If *strength* is specified, sets the centering force’s strength. A reduced strength of e.g. 0.05 softens the movements on interactive graphs in which new nodes enter or exit the graph. If *strength* is not specified, returns the force’s current strength, which defaults to 1.
+
+#### Collision
+
+The collision force treats nodes as circles with a given [radius](#collide_radius), rather than points, and prevents nodes from overlapping. More formally, two nodes *a* and *b* are separated so that the distance between *a* and *b* is at least *radius*(*a*) + *radius*(*b*). To reduce jitter, this is by default a “soft†constraint with a configurable [strength](#collide_strength) and [iteration count](#collide_iterations).
+
+# d3.forceCollide([radius]) [<>](https://github.com/d3/d3-force/blob/master/src/collide.js "Source")
+
+Creates a new circle collision force with the specified [*radius*](#collide_radius). If *radius* is not specified, it defaults to the constant one for all nodes.
+
+# collide.radius([radius]) [<>](https://github.com/d3/d3-force/blob/master/src/collide.js#L86 "Source")
+
+If *radius* is specified, sets the radius accessor to the specified number or function, re-evaluates the radius accessor for each node, and returns this force. If *radius* is not specified, returns the current radius accessor, which defaults to:
+
+```js
+function radius() {
+ return 1;
+}
+```
+
+The radius accessor is invoked for each [node](#simulation_nodes) in the simulation, being passed the *node* and its zero-based *index*. The resulting number is then stored internally, such that the radius of each node is only recomputed when the force is initialized or when this method is called with a new *radius*, and not on every application of the force.
+
+# collide.strength([strength]) [<>](https://github.com/d3/d3-force/blob/master/src/collide.js#L82 "Source")
+
+If *strength* is specified, sets the force strength to the specified number in the range [0,1] and returns this force. If *strength* is not specified, returns the current strength which defaults to 1.
+
+Overlapping nodes are resolved through iterative relaxation. For each node, the other nodes that are anticipated to overlap at the next tick (using the anticipated positions ⟨*x* + *vx*,*y* + *vy*⟩) are determined; the node’s velocity is then modified to push the node out of each overlapping node. The change in velocity is dampened by the force’s strength such that the resolution of simultaneous overlaps can be blended together to find a stable solution.
+
+# collide.iterations([iterations]) [<>](https://github.com/d3/d3-force/blob/master/src/collide.js#L78 "Source")
+
+If *iterations* is specified, sets the number of iterations per application to the specified number and returns this force. If *iterations* is not specified, returns the current iteration count which defaults to 1. Increasing the number of iterations greatly increases the rigidity of the constraint and avoids partial overlap of nodes, but also increases the runtime cost to evaluate the force.
+
+#### Links
+
+The link force pushes linked nodes together or apart according to the desired [link distance](#link_distance). The strength of the force is proportional to the difference between the linked nodes’ distance and the target distance, similar to a spring force.
+
+# d3.forceLink([links]) [<>](https://github.com/d3/d3-force/blob/master/src/link.js "Source")
+
+Creates a new link force with the specified *links* and default parameters. If *links* is not specified, it defaults to the empty array.
+
+# link.links([links]) [<>](https://github.com/d3/d3-force/blob/master/src/link.js#L92 "Source")
+
+If *links* is specified, sets the array of links associated with this force, recomputes the [distance](#link_distance) and [strength](#link_strength) parameters for each link, and returns this force. If *links* is not specified, returns the current array of links, which defaults to the empty array.
+
+Each link is an object with the following properties:
+
+* `source` - the link’s source node; see [*simulation*.nodes](#simulation_nodes)
+* `target` - the link’s target node; see [*simulation*.nodes](#simulation_nodes)
+* `index` - the zero-based index into *links*, assigned by this method
+
+For convenience, a link’s source and target properties may be initialized using numeric or string identifiers rather than object references; see [*link*.id](#link_id). When the link force is [initialized](#force_initialize) (or re-initialized, as when the nodes or links change), any *link*.source or *link*.target property which is *not* an object is replaced by an object reference to the corresponding *node* with the given identifier.
+
+If the specified array of *links* is modified, such as when links are added to or removed from the simulation, this method must be called again with the new (or changed) array to notify the force of the change; the force does not make a defensive copy of the specified array.
+
+# link.id([id]) [<>](https://github.com/d3/d3-force/blob/master/src/link.js#L96 "Source")
+
+If *id* is specified, sets the node id accessor to the specified function and returns this force. If *id* is not specified, returns the current node id accessor, which defaults to the numeric *node*.index:
+
+```js
+function id(d) {
+ return d.index;
+}
+```
+
+The default id accessor allows each link’s source and target to be specified as a zero-based index into the [nodes](#simulation_nodes) array. For example:
+
+```js
+var nodes = [
+ {"id": "Alice"},
+ {"id": "Bob"},
+ {"id": "Carol"}
+];
+
+var links = [
+ {"source": 0, "target": 1}, // Alice → Bob
+ {"source": 1, "target": 2} // Bob → Carol
+];
+```
+
+Now consider a different id accessor that returns a string:
+
+```js
+function id(d) {
+ return d.id;
+}
+```
+
+With this accessor, you can use named sources and targets:
+
+```js
+var nodes = [
+ {"id": "Alice"},
+ {"id": "Bob"},
+ {"id": "Carol"}
+];
+
+var links = [
+ {"source": "Alice", "target": "Bob"},
+ {"source": "Bob", "target": "Carol"}
+];
+```
+
+This is particularly useful when representing graphs in JSON, as JSON does not allow references. See [this example](http://bl.ocks.org/mbostock/f584aa36df54c451c94a9d0798caed35).
+
+The id accessor is invoked for each node whenever the force is initialized, as when the [nodes](#simulation_nodes) or [links](#link_links) change, being passed the node and its zero-based index.
+
+# link.distance([distance]) [<>](https://github.com/d3/d3-force/blob/master/src/link.js#L108 "Source")
+
+If *distance* is specified, sets the distance accessor to the specified number or function, re-evaluates the distance accessor for each link, and returns this force. If *distance* is not specified, returns the current distance accessor, which defaults to:
+
+```js
+function distance() {
+ return 30;
+}
+```
+
+The distance accessor is invoked for each [link](#link_links), being passed the *link* and its zero-based *index*. The resulting number is then stored internally, such that the distance of each link is only recomputed when the force is initialized or when this method is called with a new *distance*, and not on every application of the force.
+
+# link.strength([strength]) [<>](https://github.com/d3/d3-force/blob/master/src/link.js#L104 "Source")
+
+If *strength* is specified, sets the strength accessor to the specified number or function, re-evaluates the strength accessor for each link, and returns this force. If *strength* is not specified, returns the current strength accessor, which defaults to:
+
+```js
+function strength(link) {
+ return 1 / Math.min(count(link.source), count(link.target));
+}
+```
+
+Where *count*(*node*) is a function that returns the number of links with the given node as a source or target. This default was chosen because it automatically reduces the strength of links connected to heavily-connected nodes, improving stability.
+
+The strength accessor is invoked for each [link](#link_links), being passed the *link* and its zero-based *index*. The resulting number is then stored internally, such that the strength of each link is only recomputed when the force is initialized or when this method is called with a new *strength*, and not on every application of the force.
+
+# link.iterations([iterations]) [<>](https://github.com/d3/d3-force/blob/master/src/link.js#L100 "Source")
+
+If *iterations* is specified, sets the number of iterations per application to the specified number and returns this force. If *iterations* is not specified, returns the current iteration count which defaults to 1. Increasing the number of iterations greatly increases the rigidity of the constraint and is useful for [complex structures such as lattices](http://bl.ocks.org/mbostock/1b64ec067fcfc51e7471d944f51f1611), but also increases the runtime cost to evaluate the force.
+
+#### Many-Body
+
+The many-body (or *n*-body) force applies mutually amongst all [nodes](#simulation_nodes). It can be used to simulate gravity (attraction) if the [strength](#manyBody_strength) is positive, or electrostatic charge (repulsion) if the strength is negative. This implementation uses quadtrees and the [Barnes–Hut approximation](https://en.wikipedia.org/wiki/Barnes–Hut_simulation) to greatly improve performance; the accuracy can be customized using the [theta](#manyBody_theta) parameter.
+
+Unlike links, which only affect two linked nodes, the charge force is global: every node affects every other node, even if they are on disconnected subgraphs.
+
+# d3.forceManyBody() [<>](https://github.com/d3/d3-force/blob/master/src/manyBody.js "Source")
+
+Creates a new many-body force with the default parameters.
+
+# manyBody.strength([strength]) [<>](https://github.com/d3/d3-force/blob/master/src/manyBody.js#L97 "Source")
+
+If *strength* is specified, sets the strength accessor to the specified number or function, re-evaluates the strength accessor for each node, and returns this force. A positive value causes nodes to attract each other, similar to gravity, while a negative value causes nodes to repel each other, similar to electrostatic charge. If *strength* is not specified, returns the current strength accessor, which defaults to:
+
+```js
+function strength() {
+ return -30;
+}
+```
+
+The strength accessor is invoked for each [node](#simulation_nodes) in the simulation, being passed the *node* and its zero-based *index*. The resulting number is then stored internally, such that the strength of each node is only recomputed when the force is initialized or when this method is called with a new *strength*, and not on every application of the force.
+
+# manyBody.theta([theta]) [<>](https://github.com/d3/d3-force/blob/master/src/manyBody.js#L109 "Source")
+
+If *theta* is specified, sets the Barnes–Hut approximation criterion to the specified number and returns this force. If *theta* is not specified, returns the current value, which defaults to 0.9.
+
+To accelerate computation, this force implements the [Barnes–Hut approximation](http://en.wikipedia.org/wiki/Barnes–Hut_simulation) which takes O(*n* log *n*) per application where *n* is the number of [nodes](#simulation_nodes). For each application, a [quadtree](https://github.com/d3/d3-quadtree) stores the current node positions; then for each node, the combined force of all other nodes on the given node is computed. For a cluster of nodes that is far away, the charge force can be approximated by treating the cluster as a single, larger node. The *theta* parameter determines the accuracy of the approximation: if the ratio *w* / *l* of the width *w* of the quadtree cell to the distance *l* from the node to the cell’s center of mass is less than *theta*, all nodes in the given cell are treated as a single node rather than individually.
+
+# manyBody.distanceMin([distance]) [<>](https://github.com/d3/d3-force/blob/master/src/manyBody.js#L101 "Source")
+
+If *distance* is specified, sets the minimum distance between nodes over which this force is considered. If *distance* is not specified, returns the current minimum distance, which defaults to 1. A minimum distance establishes an upper bound on the strength of the force between two nearby nodes, avoiding instability. In particular, it avoids an infinitely-strong force if two nodes are exactly coincident; in this case, the direction of the force is random.
+
+# manyBody.distanceMax([distance]) [<>](https://github.com/d3/d3-force/blob/master/src/manyBody.js#L105 "Source")
+
+If *distance* is specified, sets the maximum distance between nodes over which this force is considered. If *distance* is not specified, returns the current maximum distance, which defaults to infinity. Specifying a finite maximum distance improves performance and produces a more localized layout.
+
+#### Positioning
+
+The [*x*](#forceX)- and [*y*](#forceY)-positioning forces push nodes towards a desired position along the given dimension with a configurable strength. The [*radial*](#forceRadial) force is similar, except it pushes nodes towards the closest point on a given circle. The strength of the force is proportional to the one-dimensional distance between the node’s position and the target position. While these forces can be used to position individual nodes, they are intended primarily for global forces that apply to all (or most) nodes.
+
+# d3.forceX([x]) [<>](https://github.com/d3/d3-force/blob/master/src/x.js "Source")
+
+Creates a new positioning force along the *x*-axis towards the given position [*x*](#x_x). If *x* is not specified, it defaults to 0.
+
+# x.strength([strength]) [<>](https://github.com/d3/d3-force/blob/master/src/x.js#L32 "Source")
+
+If *strength* is specified, sets the strength accessor to the specified number or function, re-evaluates the strength accessor for each node, and returns this force. The *strength* determines how much to increment the node’s *x*-velocity: ([*x*](#x_x) - *node*.x) × *strength*. For example, a value of 0.1 indicates that the node should move a tenth of the way from its current *x*-position to the target *x*-position with each application. Higher values moves nodes more quickly to the target position, often at the expense of other forces or constraints. A value outside the range [0,1] is not recommended.
+
+If *strength* is not specified, returns the current strength accessor, which defaults to:
+
+```js
+function strength() {
+ return 0.1;
+}
+```
+
+The strength accessor is invoked for each [node](#simulation_nodes) in the simulation, being passed the *node* and its zero-based *index*. The resulting number is then stored internally, such that the strength of each node is only recomputed when the force is initialized or when this method is called with a new *strength*, and not on every application of the force.
+
+# x.x([x]) [<>](https://github.com/d3/d3-force/blob/master/src/x.js#L36 "Source")
+
+If *x* is specified, sets the *x*-coordinate accessor to the specified number or function, re-evaluates the *x*-accessor for each node, and returns this force. If *x* is not specified, returns the current *x*-accessor, which defaults to:
+
+```js
+function x() {
+ return 0;
+}
+```
+
+The *x*-accessor is invoked for each [node](#simulation_nodes) in the simulation, being passed the *node* and its zero-based *index*. The resulting number is then stored internally, such that the target *x*-coordinate of each node is only recomputed when the force is initialized or when this method is called with a new *x*, and not on every application of the force.
+
+# d3.forceY([y]) [<>](https://github.com/d3/d3-force/blob/master/src/y.js "Source")
+
+Creates a new positioning force along the *y*-axis towards the given position [*y*](#y_y). If *y* is not specified, it defaults to 0.
+
+# y.strength([strength]) [<>](https://github.com/d3/d3-force/blob/master/src/y.js#L32 "Source")
+
+If *strength* is specified, sets the strength accessor to the specified number or function, re-evaluates the strength accessor for each node, and returns this force. The *strength* determines how much to increment the node’s *y*-velocity: ([*y*](#y_y) - *node*.y) × *strength*. For example, a value of 0.1 indicates that the node should move a tenth of the way from its current *y*-position to the target *y*-position with each application. Higher values moves nodes more quickly to the target position, often at the expense of other forces or constraints. A value outside the range [0,1] is not recommended.
+
+If *strength* is not specified, returns the current strength accessor, which defaults to:
+
+```js
+function strength() {
+ return 0.1;
+}
+```
+
+The strength accessor is invoked for each [node](#simulation_nodes) in the simulation, being passed the *node* and its zero-based *index*. The resulting number is then stored internally, such that the strength of each node is only recomputed when the force is initialized or when this method is called with a new *strength*, and not on every application of the force.
+
+# y.y([y]) [<>](https://github.com/d3/d3-force/blob/master/src/y.js#L36 "Source")
+
+If *y* is specified, sets the *y*-coordinate accessor to the specified number or function, re-evaluates the *y*-accessor for each node, and returns this force. If *y* is not specified, returns the current *y*-accessor, which defaults to:
+
+```js
+function y() {
+ return 0;
+}
+```
+
+The *y*-accessor is invoked for each [node](#simulation_nodes) in the simulation, being passed the *node* and its zero-based *index*. The resulting number is then stored internally, such that the target *y*-coordinate of each node is only recomputed when the force is initialized or when this method is called with a new *y*, and not on every application of the force.
+
+# d3.forceRadial(radius[, x][, y]) [<>](https://github.com/d3/d3-force/blob/master/src/radial.js "Source")
+
+[
](https://bl.ocks.org/mbostock/cd98bf52e9067e26945edd95e8cf6ef9)
+
+Creates a new positioning force towards a circle of the specified [*radius*](#radial_radius) centered at ⟨[*x*](#radial_x),[*y*](#radial_y)⟩. If *x* and *y* are not specified, they default to ⟨0,0⟩.
+
+# radial.strength([strength]) [<>](https://github.com/d3/d3-force/blob/master/src/radial.js "Source")
+
+If *strength* is specified, sets the strength accessor to the specified number or function, re-evaluates the strength accessor for each node, and returns this force. The *strength* determines how much to increment the node’s *x*- and *y*-velocity. For example, a value of 0.1 indicates that the node should move a tenth of the way from its current position to the closest point on the circle with each application. Higher values moves nodes more quickly to the target position, often at the expense of other forces or constraints. A value outside the range [0,1] is not recommended.
+
+If *strength* is not specified, returns the current strength accessor, which defaults to:
+
+```js
+function strength() {
+ return 0.1;
+}
+```
+
+The strength accessor is invoked for each [node](#simulation_nodes) in the simulation, being passed the *node* and its zero-based *index*. The resulting number is then stored internally, such that the strength of each node is only recomputed when the force is initialized or when this method is called with a new *strength*, and not on every application of the force.
+
+# radial.radius([radius]) [<>](https://github.com/d3/d3-force/blob/master/src/radial.js "Source")
+
+If *radius* is specified, sets the circle *radius* to the specified number or function, re-evaluates the *radius* accessor for each node, and returns this force. If *radius* is not specified, returns the current *radius* accessor.
+
+The *radius* accessor is invoked for each [node](#simulation_nodes) in the simulation, being passed the *node* and its zero-based *index*. The resulting number is then stored internally, such that the target radius of each node is only recomputed when the force is initialized or when this method is called with a new *radius*, and not on every application of the force.
+
+# radial.x([x]) [<>](https://github.com/d3/d3-force/blob/master/src/radial.js "Source")
+
+If *x* is specified, sets the *x*-coordinate of the circle center to the specified number and returns this force. If *x* is not specified, returns the current *x*-coordinate of the center, which defaults to zero.
+
+# radial.y([y]) [<>](https://github.com/d3/d3-force/blob/master/src/radial.js "Source")
+
+If *y* is specified, sets the *y*-coordinate of the circle center to the specified number and returns this force. If *y* is not specified, returns the current *y*-coordinate of the center, which defaults to zero.
diff --git a/node_modules/d3-force/dist/d3-force.js b/node_modules/d3-force/dist/d3-force.js
new file mode 100644
index 00000000..d96788dd
--- /dev/null
+++ b/node_modules/d3-force/dist/d3-force.js
@@ -0,0 +1,693 @@
+// https://d3js.org/d3-force/ v2.1.1 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-quadtree'), require('d3-dispatch'), require('d3-timer')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-quadtree', 'd3-dispatch', 'd3-timer'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}, global.d3, global.d3, global.d3));
+}(this, function (exports, d3Quadtree, d3Dispatch, d3Timer) { 'use strict';
+
+function center(x, y) {
+ var nodes, strength = 1;
+
+ if (x == null) x = 0;
+ if (y == null) y = 0;
+
+ function force() {
+ var i,
+ n = nodes.length,
+ node,
+ sx = 0,
+ sy = 0;
+
+ for (i = 0; i < n; ++i) {
+ node = nodes[i], sx += node.x, sy += node.y;
+ }
+
+ for (sx = (sx / n - x) * strength, sy = (sy / n - y) * strength, i = 0; i < n; ++i) {
+ node = nodes[i], node.x -= sx, node.y -= sy;
+ }
+ }
+
+ force.initialize = function(_) {
+ nodes = _;
+ };
+
+ force.x = function(_) {
+ return arguments.length ? (x = +_, force) : x;
+ };
+
+ force.y = function(_) {
+ return arguments.length ? (y = +_, force) : y;
+ };
+
+ force.strength = function(_) {
+ return arguments.length ? (strength = +_, force) : strength;
+ };
+
+ return force;
+}
+
+function constant(x) {
+ return function() {
+ return x;
+ };
+}
+
+function jiggle(random) {
+ return (random() - 0.5) * 1e-6;
+}
+
+function x(d) {
+ return d.x + d.vx;
+}
+
+function y(d) {
+ return d.y + d.vy;
+}
+
+function collide(radius) {
+ var nodes,
+ radii,
+ random,
+ strength = 1,
+ iterations = 1;
+
+ if (typeof radius !== "function") radius = constant(radius == null ? 1 : +radius);
+
+ function force() {
+ var i, n = nodes.length,
+ tree,
+ node,
+ xi,
+ yi,
+ ri,
+ ri2;
+
+ for (var k = 0; k < iterations; ++k) {
+ tree = d3Quadtree.quadtree(nodes, x, y).visitAfter(prepare);
+ for (i = 0; i < n; ++i) {
+ node = nodes[i];
+ ri = radii[node.index], ri2 = ri * ri;
+ xi = node.x + node.vx;
+ yi = node.y + node.vy;
+ tree.visit(apply);
+ }
+ }
+
+ function apply(quad, x0, y0, x1, y1) {
+ var data = quad.data, rj = quad.r, r = ri + rj;
+ if (data) {
+ if (data.index > node.index) {
+ var x = xi - data.x - data.vx,
+ y = yi - data.y - data.vy,
+ l = x * x + y * y;
+ if (l < r * r) {
+ if (x === 0) x = jiggle(random), l += x * x;
+ if (y === 0) y = jiggle(random), l += y * y;
+ l = (r - (l = Math.sqrt(l))) / l * strength;
+ node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
+ node.vy += (y *= l) * r;
+ data.vx -= x * (r = 1 - r);
+ data.vy -= y * r;
+ }
+ }
+ return;
+ }
+ return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
+ }
+ }
+
+ function prepare(quad) {
+ if (quad.data) return quad.r = radii[quad.data.index];
+ for (var i = quad.r = 0; i < 4; ++i) {
+ if (quad[i] && quad[i].r > quad.r) {
+ quad.r = quad[i].r;
+ }
+ }
+ }
+
+ function initialize() {
+ if (!nodes) return;
+ var i, n = nodes.length, node;
+ radii = new Array(n);
+ for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
+ }
+
+ force.initialize = function(_nodes, _random) {
+ nodes = _nodes;
+ random = _random;
+ initialize();
+ };
+
+ force.iterations = function(_) {
+ return arguments.length ? (iterations = +_, force) : iterations;
+ };
+
+ force.strength = function(_) {
+ return arguments.length ? (strength = +_, force) : strength;
+ };
+
+ force.radius = function(_) {
+ return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), initialize(), force) : radius;
+ };
+
+ return force;
+}
+
+function index(d) {
+ return d.index;
+}
+
+function find(nodeById, nodeId) {
+ var node = nodeById.get(nodeId);
+ if (!node) throw new Error("node not found: " + nodeId);
+ return node;
+}
+
+function link(links) {
+ var id = index,
+ strength = defaultStrength,
+ strengths,
+ distance = constant(30),
+ distances,
+ nodes,
+ count,
+ bias,
+ random,
+ iterations = 1;
+
+ if (links == null) links = [];
+
+ function defaultStrength(link) {
+ return 1 / Math.min(count[link.source.index], count[link.target.index]);
+ }
+
+ function force(alpha) {
+ for (var k = 0, n = links.length; k < iterations; ++k) {
+ for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
+ link = links[i], source = link.source, target = link.target;
+ x = target.x + target.vx - source.x - source.vx || jiggle(random);
+ y = target.y + target.vy - source.y - source.vy || jiggle(random);
+ l = Math.sqrt(x * x + y * y);
+ l = (l - distances[i]) / l * alpha * strengths[i];
+ x *= l, y *= l;
+ target.vx -= x * (b = bias[i]);
+ target.vy -= y * b;
+ source.vx += x * (b = 1 - b);
+ source.vy += y * b;
+ }
+ }
+ }
+
+ function initialize() {
+ if (!nodes) return;
+
+ var i,
+ n = nodes.length,
+ m = links.length,
+ nodeById = new Map(nodes.map((d, i) => [id(d, i, nodes), d])),
+ link;
+
+ for (i = 0, count = new Array(n); i < m; ++i) {
+ link = links[i], link.index = i;
+ if (typeof link.source !== "object") link.source = find(nodeById, link.source);
+ if (typeof link.target !== "object") link.target = find(nodeById, link.target);
+ count[link.source.index] = (count[link.source.index] || 0) + 1;
+ count[link.target.index] = (count[link.target.index] || 0) + 1;
+ }
+
+ for (i = 0, bias = new Array(m); i < m; ++i) {
+ link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
+ }
+
+ strengths = new Array(m), initializeStrength();
+ distances = new Array(m), initializeDistance();
+ }
+
+ function initializeStrength() {
+ if (!nodes) return;
+
+ for (var i = 0, n = links.length; i < n; ++i) {
+ strengths[i] = +strength(links[i], i, links);
+ }
+ }
+
+ function initializeDistance() {
+ if (!nodes) return;
+
+ for (var i = 0, n = links.length; i < n; ++i) {
+ distances[i] = +distance(links[i], i, links);
+ }
+ }
+
+ force.initialize = function(_nodes, _random) {
+ nodes = _nodes;
+ random = _random;
+ initialize();
+ };
+
+ force.links = function(_) {
+ return arguments.length ? (links = _, initialize(), force) : links;
+ };
+
+ force.id = function(_) {
+ return arguments.length ? (id = _, force) : id;
+ };
+
+ force.iterations = function(_) {
+ return arguments.length ? (iterations = +_, force) : iterations;
+ };
+
+ force.strength = function(_) {
+ return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initializeStrength(), force) : strength;
+ };
+
+ force.distance = function(_) {
+ return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), initializeDistance(), force) : distance;
+ };
+
+ return force;
+}
+
+// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
+const a = 1664525;
+const c = 1013904223;
+const m = 4294967296; // 2^32
+
+function lcg() {
+ let s = 1;
+ return () => (s = (a * s + c) % m) / m;
+}
+
+function x$1(d) {
+ return d.x;
+}
+
+function y$1(d) {
+ return d.y;
+}
+
+var initialRadius = 10,
+ initialAngle = Math.PI * (3 - Math.sqrt(5));
+
+function simulation(nodes) {
+ var simulation,
+ alpha = 1,
+ alphaMin = 0.001,
+ alphaDecay = 1 - Math.pow(alphaMin, 1 / 300),
+ alphaTarget = 0,
+ velocityDecay = 0.6,
+ forces = new Map(),
+ stepper = d3Timer.timer(step),
+ event = d3Dispatch.dispatch("tick", "end"),
+ random = lcg();
+
+ if (nodes == null) nodes = [];
+
+ function step() {
+ tick();
+ event.call("tick", simulation);
+ if (alpha < alphaMin) {
+ stepper.stop();
+ event.call("end", simulation);
+ }
+ }
+
+ function tick(iterations) {
+ var i, n = nodes.length, node;
+
+ if (iterations === undefined) iterations = 1;
+
+ for (var k = 0; k < iterations; ++k) {
+ alpha += (alphaTarget - alpha) * alphaDecay;
+
+ forces.forEach(function(force) {
+ force(alpha);
+ });
+
+ for (i = 0; i < n; ++i) {
+ node = nodes[i];
+ if (node.fx == null) node.x += node.vx *= velocityDecay;
+ else node.x = node.fx, node.vx = 0;
+ if (node.fy == null) node.y += node.vy *= velocityDecay;
+ else node.y = node.fy, node.vy = 0;
+ }
+ }
+
+ return simulation;
+ }
+
+ function initializeNodes() {
+ for (var i = 0, n = nodes.length, node; i < n; ++i) {
+ node = nodes[i], node.index = i;
+ if (node.fx != null) node.x = node.fx;
+ if (node.fy != null) node.y = node.fy;
+ if (isNaN(node.x) || isNaN(node.y)) {
+ var radius = initialRadius * Math.sqrt(0.5 + i), angle = i * initialAngle;
+ node.x = radius * Math.cos(angle);
+ node.y = radius * Math.sin(angle);
+ }
+ if (isNaN(node.vx) || isNaN(node.vy)) {
+ node.vx = node.vy = 0;
+ }
+ }
+ }
+
+ function initializeForce(force) {
+ if (force.initialize) force.initialize(nodes, random);
+ return force;
+ }
+
+ initializeNodes();
+
+ return simulation = {
+ tick: tick,
+
+ restart: function() {
+ return stepper.restart(step), simulation;
+ },
+
+ stop: function() {
+ return stepper.stop(), simulation;
+ },
+
+ nodes: function(_) {
+ return arguments.length ? (nodes = _, initializeNodes(), forces.forEach(initializeForce), simulation) : nodes;
+ },
+
+ alpha: function(_) {
+ return arguments.length ? (alpha = +_, simulation) : alpha;
+ },
+
+ alphaMin: function(_) {
+ return arguments.length ? (alphaMin = +_, simulation) : alphaMin;
+ },
+
+ alphaDecay: function(_) {
+ return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay;
+ },
+
+ alphaTarget: function(_) {
+ return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget;
+ },
+
+ velocityDecay: function(_) {
+ return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
+ },
+
+ randomSource: function(_) {
+ return arguments.length ? (random = _, forces.forEach(initializeForce), simulation) : random;
+ },
+
+ force: function(name, _) {
+ return arguments.length > 1 ? ((_ == null ? forces.delete(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
+ },
+
+ find: function(x, y, radius) {
+ var i = 0,
+ n = nodes.length,
+ dx,
+ dy,
+ d2,
+ node,
+ closest;
+
+ if (radius == null) radius = Infinity;
+ else radius *= radius;
+
+ for (i = 0; i < n; ++i) {
+ node = nodes[i];
+ dx = x - node.x;
+ dy = y - node.y;
+ d2 = dx * dx + dy * dy;
+ if (d2 < radius) closest = node, radius = d2;
+ }
+
+ return closest;
+ },
+
+ on: function(name, _) {
+ return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name);
+ }
+ };
+}
+
+function manyBody() {
+ var nodes,
+ node,
+ random,
+ alpha,
+ strength = constant(-30),
+ strengths,
+ distanceMin2 = 1,
+ distanceMax2 = Infinity,
+ theta2 = 0.81;
+
+ function force(_) {
+ var i, n = nodes.length, tree = d3Quadtree.quadtree(nodes, x$1, y$1).visitAfter(accumulate);
+ for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
+ }
+
+ function initialize() {
+ if (!nodes) return;
+ var i, n = nodes.length, node;
+ strengths = new Array(n);
+ for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
+ }
+
+ function accumulate(quad) {
+ var strength = 0, q, c, weight = 0, x, y, i;
+
+ // For internal nodes, accumulate forces from child quadrants.
+ if (quad.length) {
+ for (x = y = i = 0; i < 4; ++i) {
+ if ((q = quad[i]) && (c = Math.abs(q.value))) {
+ strength += q.value, weight += c, x += c * q.x, y += c * q.y;
+ }
+ }
+ quad.x = x / weight;
+ quad.y = y / weight;
+ }
+
+ // For leaf nodes, accumulate forces from coincident quadrants.
+ else {
+ q = quad;
+ q.x = q.data.x;
+ q.y = q.data.y;
+ do strength += strengths[q.data.index];
+ while (q = q.next);
+ }
+
+ quad.value = strength;
+ }
+
+ function apply(quad, x1, _, x2) {
+ if (!quad.value) return true;
+
+ var x = quad.x - node.x,
+ y = quad.y - node.y,
+ w = x2 - x1,
+ l = x * x + y * y;
+
+ // Apply the Barnes-Hut approximation if possible.
+ // Limit forces for very close nodes; randomize direction if coincident.
+ if (w * w / theta2 < l) {
+ if (l < distanceMax2) {
+ if (x === 0) x = jiggle(random), l += x * x;
+ if (y === 0) y = jiggle(random), l += y * y;
+ if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
+ node.vx += x * quad.value * alpha / l;
+ node.vy += y * quad.value * alpha / l;
+ }
+ return true;
+ }
+
+ // Otherwise, process points directly.
+ else if (quad.length || l >= distanceMax2) return;
+
+ // Limit forces for very close nodes; randomize direction if coincident.
+ if (quad.data !== node || quad.next) {
+ if (x === 0) x = jiggle(random), l += x * x;
+ if (y === 0) y = jiggle(random), l += y * y;
+ if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
+ }
+
+ do if (quad.data !== node) {
+ w = strengths[quad.data.index] * alpha / l;
+ node.vx += x * w;
+ node.vy += y * w;
+ } while (quad = quad.next);
+ }
+
+ force.initialize = function(_nodes, _random) {
+ nodes = _nodes;
+ random = _random;
+ initialize();
+ };
+
+ force.strength = function(_) {
+ return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
+ };
+
+ force.distanceMin = function(_) {
+ return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
+ };
+
+ force.distanceMax = function(_) {
+ return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
+ };
+
+ force.theta = function(_) {
+ return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
+ };
+
+ return force;
+}
+
+function radial(radius, x, y) {
+ var nodes,
+ strength = constant(0.1),
+ strengths,
+ radiuses;
+
+ if (typeof radius !== "function") radius = constant(+radius);
+ if (x == null) x = 0;
+ if (y == null) y = 0;
+
+ function force(alpha) {
+ for (var i = 0, n = nodes.length; i < n; ++i) {
+ var node = nodes[i],
+ dx = node.x - x || 1e-6,
+ dy = node.y - y || 1e-6,
+ r = Math.sqrt(dx * dx + dy * dy),
+ k = (radiuses[i] - r) * strengths[i] * alpha / r;
+ node.vx += dx * k;
+ node.vy += dy * k;
+ }
+ }
+
+ function initialize() {
+ if (!nodes) return;
+ var i, n = nodes.length;
+ strengths = new Array(n);
+ radiuses = new Array(n);
+ for (i = 0; i < n; ++i) {
+ radiuses[i] = +radius(nodes[i], i, nodes);
+ strengths[i] = isNaN(radiuses[i]) ? 0 : +strength(nodes[i], i, nodes);
+ }
+ }
+
+ force.initialize = function(_) {
+ nodes = _, initialize();
+ };
+
+ force.strength = function(_) {
+ return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
+ };
+
+ force.radius = function(_) {
+ return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), initialize(), force) : radius;
+ };
+
+ force.x = function(_) {
+ return arguments.length ? (x = +_, force) : x;
+ };
+
+ force.y = function(_) {
+ return arguments.length ? (y = +_, force) : y;
+ };
+
+ return force;
+}
+
+function x$2(x) {
+ var strength = constant(0.1),
+ nodes,
+ strengths,
+ xz;
+
+ if (typeof x !== "function") x = constant(x == null ? 0 : +x);
+
+ function force(alpha) {
+ for (var i = 0, n = nodes.length, node; i < n; ++i) {
+ node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
+ }
+ }
+
+ function initialize() {
+ if (!nodes) return;
+ var i, n = nodes.length;
+ strengths = new Array(n);
+ xz = new Array(n);
+ for (i = 0; i < n; ++i) {
+ strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
+ }
+ }
+
+ force.initialize = function(_) {
+ nodes = _;
+ initialize();
+ };
+
+ force.strength = function(_) {
+ return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
+ };
+
+ force.x = function(_) {
+ return arguments.length ? (x = typeof _ === "function" ? _ : constant(+_), initialize(), force) : x;
+ };
+
+ return force;
+}
+
+function y$2(y) {
+ var strength = constant(0.1),
+ nodes,
+ strengths,
+ yz;
+
+ if (typeof y !== "function") y = constant(y == null ? 0 : +y);
+
+ function force(alpha) {
+ for (var i = 0, n = nodes.length, node; i < n; ++i) {
+ node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
+ }
+ }
+
+ function initialize() {
+ if (!nodes) return;
+ var i, n = nodes.length;
+ strengths = new Array(n);
+ yz = new Array(n);
+ for (i = 0; i < n; ++i) {
+ strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
+ }
+ }
+
+ force.initialize = function(_) {
+ nodes = _;
+ initialize();
+ };
+
+ force.strength = function(_) {
+ return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
+ };
+
+ force.y = function(_) {
+ return arguments.length ? (y = typeof _ === "function" ? _ : constant(+_), initialize(), force) : y;
+ };
+
+ return force;
+}
+
+exports.forceCenter = center;
+exports.forceCollide = collide;
+exports.forceLink = link;
+exports.forceManyBody = manyBody;
+exports.forceRadial = radial;
+exports.forceSimulation = simulation;
+exports.forceX = x$2;
+exports.forceY = y$2;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-force/dist/d3-force.min.js b/node_modules/d3-force/dist/d3-force.min.js
new file mode 100644
index 00000000..d6dcb2c0
--- /dev/null
+++ b/node_modules/d3-force/dist/d3-force.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-force/ v2.1.1 Copyright 2020 Mike Bostock
+!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-quadtree"),require("d3-dispatch"),require("d3-timer")):"function"==typeof define&&define.amd?define(["exports","d3-quadtree","d3-dispatch","d3-timer"],t):t((n=n||self).d3=n.d3||{},n.d3,n.d3,n.d3)}(this,function(n,t,r,e){"use strict";function i(n){return function(){return n}}function u(n){return 1e-6*(n()-.5)}function o(n){return n.x+n.vx}function f(n){return n.y+n.vy}function a(n){return n.index}function c(n,t){var r=n.get(t);if(!r)throw new Error("node not found: "+t);return r}const l=1664525,h=1013904223,v=4294967296;function y(n){return n.x}function d(n){return n.y}var x=10,g=Math.PI*(3-Math.sqrt(5));n.forceCenter=function(n,t){var r,e=1;function i(){var i,u,o=r.length,f=0,a=0;for(i=0;i(c=t.charCodeAt(o))||c>57){l=(46===c?d+t.slice(o+1):t.slice(o))+l,t=t.slice(0,o);break}}y&&!u&&(t=a(t,1/0));var A=h.length+t.length+l.length,N=A
# d3.geoAzimuthalEqualAreaRaw
+
+[
](https://observablehq.com/@d3/azimuthal-equal-area)
+
+The azimuthal equal-area projection.
+
+# d3.geoAzimuthalEquidistant() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/azimuthalEquidistant.js "Source")
+
# d3.geoAzimuthalEquidistantRaw
+
+[
](https://observablehq.com/@d3/azimuthal-equidistant)
+
+The azimuthal equidistant projection.
+
+# d3.geoGnomonic() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/gnomonic.js "Source")
+
# d3.geoGnomonicRaw
+
+[
](https://observablehq.com/@d3/gnomonic)
+
+The gnomonic projection.
+
+# d3.geoOrthographic() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/orthographic.js "Source")
+
# d3.geoOrthographicRaw
+
+[
](https://observablehq.com/@d3/orthographic)
+
+The orthographic projection.
+
+# d3.geoStereographic() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/stereographic.js "Source")
+
# d3.geoStereographicRaw
+
+[
](https://observablehq.com/@d3/stereographic)
+
+The stereographic projection.
+
+#### Equal-Earth
+
+# d3.geoEqualEarth() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/equalEarth.js "Source")
+
# d3.geoEqualEarthRaw
+
+[
](https://observablehq.com/@d3/equal-earth)
+
+The Equal Earth projection, by Bojan Å avriÄ _et al._, 2018.
+
+#### Composite Projections
+
+Composite consist of several projections that are composed into a single display. The constituent projections have fixed clip, center and rotation, and thus composite projections do not support [*projection*.center](#projection_center), [*projection*.rotate](#projection_rotate), [*projection*.clipAngle](#projection_clipAngle), or [*projection*.clipExtent](#projection_clipExtent).
+
+# d3.geoAlbersUsa() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/albersUsa.js "Source")
+
+[
](https://observablehq.com/@d3/u-s-map)
+
+This is a U.S.-centric composite projection of three [d3.geoConicEqualArea](#geoConicEqualArea) projections: [d3.geoAlbers](#geoAlbers) is used for the lower forty-eight states, and separate conic equal-area projections are used for Alaska and Hawaii. Note that the scale for Alaska is diminished: it is projected at 0.35× its true relative area. This diagram by Philippe Rivière illustrates how this projection uses two rectangular insets for Alaska and Hawaii:
+
+[
](https://bl.ocks.org/Fil/7723167596af40d9159be34ffbf8d36b)
+
+See [Albers USA with Territories](https://www.npmjs.com/package/geo-albers-usa-territories) for an extension to all US territories, and [d3-composite-projections](http://geoexamples.com/d3-composite-projections/) for more examples.
+
+#### Conic Projections
+
+Conic projections project the sphere onto a cone, and then unroll the cone onto the plane. Conic projections have [two standard parallels](#conic_parallels).
+
+# conic.parallels([parallels]) [<>](https://github.com/d3/d3-geo/blob/master/src/projection/conic.js "Source")
+
+The [two standard parallels](https://en.wikipedia.org/wiki/Map_projection#Conic) that define the map layout in conic projections.
+
+# d3.geoAlbers() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/albers.js "Source")
+
+[
](https://observablehq.com/@d3/u-s-map)
+
+The Albers’ equal area-conic projection. This is a U.S.-centric configuration of [d3.geoConicEqualArea](#geoConicEqualArea).
+
+# d3.geoConicConformal() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/conicConformal.js "Source")
+
# d3.geoConicConformalRaw(phi0, phi1) [<>](https://github.com/d3/d3-geo/blob/master/src/projection/conicConformal.js "Source")
+
+[
](https://observablehq.com/@d3/conic-conformal)
+
+The conic conformal projection. The parallels default to [30°, 30°] resulting in flat top. See also [*conic*.parallels](#conic_parallels).
+
+# d3.geoConicEqualArea() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/conicEqualArea.js "Source")
+
# d3.geoConicEqualAreaRaw(phi0, phi1) [<>](https://github.com/d3/d3-geo/blob/master/src/projection/conicEqualArea.js "Source")
+
+[
](https://observablehq.com/@d3/conic-equal-area)
+
+The Albers’ equal-area conic projection. See also [*conic*.parallels](#conic_parallels).
+
+# d3.geoConicEquidistant() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/conicEquidistant.js "Source")
+
# d3.geoConicEquidistantRaw(phi0, phi1) [<>](https://github.com/d3/d3-geo/blob/master/src/projection/conicEquidistant.js "Source")
+
+[
](https://observablehq.com/@d3/conic-equidistant)
+
+The conic equidistant projection. See also [*conic*.parallels](#conic_parallels).
+
+#### Cylindrical Projections
+
+Cylindrical projections project the sphere onto a containing cylinder, and then unroll the cylinder onto the plane. [Pseudocylindrical projections](https://web.archive.org/web/20150928042327/http://www.progonos.com/furuti/MapProj/Normal/ProjPCyl/projPCyl.html) are a generalization of cylindrical projections.
+
+# d3.geoEquirectangular() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/equirectangular.js "Source")
+
# d3.geoEquirectangularRaw
+
+[
](https://observablehq.com/@d3/equirectangular)
+
+The equirectangular (plate carrée) projection.
+
+# d3.geoMercator() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/mercator.js "Source")
+
# d3.geoMercatorRaw
+
+[
](https://observablehq.com/@d3/mercator)
+
+The spherical Mercator projection. Defines a default [*projection*.clipExtent](#projection_clipExtent) such that the world is projected to a square, clipped to approximately ±85° latitude.
+
+# d3.geoTransverseMercator() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/transverseMercator.js "Source")
+
# d3.geoTransverseMercatorRaw
+
+[
](https://observablehq.com/@d3/transverse-mercator)
+
+The transverse spherical Mercator projection. Defines a default [*projection*.clipExtent](#projection_clipExtent) such that the world is projected to a square, clipped to approximately ±85° latitude.
+
+# d3.geoNaturalEarth1() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/naturalEarth1.js "Source")
+
# d3.geoNaturalEarth1Raw
+
+[
](https://observablehq.com/@d3/natural-earth)
+
+The [Natural Earth projection](http://www.shadedrelief.com/NE_proj/) is a pseudocylindrical projection designed by Tom Patterson. It is neither conformal nor equal-area, but appealing to the eye for small-scale maps of the whole world.
+
+### Raw Projections
+
+Raw projections are point transformation functions that are used to implement custom projections; they typically passed to [d3.geoProjection](#geoProjection) or [d3.geoProjectionMutator](#geoProjectionMutator). They are exposed here to facilitate the derivation of related projections. Raw projections take spherical coordinates \[*lambda*, *phi*\] in radians (not degrees!) and return a point \[*x*, *y*\], typically in the unit square centered around the origin.
+
+# project(lambda, phi)
+
+Projects the specified point [lambda, phi] in radians, returning a new point \[*x*, *y*\] in unitless coordinates.
+
+# project.invert(x, y)
+
+The inverse of [*project*](#_project).
+
+# d3.geoProjection(project) [<>](https://github.com/d3/d3-geo/blob/master/src/projection/index.js "Source")
+
+Constructs a new projection from the specified [raw projection](#_project), *project*. The *project* function takes the *longitude* and *latitude* of a given point in [radians](http://mathworld.wolfram.com/Radian.html), often referred to as *lambda* (λ) and *phi* (φ), and returns a two-element array \[*x*, *y*\] representing its unit projection. The *project* function does not need to scale or translate the point, as these are applied automatically by [*projection*.scale](#projection_scale), [*projection*.translate](#projection_translate), and [*projection*.center](#projection_center). Likewise, the *project* function does not need to perform any spherical rotation, as [*projection*.rotate](#projection_rotate) is applied prior to projection.
+
+For example, a spherical Mercator projection can be implemented as:
+
+```js
+var mercator = d3.geoProjection(function(x, y) {
+ return [x, Math.log(Math.tan(Math.PI / 4 + y / 2))];
+});
+```
+
+If the *project* function exposes an *invert* method, the returned projection will also expose [*projection*.invert](#projection_invert).
+
+# d3.geoProjectionMutator(factory) [<>](https://github.com/d3/d3-geo/blob/master/src/projection/index.js "Source")
+
+Constructs a new projection from the specified [raw projection](#_project) *factory* and returns a *mutate* function to call whenever the raw projection changes. The *factory* must return a raw projection. The returned *mutate* function returns the wrapped projection. For example, a conic projection typically has two configurable parallels. A suitable *factory* function, such as [d3.geoConicEqualAreaRaw](#geoConicEqualAreaRaw), would have the form:
+
+```js
+// y0 and y1 represent two parallels
+function conicFactory(phi0, phi1) {
+ return function conicRaw(lambda, phi) {
+ return […, …];
+ };
+}
+```
+
+Using d3.geoProjectionMutator, you can implement a standard projection that allows the parallels to be changed, reassigning the raw projection used internally by [d3.geoProjection](#geoProjection):
+
+```js
+function conicCustom() {
+ var phi0 = 29.5,
+ phi1 = 45.5,
+ mutate = d3.geoProjectionMutator(conicFactory),
+ projection = mutate(phi0, phi1);
+
+ projection.parallels = function(_) {
+ return arguments.length ? mutate(phi0 = +_[0], phi1 = +_[1]) : [phi0, phi1];
+ };
+
+ return projection;
+}
+```
+
+When creating a mutable projection, the *mutate* function is typically not exposed.
+
+### Spherical Math
+
+# d3.geoArea(object) [<>](https://github.com/d3/d3-geo/blob/master/src/area.js "Source")
+
+Returns the spherical area of the specified GeoJSON *object* in [steradians](http://mathworld.wolfram.com/Steradian.html). This is the spherical equivalent of [*path*.area](#path_area).
+
+# d3.geoBounds(object) [<>](https://github.com/d3/d3-geo/blob/master/src/bounds.js "Source")
+
+Returns the [spherical bounding box](https://www.jasondavies.com/maps/bounds/) for the specified GeoJSON *object*. The bounding box is represented by a two-dimensional array: \[\[*left*, *bottom*], \[*right*, *top*\]\], where *left* is the minimum longitude, *bottom* is the minimum latitude, *right* is maximum longitude, and *top* is the maximum latitude. All coordinates are given in degrees. (Note that in projected planar coordinates, the minimum latitude is typically the maximum *y*-value, and the maximum latitude is typically the minimum *y*-value.) This is the spherical equivalent of [*path*.bounds](#path_bounds).
+
+# d3.geoCentroid(object) [<>](https://github.com/d3/d3-geo/blob/master/src/centroid.js "Source")
+
+Returns the spherical centroid of the specified GeoJSON *object*. This is the spherical equivalent of [*path*.centroid](#path_centroid).
+
+# d3.geoDistance(a, b) [<>](https://github.com/d3/d3-geo/blob/master/src/distance.js "Source")
+
+Returns the great-arc distance in [radians](http://mathworld.wolfram.com/Radian.html) between the two points *a* and *b*. Each point must be specified as a two-element array \[*longitude*, *latitude*\] in degrees. This is the spherical equivalent of [*path*.measure](#path_measure) given a LineString of two points.
+
+# d3.geoLength(object) [<>](https://github.com/d3/d3-geo/blob/master/src/length.js "Source")
+
+Returns the great-arc length of the specified GeoJSON *object* in [radians](http://mathworld.wolfram.com/Radian.html). For polygons, returns the perimeter of the exterior ring plus that of any interior rings. This is the spherical equivalent of [*path*.measure](#path_measure).
+
+# d3.geoInterpolate(a, b) [<>](https://github.com/d3/d3-geo/blob/master/src/interpolate.js "Source")
+
+Returns an interpolator function given two points *a* and *b*. Each point must be specified as a two-element array \[*longitude*, *latitude*\] in degrees. The returned interpolator function takes a single argument *t*, where *t* is a number ranging from 0 to 1; a value of 0 returns the point *a*, while a value of 1 returns the point *b*. Intermediate values interpolate from *a* to *b* along the great arc that passes through both *a* and *b*. If *a* and *b* are antipodes, an arbitrary great arc is chosen.
+
+# d3.geoContains(object, point) [<>](https://github.com/d3/d3-geo/blob/master/src/contains.js "Source")
+
+Returns true if and only if the specified GeoJSON *object* contains the specified *point*, or false if the *object* does not contain the *point*. The point must be specified as a two-element array \[*longitude*, *latitude*\] in degrees. For Point and MultiPoint geometries, an exact test is used; for a Sphere, true is always returned; for other geometries, an epsilon threshold is applied.
+
+# d3.geoRotation(angles) [<>](https://github.com/d3/d3-geo/blob/master/src/rotation.js "Source")
+
+Returns a [rotation function](#_rotation) for the given *angles*, which must be a two- or three-element array of numbers [*lambda*, *phi*, *gamma*] specifying the rotation angles in degrees about [each spherical axis](https://bl.ocks.org/mbostock/4282586). (These correspond to [yaw, pitch and roll](https://en.wikipedia.org/wiki/Aircraft_principal_axes).) If the rotation angle *gamma* is omitted, it defaults to 0. See also [*projection*.rotate](#projection_rotate).
+
+# rotation(point) [<>](https://github.com/d3/d3-geo/blob/master/src/rotation.js "Source")
+
+Returns a new array \[*longitude*, *latitude*\] in degrees representing the rotated point of the given *point*. The point must be specified as a two-element array \[*longitude*, *latitude*\] in degrees.
+
+# rotation.invert(point) [<>](https://github.com/d3/d3-geo/blob/master/src/rotation.js "Source")
+
+Returns a new array \[*longitude*, *latitude*\] in degrees representing the point of the given rotated *point*; the inverse of [*rotation*](#_rotation). The point must be specified as a two-element array \[*longitude*, *latitude*\] in degrees.
+
+### Spherical Shapes
+
+To generate a [great arc](https://en.wikipedia.org/wiki/Great-circle_distance) (a segment of a great circle), simply pass a GeoJSON LineString geometry object to a [d3.geoPath](#geoPath). D3’s projections use great-arc interpolation for intermediate points, so there’s no need for a great arc shape generator.
+
+# d3.geoCircle() [<>](https://github.com/d3/d3-geo/blob/master/src/circle.js "Source")
+
+Returns a new circle generator.
+
+# circle(arguments…) [<>](https://github.com/d3/d3-geo/blob/master/src/circle.js "Source")
+
+Returns a new GeoJSON geometry object of type “Polygon†approximating a circle on the surface of a sphere, with the current [center](#circle_center), [radius](#circle_radius) and [precision](#circle_precision). Any *arguments* are passed to the accessors.
+
+# circle.center([center]) [<>](https://github.com/d3/d3-geo/blob/master/src/circle.js "Source")
+
+If *center* is specified, sets the circle center to the specified point \[*longitude*, *latitude*\] in degrees, and returns this circle generator. The center may also be specified as a function; this function will be invoked whenever a circle is [generated](#_circle), being passed any arguments passed to the circle generator. If *center* is not specified, returns the current center accessor, which defaults to:
+
+```js
+function center() {
+ return [0, 0];
+}
+```
+
+# circle.radius([radius]) [<>](https://github.com/d3/d3-geo/blob/master/src/circle.js "Source")
+
+If *radius* is specified, sets the circle radius to the specified angle in degrees, and returns this circle generator. The radius may also be specified as a function; this function will be invoked whenever a circle is [generated](#_circle), being passed any arguments passed to the circle generator. If *radius* is not specified, returns the current radius accessor, which defaults to:
+
+```js
+function radius() {
+ return 90;
+}
+```
+
+# circle.precision([angle]) [<>](https://github.com/d3/d3-geo/blob/master/src/circle.js "Source")
+
+If *precision* is specified, sets the circle precision to the specified angle in degrees, and returns this circle generator. The precision may also be specified as a function; this function will be invoked whenever a circle is [generated](#_circle), being passed any arguments passed to the circle generator. If *precision* is not specified, returns the current precision accessor, which defaults to:
+
+```js
+function precision() {
+ return 6;
+}
+```
+
+Small circles do not follow great arcs and thus the generated polygon is only an approximation. Specifying a smaller precision angle improves the accuracy of the approximate polygon, but also increase the cost to generate and render it.
+
+# d3.geoGraticule() [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+Constructs a geometry generator for creating graticules: a uniform grid of [meridians](https://en.wikipedia.org/wiki/Meridian_\(geography\)) and [parallels](https://en.wikipedia.org/wiki/Circle_of_latitude) for showing projection distortion. The default graticule has meridians and parallels every 10° between ±80° latitude; for the polar regions, there are meridians every 90°.
+
+
+
+# graticule() [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+Returns a GeoJSON MultiLineString geometry object representing all meridians and parallels for this graticule.
+
+# graticule.lines() [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+Returns an array of GeoJSON LineString geometry objects, one for each meridian or parallel for this graticule.
+
+# graticule.outline() [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+Returns a GeoJSON Polygon geometry object representing the outline of this graticule, i.e. along the meridians and parallels defining its extent.
+
+# graticule.extent([extent]) [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+If *extent* is specified, sets the major and minor extents of this graticule. If *extent* is not specified, returns the current minor extent, which defaults to ⟨⟨-180°, -80° - ε⟩, ⟨180°, 80° + ε⟩⟩.
+
+# graticule.extentMajor([extent]) [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+If *extent* is specified, sets the major extent of this graticule. If *extent* is not specified, returns the current major extent, which defaults to ⟨⟨-180°, -90° + ε⟩, ⟨180°, 90° - ε⟩⟩.
+
+# graticule.extentMinor([extent]) [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+If *extent* is specified, sets the minor extent of this graticule. If *extent* is not specified, returns the current minor extent, which defaults to ⟨⟨-180°, -80° - ε⟩, ⟨180°, 80° + ε⟩⟩.
+
+# graticule.step([step]) [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+If *step* is specified, sets the major and minor step for this graticule. If *step* is not specified, returns the current minor step, which defaults to ⟨10°, 10°⟩.
+
+# graticule.stepMajor([step]) [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+If *step* is specified, sets the major step for this graticule. If *step* is not specified, returns the current major step, which defaults to ⟨90°, 360°⟩.
+
+# graticule.stepMinor([step]) [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+If *step* is specified, sets the minor step for this graticule. If *step* is not specified, returns the current minor step, which defaults to ⟨10°, 10°⟩.
+
+# graticule.precision([angle]) [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+If *precision* is specified, sets the precision for this graticule, in degrees. If *precision* is not specified, returns the current precision, which defaults to 2.5°.
+
+# d3.geoGraticule10() [<>](https://github.com/d3/d3-geo/blob/master/src/graticule.js "Source")
+
+A convenience method for directly generating the default 10° global graticule as a GeoJSON MultiLineString geometry object. Equivalent to:
+
+```js
+function geoGraticule10() {
+ return d3.geoGraticule()();
+}
+```
+
+### Streams
+
+D3 transforms geometry using a sequence of function calls, rather than materializing intermediate representations, to minimize overhead. Streams must implement several methods to receive input geometry. Streams are inherently stateful; the meaning of a [point](#point) depends on whether the point is inside of a [line](#lineStart), and likewise a line is distinguished from a ring by a [polygon](#polygonStart). Despite the name “streamâ€, these method calls are currently synchronous.
+
+# d3.geoStream(object, stream) [<>](https://github.com/d3/d3-geo/blob/master/src/stream.js "Source")
+
+Streams the specified [GeoJSON](http://geojson.org) *object* to the specified [projection *stream*](#projection-streams). While both features and geometry objects are supported as input, the stream interface only describes the geometry, and thus additional feature properties are not visible to streams.
+
+# stream.point(x, y[, z])
+
+Indicates a point with the specified coordinates *x* and *y* (and optionally *z*). The coordinate system is unspecified and implementation-dependent; for example, [projection streams](https://github.com/d3/d3-geo-projection) require spherical coordinates in degrees as input. Outside the context of a polygon or line, a point indicates a point geometry object ([Point](http://www.geojson.org/geojson-spec.html#point) or [MultiPoint](http://www.geojson.org/geojson-spec.html#multipoint)). Within a line or polygon ring, the point indicates a control point.
+
+# stream.lineStart()
+
+Indicates the start of a line or ring. Within a polygon, indicates the start of a ring. The first ring of a polygon is the exterior ring, and is typically clockwise. Any subsequent rings indicate holes in the polygon, and are typically counterclockwise.
+
+# stream.lineEnd()
+
+Indicates the end of a line or ring. Within a polygon, indicates the end of a ring. Unlike GeoJSON, the redundant closing coordinate of a ring is *not* indicated via [point](#point), and instead is implied via lineEnd within a polygon. Thus, the given polygon input:
+
+```json
+{
+ "type": "Polygon",
+ "coordinates": [
+ [[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]
+ ]
+}
+```
+
+Will produce the following series of method calls on the stream:
+
+```js
+stream.polygonStart();
+stream.lineStart();
+stream.point(0, 0);
+stream.point(0, 1);
+stream.point(1, 1);
+stream.point(1, 0);
+stream.lineEnd();
+stream.polygonEnd();
+```
+
+# stream.polygonStart()
+
+Indicates the start of a polygon. The first line of a polygon indicates the exterior ring, and any subsequent lines indicate interior holes.
+
+# stream.polygonEnd()
+
+Indicates the end of a polygon.
+
+# stream.sphere()
+
+Indicates the sphere (the globe; the unit sphere centered at ⟨0,0,0⟩).
+
+### Transforms
+
+Transforms are a generalization of projections. Transform implement [*projection*.stream](#projection_stream) and can be passed to [*path*.projection](#path_projection). However, they only implement a subset of the other projection methods, and represent arbitrary geometric transformations rather than projections from spherical to planar coordinates.
+
+# d3.geoTransform(methods) [<>](https://github.com/d3/d3-geo/blob/master/src/transform.js "Source")
+
+Defines an arbitrary transform using the methods defined on the specified *methods* object. Any undefined methods will use pass-through methods that propagate inputs to the output stream. For example, to reflect the *y*-dimension (see also [*identity*.reflectY](#identity_reflectY)):
+
+```js
+var reflectY = d3.geoTransform({
+ point: function(x, y) {
+ this.stream.point(x, -y);
+ }
+});
+```
+
+Or to define an affine matrix transformation:
+
+```js
+function matrix(a, b, c, d, tx, ty) {
+ return d3.geoTransform({
+ point: function(x, y) {
+ this.stream.point(a * x + b * y + tx, c * x + d * y + ty);
+ }
+ });
+}
+```
+
+# d3.geoIdentity() [<>](https://github.com/d3/d3-geo/blob/master/src/projection/identity.js "Source")
+
+The identity transform can be used to scale, translate and clip planar geometry. It implements [*projection*.scale](#projection_scale), [*projection*.translate](#projection_translate), [*projection*.fitExtent](#projection_fitExtent), [*projection*.fitSize](#projection_fitSize), [*projection*.fitWidth](#projection_fitWidth), [*projection*.fitHeight](#projection_fitHeight), [*projection*.clipExtent](#projection_clipExtent), [*projection*.angle](#projection_angle), [*projection*.reflectX](#projection_reflectX) and [*projection*.reflectY](#projection_reflectY).
+
+### Clipping
+
+Projections perform cutting or clipping of geometries in two stages.
+
+# preclip(stream)
+
+Pre-clipping occurs in geographic coordinates. Cutting along the antimeridian line, or clipping along a small circle are the most common strategies.
+
+See [*projection*.preclip](#projection_preclip).
+
+# postclip(stream)
+
+Post-clipping occurs on the plane, when a projection is bounded to a certain extent such as a rectangle.
+
+See [*projection*.postclip](#projection_postclip).
+
+Clipping functions are implemented as transformations of a [projection stream](#streams). Pre-clipping operates on spherical coordinates, in radians. Post-clipping operates on planar coordinates, in pixels.
+
+# d3.geoClipAntimeridian
+
+A clipping function which transforms a stream such that geometries (lines or polygons) that cross the antimeridian line are cut in two, one on each side. Typically used for pre-clipping.
+
+# d3.geoClipCircle(angle)
+
+Generates a clipping function which transforms a stream such that geometries are bounded by a small circle of radius *angle* around the projection’s [center](#projection_center). Typically used for pre-clipping.
+
+# d3.geoClipRectangle(x0, y0, x1, y1)
+
+Generates a clipping function which transforms a stream such that geometries are bounded by a rectangle of coordinates [[x0, y0], [x1, y1]]. Typically used for post-clipping.
diff --git a/node_modules/d3-geo/dist/d3-geo.js b/node_modules/d3-geo/dist/d3-geo.js
new file mode 100644
index 00000000..54c5643b
--- /dev/null
+++ b/node_modules/d3-geo/dist/d3-geo.js
@@ -0,0 +1,3127 @@
+// https://d3js.org/d3-geo/ v2.0.1 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-array'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}, global.d3));
+}(this, function (exports, d3Array) { 'use strict';
+
+var epsilon = 1e-6;
+var epsilon2 = 1e-12;
+var pi = Math.PI;
+var halfPi = pi / 2;
+var quarterPi = pi / 4;
+var tau = pi * 2;
+
+var degrees = 180 / pi;
+var radians = pi / 180;
+
+var abs = Math.abs;
+var atan = Math.atan;
+var atan2 = Math.atan2;
+var cos = Math.cos;
+var ceil = Math.ceil;
+var exp = Math.exp;
+var hypot = Math.hypot;
+var log = Math.log;
+var pow = Math.pow;
+var sin = Math.sin;
+var sign = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
+var sqrt = Math.sqrt;
+var tan = Math.tan;
+
+function acos(x) {
+ return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
+}
+
+function asin(x) {
+ return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
+}
+
+function haversin(x) {
+ return (x = sin(x / 2)) * x;
+}
+
+function noop() {}
+
+function streamGeometry(geometry, stream) {
+ if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
+ streamGeometryType[geometry.type](geometry, stream);
+ }
+}
+
+var streamObjectType = {
+ Feature: function(object, stream) {
+ streamGeometry(object.geometry, stream);
+ },
+ FeatureCollection: function(object, stream) {
+ var features = object.features, i = -1, n = features.length;
+ while (++i < n) streamGeometry(features[i].geometry, stream);
+ }
+};
+
+var streamGeometryType = {
+ Sphere: function(object, stream) {
+ stream.sphere();
+ },
+ Point: function(object, stream) {
+ object = object.coordinates;
+ stream.point(object[0], object[1], object[2]);
+ },
+ MultiPoint: function(object, stream) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
+ },
+ LineString: function(object, stream) {
+ streamLine(object.coordinates, stream, 0);
+ },
+ MultiLineString: function(object, stream) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) streamLine(coordinates[i], stream, 0);
+ },
+ Polygon: function(object, stream) {
+ streamPolygon(object.coordinates, stream);
+ },
+ MultiPolygon: function(object, stream) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) streamPolygon(coordinates[i], stream);
+ },
+ GeometryCollection: function(object, stream) {
+ var geometries = object.geometries, i = -1, n = geometries.length;
+ while (++i < n) streamGeometry(geometries[i], stream);
+ }
+};
+
+function streamLine(coordinates, stream, closed) {
+ var i = -1, n = coordinates.length - closed, coordinate;
+ stream.lineStart();
+ while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
+ stream.lineEnd();
+}
+
+function streamPolygon(coordinates, stream) {
+ var i = -1, n = coordinates.length;
+ stream.polygonStart();
+ while (++i < n) streamLine(coordinates[i], stream, 1);
+ stream.polygonEnd();
+}
+
+function geoStream(object, stream) {
+ if (object && streamObjectType.hasOwnProperty(object.type)) {
+ streamObjectType[object.type](object, stream);
+ } else {
+ streamGeometry(object, stream);
+ }
+}
+
+var areaRingSum = new d3Array.Adder();
+
+// hello?
+
+var areaSum = new d3Array.Adder(),
+ lambda00,
+ phi00,
+ lambda0,
+ cosPhi0,
+ sinPhi0;
+
+var areaStream = {
+ point: noop,
+ lineStart: noop,
+ lineEnd: noop,
+ polygonStart: function() {
+ areaRingSum = new d3Array.Adder();
+ areaStream.lineStart = areaRingStart;
+ areaStream.lineEnd = areaRingEnd;
+ },
+ polygonEnd: function() {
+ var areaRing = +areaRingSum;
+ areaSum.add(areaRing < 0 ? tau + areaRing : areaRing);
+ this.lineStart = this.lineEnd = this.point = noop;
+ },
+ sphere: function() {
+ areaSum.add(tau);
+ }
+};
+
+function areaRingStart() {
+ areaStream.point = areaPointFirst;
+}
+
+function areaRingEnd() {
+ areaPoint(lambda00, phi00);
+}
+
+function areaPointFirst(lambda, phi) {
+ areaStream.point = areaPoint;
+ lambda00 = lambda, phi00 = phi;
+ lambda *= radians, phi *= radians;
+ lambda0 = lambda, cosPhi0 = cos(phi = phi / 2 + quarterPi), sinPhi0 = sin(phi);
+}
+
+function areaPoint(lambda, phi) {
+ lambda *= radians, phi *= radians;
+ phi = phi / 2 + quarterPi; // 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 dLambda = lambda - lambda0,
+ sdLambda = dLambda >= 0 ? 1 : -1,
+ adLambda = sdLambda * dLambda,
+ cosPhi = cos(phi),
+ sinPhi = sin(phi),
+ k = sinPhi0 * sinPhi,
+ u = cosPhi0 * cosPhi + k * cos(adLambda),
+ v = k * sdLambda * sin(adLambda);
+ areaRingSum.add(atan2(v, u));
+
+ // Advance the previous points.
+ lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
+}
+
+function area(object) {
+ areaSum = new d3Array.Adder();
+ geoStream(object, areaStream);
+ return areaSum * 2;
+}
+
+function spherical(cartesian) {
+ return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
+}
+
+function cartesian(spherical) {
+ var lambda = spherical[0], phi = spherical[1], cosPhi = cos(phi);
+ return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
+}
+
+function cartesianDot(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+
+function 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]];
+}
+
+// TODO return a
+function cartesianAddInPlace(a, b) {
+ a[0] += b[0], a[1] += b[1], a[2] += b[2];
+}
+
+function cartesianScale(vector, k) {
+ return [vector[0] * k, vector[1] * k, vector[2] * k];
+}
+
+// TODO return d
+function cartesianNormalizeInPlace(d) {
+ var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+ d[0] /= l, d[1] /= l, d[2] /= l;
+}
+
+var lambda0$1, phi0, lambda1, phi1, // bounds
+ lambda2, // previous lambda-coordinate
+ lambda00$1, phi00$1, // first point
+ p0, // previous 3D point
+ deltaSum,
+ ranges,
+ range;
+
+var boundsStream = {
+ point: boundsPoint,
+ lineStart: boundsLineStart,
+ lineEnd: boundsLineEnd,
+ polygonStart: function() {
+ boundsStream.point = boundsRingPoint;
+ boundsStream.lineStart = boundsRingStart;
+ boundsStream.lineEnd = boundsRingEnd;
+ deltaSum = new d3Array.Adder();
+ areaStream.polygonStart();
+ },
+ polygonEnd: function() {
+ areaStream.polygonEnd();
+ boundsStream.point = boundsPoint;
+ boundsStream.lineStart = boundsLineStart;
+ boundsStream.lineEnd = boundsLineEnd;
+ if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
+ else if (deltaSum > epsilon) phi1 = 90;
+ else if (deltaSum < -epsilon) phi0 = -90;
+ range[0] = lambda0$1, range[1] = lambda1;
+ },
+ sphere: function() {
+ lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
+ }
+};
+
+function boundsPoint(lambda, phi) {
+ ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
+ if (phi < phi0) phi0 = phi;
+ if (phi > phi1) phi1 = phi;
+}
+
+function linePoint(lambda, phi) {
+ var p = cartesian([lambda * radians, phi * radians]);
+ if (p0) {
+ var normal = cartesianCross(p0, p),
+ equatorial = [normal[1], -normal[0], 0],
+ inflection = cartesianCross(equatorial, normal);
+ cartesianNormalizeInPlace(inflection);
+ inflection = spherical(inflection);
+ var delta = lambda - lambda2,
+ sign = delta > 0 ? 1 : -1,
+ lambdai = inflection[0] * degrees * sign,
+ phii,
+ antimeridian = abs(delta) > 180;
+ if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
+ phii = inflection[1] * degrees;
+ if (phii > phi1) phi1 = phii;
+ } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
+ phii = -inflection[1] * degrees;
+ if (phii < phi0) phi0 = phii;
+ } else {
+ if (phi < phi0) phi0 = phi;
+ if (phi > phi1) phi1 = phi;
+ }
+ if (antimeridian) {
+ if (lambda < lambda2) {
+ if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
+ } else {
+ if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
+ }
+ } else {
+ if (lambda1 >= lambda0$1) {
+ if (lambda < lambda0$1) lambda0$1 = lambda;
+ if (lambda > lambda1) lambda1 = lambda;
+ } else {
+ if (lambda > lambda2) {
+ if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
+ } else {
+ if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
+ }
+ }
+ }
+ } else {
+ ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
+ }
+ if (phi < phi0) phi0 = phi;
+ if (phi > phi1) phi1 = phi;
+ p0 = p, lambda2 = lambda;
+}
+
+function boundsLineStart() {
+ boundsStream.point = linePoint;
+}
+
+function boundsLineEnd() {
+ range[0] = lambda0$1, range[1] = lambda1;
+ boundsStream.point = boundsPoint;
+ p0 = null;
+}
+
+function boundsRingPoint(lambda, phi) {
+ if (p0) {
+ var delta = lambda - lambda2;
+ deltaSum.add(abs(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
+ } else {
+ lambda00$1 = lambda, phi00$1 = phi;
+ }
+ areaStream.point(lambda, phi);
+ linePoint(lambda, phi);
+}
+
+function boundsRingStart() {
+ areaStream.lineStart();
+}
+
+function boundsRingEnd() {
+ boundsRingPoint(lambda00$1, phi00$1);
+ areaStream.lineEnd();
+ if (abs(deltaSum) > epsilon) lambda0$1 = -(lambda1 = 180);
+ range[0] = lambda0$1, range[1] = lambda1;
+ p0 = null;
+}
+
+// Finds the left-right distance between two longitudes.
+// This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
+// the distance between ±180° to be 360°.
+function angle(lambda0, lambda1) {
+ return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
+}
+
+function rangeCompare(a, b) {
+ return a[0] - b[0];
+}
+
+function rangeContains(range, x) {
+ return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
+}
+
+function bounds(feature) {
+ var i, n, a, b, merged, deltaMax, delta;
+
+ phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
+ ranges = [];
+ geoStream(feature, boundsStream);
+
+ // First, sort ranges by their minimum longitudes.
+ if (n = ranges.length) {
+ ranges.sort(rangeCompare);
+
+ // Then, merge any ranges that overlap.
+ for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
+ b = ranges[i];
+ if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
+ if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
+ if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
+ } else {
+ merged.push(a = b);
+ }
+ }
+
+ // Finally, find the largest gap between the merged ranges.
+ // The final bounding box will be the inverse of this gap.
+ for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
+ b = merged[i];
+ if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
+ }
+ }
+
+ ranges = range = null;
+
+ return lambda0$1 === Infinity || phi0 === Infinity
+ ? [[NaN, NaN], [NaN, NaN]]
+ : [[lambda0$1, phi0], [lambda1, phi1]];
+}
+
+var W0, W1,
+ X0, Y0, Z0,
+ X1, Y1, Z1,
+ X2, Y2, Z2,
+ lambda00$2, phi00$2, // first point
+ x0, y0, z0; // previous point
+
+var centroidStream = {
+ sphere: noop,
+ point: centroidPoint,
+ lineStart: centroidLineStart,
+ lineEnd: centroidLineEnd,
+ polygonStart: function() {
+ centroidStream.lineStart = centroidRingStart;
+ centroidStream.lineEnd = centroidRingEnd;
+ },
+ polygonEnd: function() {
+ centroidStream.lineStart = centroidLineStart;
+ centroidStream.lineEnd = centroidLineEnd;
+ }
+};
+
+// Arithmetic mean of Cartesian vectors.
+function centroidPoint(lambda, phi) {
+ lambda *= radians, phi *= radians;
+ var cosPhi = cos(phi);
+ centroidPointCartesian(cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi));
+}
+
+function centroidPointCartesian(x, y, z) {
+ ++W0;
+ X0 += (x - X0) / W0;
+ Y0 += (y - Y0) / W0;
+ Z0 += (z - Z0) / W0;
+}
+
+function centroidLineStart() {
+ centroidStream.point = centroidLinePointFirst;
+}
+
+function centroidLinePointFirst(lambda, phi) {
+ lambda *= radians, phi *= radians;
+ var cosPhi = cos(phi);
+ x0 = cosPhi * cos(lambda);
+ y0 = cosPhi * sin(lambda);
+ z0 = sin(phi);
+ centroidStream.point = centroidLinePoint;
+ centroidPointCartesian(x0, y0, z0);
+}
+
+function centroidLinePoint(lambda, phi) {
+ lambda *= radians, phi *= radians;
+ var cosPhi = cos(phi),
+ x = cosPhi * cos(lambda),
+ y = cosPhi * sin(lambda),
+ z = sin(phi),
+ w = atan2(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);
+ W1 += w;
+ X1 += w * (x0 + (x0 = x));
+ Y1 += w * (y0 + (y0 = y));
+ Z1 += w * (z0 + (z0 = z));
+ centroidPointCartesian(x0, y0, z0);
+}
+
+function centroidLineEnd() {
+ centroidStream.point = centroidPoint;
+}
+
+// See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
+// J. Applied Mechanics 42, 239 (1975).
+function centroidRingStart() {
+ centroidStream.point = centroidRingPointFirst;
+}
+
+function centroidRingEnd() {
+ centroidRingPoint(lambda00$2, phi00$2);
+ centroidStream.point = centroidPoint;
+}
+
+function centroidRingPointFirst(lambda, phi) {
+ lambda00$2 = lambda, phi00$2 = phi;
+ lambda *= radians, phi *= radians;
+ centroidStream.point = centroidRingPoint;
+ var cosPhi = cos(phi);
+ x0 = cosPhi * cos(lambda);
+ y0 = cosPhi * sin(lambda);
+ z0 = sin(phi);
+ centroidPointCartesian(x0, y0, z0);
+}
+
+function centroidRingPoint(lambda, phi) {
+ lambda *= radians, phi *= radians;
+ var cosPhi = cos(phi),
+ x = cosPhi * cos(lambda),
+ y = cosPhi * sin(lambda),
+ z = sin(phi),
+ cx = y0 * z - z0 * y,
+ cy = z0 * x - x0 * z,
+ cz = x0 * y - y0 * x,
+ m = hypot(cx, cy, cz),
+ w = asin(m), // line weight = angle
+ v = m && -w / m; // area weight multiplier
+ X2.add(v * cx);
+ Y2.add(v * cy);
+ Z2.add(v * cz);
+ W1 += w;
+ X1 += w * (x0 + (x0 = x));
+ Y1 += w * (y0 + (y0 = y));
+ Z1 += w * (z0 + (z0 = z));
+ centroidPointCartesian(x0, y0, z0);
+}
+
+function centroid(object) {
+ W0 = W1 =
+ X0 = Y0 = Z0 =
+ X1 = Y1 = Z1 = 0;
+ X2 = new d3Array.Adder();
+ Y2 = new d3Array.Adder();
+ Z2 = new d3Array.Adder();
+ geoStream(object, centroidStream);
+
+ var x = +X2,
+ y = +Y2,
+ z = +Z2,
+ m = hypot(x, y, z);
+
+ // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
+ if (m < epsilon2) {
+ x = X1, y = Y1, z = Z1;
+ // If the feature has zero length, fall back to arithmetic mean of point vectors.
+ if (W1 < epsilon) x = X0, y = Y0, z = Z0;
+ m = hypot(x, y, z);
+ // If the feature still has an undefined ccentroid, then return.
+ if (m < epsilon2) return [NaN, NaN];
+ }
+
+ return [atan2(y, x) * degrees, asin(z / m) * degrees];
+}
+
+function constant(x) {
+ return function() {
+ return x;
+ };
+}
+
+function 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;
+}
+
+function rotationIdentity(lambda, phi) {
+ return [abs(lambda) > pi ? lambda + Math.round(-lambda / tau) * tau : lambda, phi];
+}
+
+rotationIdentity.invert = rotationIdentity;
+
+function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
+ return (deltaLambda %= tau) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
+ : rotationLambda(deltaLambda))
+ : (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma)
+ : rotationIdentity);
+}
+
+function forwardRotationLambda(deltaLambda) {
+ return function(lambda, phi) {
+ return lambda += deltaLambda, [lambda > pi ? lambda - tau : lambda < -pi ? lambda + tau : lambda, phi];
+ };
+}
+
+function rotationLambda(deltaLambda) {
+ var rotation = forwardRotationLambda(deltaLambda);
+ rotation.invert = forwardRotationLambda(-deltaLambda);
+ return rotation;
+}
+
+function rotationPhiGamma(deltaPhi, deltaGamma) {
+ var cosDeltaPhi = cos(deltaPhi),
+ sinDeltaPhi = sin(deltaPhi),
+ cosDeltaGamma = cos(deltaGamma),
+ sinDeltaGamma = sin(deltaGamma);
+
+ function rotation(lambda, phi) {
+ var cosPhi = cos(phi),
+ x = cos(lambda) * cosPhi,
+ y = sin(lambda) * cosPhi,
+ z = sin(phi),
+ k = z * cosDeltaPhi + x * sinDeltaPhi;
+ return [
+ atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
+ asin(k * cosDeltaGamma + y * sinDeltaGamma)
+ ];
+ }
+
+ rotation.invert = function(lambda, phi) {
+ var cosPhi = cos(phi),
+ x = cos(lambda) * cosPhi,
+ y = sin(lambda) * cosPhi,
+ z = sin(phi),
+ k = z * cosDeltaGamma - y * sinDeltaGamma;
+ return [
+ atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
+ asin(k * cosDeltaPhi - x * sinDeltaPhi)
+ ];
+ };
+
+ return rotation;
+}
+
+function rotation(rotate) {
+ rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
+
+ function forward(coordinates) {
+ coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
+ return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
+ }
+
+ forward.invert = function(coordinates) {
+ coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
+ return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
+ };
+
+ return forward;
+}
+
+// Generates a circle centered at [0°, 0°], with a given radius and precision.
+function circleStream(stream, radius, delta, direction, t0, t1) {
+ if (!delta) return;
+ var cosRadius = cos(radius),
+ sinRadius = sin(radius),
+ step = direction * delta;
+ if (t0 == null) {
+ t0 = radius + direction * tau;
+ t1 = radius - step / 2;
+ } else {
+ t0 = circleRadius(cosRadius, t0);
+ t1 = circleRadius(cosRadius, t1);
+ if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau;
+ }
+ for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
+ point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
+ stream.point(point[0], point[1]);
+ }
+}
+
+// Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
+function circleRadius(cosRadius, point) {
+ point = cartesian(point), point[0] -= cosRadius;
+ cartesianNormalizeInPlace(point);
+ var radius = acos(-point[1]);
+ return ((-point[2] < 0 ? -radius : radius) + tau - epsilon) % tau;
+}
+
+function circle() {
+ var center = constant([0, 0]),
+ radius = constant(90),
+ precision = constant(6),
+ ring,
+ rotate,
+ stream = {point: point};
+
+ function point(x, y) {
+ ring.push(x = rotate(x, y));
+ x[0] *= degrees, x[1] *= degrees;
+ }
+
+ function circle() {
+ var c = center.apply(this, arguments),
+ r = radius.apply(this, arguments) * radians,
+ p = precision.apply(this, arguments) * radians;
+ ring = [];
+ rotate = rotateRadians(-c[0] * radians, -c[1] * radians, 0).invert;
+ circleStream(stream, r, p, 1);
+ c = {type: "Polygon", coordinates: [ring]};
+ ring = rotate = null;
+ return c;
+ }
+
+ circle.center = function(_) {
+ return arguments.length ? (center = typeof _ === "function" ? _ : constant([+_[0], +_[1]]), circle) : center;
+ };
+
+ circle.radius = function(_) {
+ return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), circle) : radius;
+ };
+
+ circle.precision = function(_) {
+ return arguments.length ? (precision = typeof _ === "function" ? _ : constant(+_), circle) : precision;
+ };
+
+ return circle;
+}
+
+function clipBuffer() {
+ var lines = [],
+ line;
+ return {
+ point: function(x, y, m) {
+ line.push([x, y, m]);
+ },
+ lineStart: function() {
+ lines.push(line = []);
+ },
+ lineEnd: noop,
+ rejoin: function() {
+ if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
+ },
+ result: function() {
+ var result = lines;
+ lines = [];
+ line = null;
+ return result;
+ }
+ };
+}
+
+function pointEqual(a, b) {
+ return abs(a[0] - b[0]) < epsilon && abs(a[1] - b[1]) < epsilon;
+}
+
+function Intersection(point, points, other, entry) {
+ this.x = point;
+ this.z = points;
+ this.o = other; // another intersection
+ this.e = entry; // is an entry?
+ this.v = false; // visited
+ this.n = this.p = null; // next & previous
+}
+
+// A generalized polygon clipping algorithm: given a polygon that has been cut
+// into its visible line segments, and rejoins the segments by interpolating
+// along the clip edge.
+function clipRejoin(segments, compareIntersection, startInside, interpolate, stream) {
+ var subject = [],
+ clip = [],
+ i,
+ n;
+
+ segments.forEach(function(segment) {
+ if ((n = segment.length - 1) <= 0) return;
+ var n, p0 = segment[0], p1 = segment[n], x;
+
+ if (pointEqual(p0, p1)) {
+ if (!p0[2] && !p1[2]) {
+ stream.lineStart();
+ for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
+ stream.lineEnd();
+ return;
+ }
+ // handle degenerate cases by moving the point
+ p1[0] += 2 * epsilon;
+ }
+
+ subject.push(x = new Intersection(p0, segment, null, true));
+ clip.push(x.o = new Intersection(p0, null, x, false));
+ subject.push(x = new Intersection(p1, segment, null, false));
+ clip.push(x.o = new Intersection(p1, null, x, true));
+ });
+
+ if (!subject.length) return;
+
+ clip.sort(compareIntersection);
+ link(subject);
+ link(clip);
+
+ for (i = 0, n = clip.length; i < n; ++i) {
+ clip[i].e = startInside = !startInside;
+ }
+
+ var start = subject[0],
+ points,
+ point;
+
+ while (1) {
+ // Find first unvisited intersection.
+ var current = start,
+ isSubject = true;
+ while (current.v) if ((current = current.n) === start) return;
+ points = current.z;
+ stream.lineStart();
+ do {
+ current.v = current.o.v = true;
+ if (current.e) {
+ if (isSubject) {
+ for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]);
+ } else {
+ interpolate(current.x, current.n.x, 1, stream);
+ }
+ current = current.n;
+ } else {
+ if (isSubject) {
+ points = current.p.z;
+ for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]);
+ } else {
+ interpolate(current.x, current.p.x, -1, stream);
+ }
+ current = current.p;
+ }
+ current = current.o;
+ points = current.z;
+ isSubject = !isSubject;
+ } while (!current.v);
+ stream.lineEnd();
+ }
+}
+
+function link(array) {
+ if (!(n = array.length)) return;
+ var n,
+ i = 0,
+ a = array[0],
+ b;
+ while (++i < n) {
+ a.n = b = array[i];
+ b.p = a;
+ a = b;
+ }
+ a.n = b = array[0];
+ b.p = a;
+}
+
+function longitude(point) {
+ if (abs(point[0]) <= pi)
+ return point[0];
+ else
+ return sign(point[0]) * ((abs(point[0]) + pi) % tau - pi);
+}
+
+function polygonContains(polygon, point) {
+ var lambda = longitude(point),
+ phi = point[1],
+ sinPhi = sin(phi),
+ normal = [sin(lambda), -cos(lambda), 0],
+ angle = 0,
+ winding = 0;
+
+ var sum = new d3Array.Adder();
+
+ if (sinPhi === 1) phi = halfPi + epsilon;
+ else if (sinPhi === -1) phi = -halfPi - epsilon;
+
+ for (var i = 0, n = polygon.length; i < n; ++i) {
+ if (!(m = (ring = polygon[i]).length)) continue;
+ var ring,
+ m,
+ point0 = ring[m - 1],
+ lambda0 = longitude(point0),
+ phi0 = point0[1] / 2 + quarterPi,
+ sinPhi0 = sin(phi0),
+ cosPhi0 = cos(phi0);
+
+ for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
+ var point1 = ring[j],
+ lambda1 = longitude(point1),
+ phi1 = point1[1] / 2 + quarterPi,
+ sinPhi1 = sin(phi1),
+ cosPhi1 = cos(phi1),
+ delta = lambda1 - lambda0,
+ sign = delta >= 0 ? 1 : -1,
+ absDelta = sign * delta,
+ antimeridian = absDelta > pi,
+ k = sinPhi0 * sinPhi1;
+
+ sum.add(atan2(k * sign * sin(absDelta), cosPhi0 * cosPhi1 + k * cos(absDelta)));
+ angle += antimeridian ? delta + sign * tau : delta;
+
+ // Are the longitudes either side of the point’s meridian (lambda),
+ // and are the latitudes smaller than the parallel (phi)?
+ if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
+ var arc = cartesianCross(cartesian(point0), cartesian(point1));
+ cartesianNormalizeInPlace(arc);
+ var intersection = cartesianCross(normal, arc);
+ cartesianNormalizeInPlace(intersection);
+ var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
+ if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
+ winding += antimeridian ^ delta >= 0 ? 1 : -1;
+ }
+ }
+ }
+ }
+
+ // First, determine whether the South pole is inside or outside:
+ //
+ // It is inside if:
+ // * the polygon winds around it in a clockwise direction.
+ // * the polygon does not (cumulatively) wind around it, but has a negative
+ // (counter-clockwise) area.
+ //
+ // Second, count the (signed) number of times a segment crosses a lambda
+ // from the point to the South pole. If it is zero, then the point is the
+ // same side as the South pole.
+
+ return (angle < -epsilon || angle < epsilon && sum < -epsilon2) ^ (winding & 1);
+}
+
+function clip(pointVisible, clipLine, interpolate, start) {
+ return function(sink) {
+ var line = clipLine(sink),
+ ringBuffer = clipBuffer(),
+ ringSink = clipLine(ringBuffer),
+ polygonStarted = false,
+ polygon,
+ segments,
+ ring;
+
+ var clip = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ clip.point = pointRing;
+ clip.lineStart = ringStart;
+ clip.lineEnd = ringEnd;
+ segments = [];
+ polygon = [];
+ },
+ polygonEnd: function() {
+ clip.point = point;
+ clip.lineStart = lineStart;
+ clip.lineEnd = lineEnd;
+ segments = d3Array.merge(segments);
+ var startInside = polygonContains(polygon, start);
+ if (segments.length) {
+ if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
+ clipRejoin(segments, compareIntersection, startInside, interpolate, sink);
+ } else if (startInside) {
+ if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
+ sink.lineStart();
+ interpolate(null, null, 1, sink);
+ sink.lineEnd();
+ }
+ if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
+ segments = polygon = null;
+ },
+ sphere: function() {
+ sink.polygonStart();
+ sink.lineStart();
+ interpolate(null, null, 1, sink);
+ sink.lineEnd();
+ sink.polygonEnd();
+ }
+ };
+
+ function point(lambda, phi) {
+ if (pointVisible(lambda, phi)) sink.point(lambda, phi);
+ }
+
+ function pointLine(lambda, phi) {
+ line.point(lambda, phi);
+ }
+
+ function lineStart() {
+ clip.point = pointLine;
+ line.lineStart();
+ }
+
+ function lineEnd() {
+ clip.point = point;
+ line.lineEnd();
+ }
+
+ function pointRing(lambda, phi) {
+ ring.push([lambda, phi]);
+ ringSink.point(lambda, phi);
+ }
+
+ function ringStart() {
+ ringSink.lineStart();
+ ring = [];
+ }
+
+ function ringEnd() {
+ pointRing(ring[0][0], ring[0][1]);
+ ringSink.lineEnd();
+
+ var clean = ringSink.clean(),
+ ringSegments = ringBuffer.result(),
+ i, n = ringSegments.length, m,
+ segment,
+ point;
+
+ ring.pop();
+ polygon.push(ring);
+ ring = null;
+
+ if (!n) return;
+
+ // No intersections.
+ if (clean & 1) {
+ segment = ringSegments[0];
+ if ((m = segment.length - 1) > 0) {
+ if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
+ sink.lineStart();
+ for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]);
+ sink.lineEnd();
+ }
+ return;
+ }
+
+ // Rejoin connected segments.
+ // TODO reuse ringBuffer.rejoin()?
+ if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
+
+ segments.push(ringSegments.filter(validSegment));
+ }
+
+ return clip;
+ };
+}
+
+function validSegment(segment) {
+ return segment.length > 1;
+}
+
+// Intersections are sorted along the clip edge. For both antimeridian cutting
+// and circle clipping, the same comparison is used.
+function compareIntersection(a, b) {
+ return ((a = a.x)[0] < 0 ? a[1] - halfPi - epsilon : halfPi - a[1])
+ - ((b = b.x)[0] < 0 ? b[1] - halfPi - epsilon : halfPi - b[1]);
+}
+
+var clipAntimeridian = clip(
+ function() { return true; },
+ clipAntimeridianLine,
+ clipAntimeridianInterpolate,
+ [-pi, -halfPi]
+);
+
+// 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 clipAntimeridianLine(stream) {
+ var lambda0 = NaN,
+ phi0 = NaN,
+ sign0 = NaN,
+ clean; // no intersections
+
+ return {
+ lineStart: function() {
+ stream.lineStart();
+ clean = 1;
+ },
+ point: function(lambda1, phi1) {
+ var sign1 = lambda1 > 0 ? pi : -pi,
+ delta = abs(lambda1 - lambda0);
+ if (abs(delta - pi) < epsilon) { // line crosses a pole
+ stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi : -halfPi);
+ stream.point(sign0, phi0);
+ stream.lineEnd();
+ stream.lineStart();
+ stream.point(sign1, phi0);
+ stream.point(lambda1, phi0);
+ clean = 0;
+ } else if (sign0 !== sign1 && delta >= pi) { // line crosses antimeridian
+ if (abs(lambda0 - sign0) < epsilon) lambda0 -= sign0 * epsilon; // handle degeneracies
+ if (abs(lambda1 - sign1) < epsilon) lambda1 -= sign1 * epsilon;
+ phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
+ stream.point(sign0, phi0);
+ stream.lineEnd();
+ stream.lineStart();
+ stream.point(sign1, phi0);
+ clean = 0;
+ }
+ stream.point(lambda0 = lambda1, phi0 = phi1);
+ sign0 = sign1;
+ },
+ lineEnd: function() {
+ stream.lineEnd();
+ lambda0 = phi0 = NaN;
+ },
+ clean: function() {
+ return 2 - clean; // if intersections, rejoin first and last segments
+ }
+ };
+}
+
+function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
+ var cosPhi0,
+ cosPhi1,
+ sinLambda0Lambda1 = sin(lambda0 - lambda1);
+ return abs(sinLambda0Lambda1) > epsilon
+ ? atan((sin(phi0) * (cosPhi1 = cos(phi1)) * sin(lambda1)
+ - sin(phi1) * (cosPhi0 = cos(phi0)) * sin(lambda0))
+ / (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
+ : (phi0 + phi1) / 2;
+}
+
+function clipAntimeridianInterpolate(from, to, direction, stream) {
+ var phi;
+ if (from == null) {
+ phi = direction * halfPi;
+ stream.point(-pi, phi);
+ stream.point(0, phi);
+ stream.point(pi, phi);
+ stream.point(pi, 0);
+ stream.point(pi, -phi);
+ stream.point(0, -phi);
+ stream.point(-pi, -phi);
+ stream.point(-pi, 0);
+ stream.point(-pi, phi);
+ } else if (abs(from[0] - to[0]) > epsilon) {
+ var lambda = from[0] < to[0] ? pi : -pi;
+ phi = direction * lambda / 2;
+ stream.point(-lambda, phi);
+ stream.point(0, phi);
+ stream.point(lambda, phi);
+ } else {
+ stream.point(to[0], to[1]);
+ }
+}
+
+function clipCircle(radius) {
+ var cr = cos(radius),
+ delta = 6 * radians,
+ smallRadius = cr > 0,
+ notHemisphere = abs(cr) > epsilon; // TODO optimise for this common case
+
+ function interpolate(from, to, direction, stream) {
+ circleStream(stream, radius, delta, direction, from, to);
+ }
+
+ function visible(lambda, phi) {
+ return cos(lambda) * cos(phi) > 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(stream) {
+ 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(lambda, phi) {
+ var point1 = [lambda, phi],
+ point2,
+ v = visible(lambda, phi),
+ c = smallRadius
+ ? v ? 0 : code(lambda, phi)
+ : v ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
+ if (!point0 && (v00 = v0 = v)) stream.lineStart();
+ if (v !== v0) {
+ point2 = intersect(point0, point1);
+ if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2))
+ point1[2] = 1;
+ }
+ if (v !== v0) {
+ clean = 0;
+ if (v) {
+ // outside going in
+ stream.lineStart();
+ point2 = intersect(point1, point0);
+ stream.point(point2[0], point2[1]);
+ } else {
+ // inside going out
+ point2 = intersect(point0, point1);
+ stream.point(point2[0], point2[1], 2);
+ stream.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) {
+ stream.lineStart();
+ stream.point(t[0][0], t[0][1]);
+ stream.point(t[1][0], t[1][1]);
+ stream.lineEnd();
+ } else {
+ stream.point(t[1][0], t[1][1]);
+ stream.lineEnd();
+ stream.lineStart();
+ stream.point(t[0][0], t[0][1], 3);
+ }
+ }
+ }
+ if (v && (!point0 || !pointEqual(point0, point1))) {
+ stream.point(point1[0], point1[1]);
+ }
+ point0 = point1, v0 = v, c0 = c;
+ },
+ lineEnd: function() {
+ if (v0) stream.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 = cartesian(a),
+ pb = 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 = cartesianCross(pa, pb),
+ n2n2 = cartesianDot(n2, n2),
+ n1n2 = n2[0], // 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 = cartesianCross(n1, n2),
+ A = cartesianScale(n1, c1),
+ B = cartesianScale(n2, c2);
+ cartesianAddInPlace(A, B);
+
+ // Solve |p(t)|^2 = 1.
+ var u = n1xn2,
+ w = cartesianDot(A, u),
+ uu = cartesianDot(u, u),
+ t2 = w * w - uu * (cartesianDot(A, A) - 1);
+
+ if (t2 < 0) return;
+
+ var t = sqrt(t2),
+ q = cartesianScale(u, (-w - t) / uu);
+ cartesianAddInPlace(q, A);
+ q = spherical(q);
+
+ if (!two) return q;
+
+ // Two intersection points.
+ var lambda0 = a[0],
+ lambda1 = b[0],
+ phi0 = a[1],
+ phi1 = b[1],
+ z;
+
+ if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
+
+ var delta = lambda1 - lambda0,
+ polar = abs(delta - pi) < epsilon,
+ meridian = polar || delta < epsilon;
+
+ if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z;
+
+ // Check that the first point is between a and b.
+ if (meridian
+ ? polar
+ ? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon ? phi0 : phi1)
+ : phi0 <= q[1] && q[1] <= phi1
+ : delta > pi ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
+ var q1 = cartesianScale(u, (-w + t) / uu);
+ cartesianAddInPlace(q1, A);
+ return [q, spherical(q1)];
+ }
+ }
+
+ // Generates a 4-bit vector representing the location of a point relative to
+ // the small circle's bounding box.
+ function code(lambda, phi) {
+ var r = smallRadius ? radius : pi - radius,
+ code = 0;
+ if (lambda < -r) code |= 1; // left
+ else if (lambda > r) code |= 2; // right
+ if (phi < -r) code |= 4; // below
+ else if (phi > r) code |= 8; // above
+ return code;
+ }
+
+ return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]);
+}
+
+function clipLine(a, b, x0, y0, x1, y1) {
+ var ax = a[0],
+ ay = a[1],
+ bx = b[0],
+ by = b[1],
+ t0 = 0,
+ t1 = 1,
+ dx = bx - ax,
+ dy = by - ay,
+ r;
+
+ r = x0 - ax;
+ if (!dx && r > 0) return;
+ r /= dx;
+ if (dx < 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ } else if (dx > 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ }
+
+ r = x1 - ax;
+ if (!dx && r < 0) return;
+ r /= dx;
+ if (dx < 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ } else if (dx > 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ }
+
+ r = y0 - ay;
+ if (!dy && r > 0) return;
+ r /= dy;
+ if (dy < 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ } else if (dy > 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ }
+
+ r = y1 - ay;
+ if (!dy && r < 0) return;
+ r /= dy;
+ if (dy < 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ } else if (dy > 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ }
+
+ if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
+ if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
+ return true;
+}
+
+var clipMax = 1e9, clipMin = -clipMax;
+
+// TODO Use d3-polygon’s polygonContains here for the ring check?
+// TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
+
+function clipRectangle(x0, y0, x1, y1) {
+
+ function visible(x, y) {
+ return x0 <= x && x <= x1 && y0 <= y && y <= y1;
+ }
+
+ function interpolate(from, to, direction, stream) {
+ var a = 0, a1 = 0;
+ if (from == null
+ || (a = corner(from, direction)) !== (a1 = corner(to, direction))
+ || comparePoint(from, to) < 0 ^ direction > 0) {
+ do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
+ while ((a = (a + direction + 4) % 4) !== a1);
+ } else {
+ stream.point(to[0], to[1]);
+ }
+ }
+
+ function corner(p, direction) {
+ return abs(p[0] - x0) < epsilon ? direction > 0 ? 0 : 3
+ : abs(p[0] - x1) < epsilon ? direction > 0 ? 2 : 1
+ : abs(p[1] - y0) < epsilon ? direction > 0 ? 1 : 0
+ : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
+ }
+
+ function compareIntersection(a, b) {
+ return comparePoint(a.x, b.x);
+ }
+
+ function comparePoint(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];
+ }
+
+ return function(stream) {
+ var activeStream = stream,
+ bufferStream = clipBuffer(),
+ segments,
+ polygon,
+ ring,
+ x__, y__, v__, // first point
+ x_, y_, v_, // previous point
+ first,
+ clean;
+
+ var clipStream = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: polygonStart,
+ polygonEnd: polygonEnd
+ };
+
+ function point(x, y) {
+ if (visible(x, y)) activeStream.point(x, y);
+ }
+
+ function polygonInside() {
+ var winding = 0;
+
+ for (var i = 0, n = polygon.length; i < n; ++i) {
+ for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
+ a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
+ if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; }
+ else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; }
+ }
+ }
+
+ return winding;
+ }
+
+ // Buffer geometry within a polygon and then clip it en masse.
+ function polygonStart() {
+ activeStream = bufferStream, segments = [], polygon = [], clean = true;
+ }
+
+ function polygonEnd() {
+ var startInside = polygonInside(),
+ cleanInside = clean && startInside,
+ visible = (segments = d3Array.merge(segments)).length;
+ if (cleanInside || visible) {
+ stream.polygonStart();
+ if (cleanInside) {
+ stream.lineStart();
+ interpolate(null, null, 1, stream);
+ stream.lineEnd();
+ }
+ if (visible) {
+ clipRejoin(segments, compareIntersection, startInside, interpolate, stream);
+ }
+ stream.polygonEnd();
+ }
+ activeStream = stream, segments = polygon = ring = null;
+ }
+
+ function lineStart() {
+ clipStream.point = linePoint;
+ if (polygon) polygon.push(ring = []);
+ first = true;
+ v_ = false;
+ x_ = y_ = NaN;
+ }
+
+ // TODO rather than special-case polygons, simply handle them separately.
+ // Ideally, coincident intersection points should be jittered to avoid
+ // clipping issues.
+ function lineEnd() {
+ if (segments) {
+ linePoint(x__, y__);
+ if (v__ && v_) bufferStream.rejoin();
+ segments.push(bufferStream.result());
+ }
+ clipStream.point = point;
+ if (v_) activeStream.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) {
+ activeStream.lineStart();
+ activeStream.point(x, y);
+ }
+ } else {
+ if (v && v_) activeStream.point(x, y);
+ else {
+ var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
+ b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
+ if (clipLine(a, b, x0, y0, x1, y1)) {
+ if (!v_) {
+ activeStream.lineStart();
+ activeStream.point(a[0], a[1]);
+ }
+ activeStream.point(b[0], b[1]);
+ if (!v) activeStream.lineEnd();
+ clean = false;
+ } else if (v) {
+ activeStream.lineStart();
+ activeStream.point(x, y);
+ clean = false;
+ }
+ }
+ }
+ x_ = x, y_ = y, v_ = v;
+ }
+
+ return clipStream;
+ };
+}
+
+function extent() {
+ var x0 = 0,
+ y0 = 0,
+ x1 = 960,
+ y1 = 500,
+ cache,
+ cacheStream,
+ clip;
+
+ return clip = {
+ stream: function(stream) {
+ return cache && cacheStream === stream ? cache : cache = clipRectangle(x0, y0, x1, y1)(cacheStream = stream);
+ },
+ extent: function(_) {
+ return arguments.length ? (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1], cache = cacheStream = null, clip) : [[x0, y0], [x1, y1]];
+ }
+ };
+}
+
+var lengthSum,
+ lambda0$2,
+ sinPhi0$1,
+ cosPhi0$1;
+
+var lengthStream = {
+ sphere: noop,
+ point: noop,
+ lineStart: lengthLineStart,
+ lineEnd: noop,
+ polygonStart: noop,
+ polygonEnd: noop
+};
+
+function lengthLineStart() {
+ lengthStream.point = lengthPointFirst;
+ lengthStream.lineEnd = lengthLineEnd;
+}
+
+function lengthLineEnd() {
+ lengthStream.point = lengthStream.lineEnd = noop;
+}
+
+function lengthPointFirst(lambda, phi) {
+ lambda *= radians, phi *= radians;
+ lambda0$2 = lambda, sinPhi0$1 = sin(phi), cosPhi0$1 = cos(phi);
+ lengthStream.point = lengthPoint;
+}
+
+function lengthPoint(lambda, phi) {
+ lambda *= radians, phi *= radians;
+ var sinPhi = sin(phi),
+ cosPhi = cos(phi),
+ delta = abs(lambda - lambda0$2),
+ cosDelta = cos(delta),
+ sinDelta = sin(delta),
+ x = cosPhi * sinDelta,
+ y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
+ z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
+ lengthSum.add(atan2(sqrt(x * x + y * y), z));
+ lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
+}
+
+function length(object) {
+ lengthSum = new d3Array.Adder();
+ geoStream(object, lengthStream);
+ return +lengthSum;
+}
+
+var coordinates = [null, null],
+ object = {type: "LineString", coordinates: coordinates};
+
+function distance(a, b) {
+ coordinates[0] = a;
+ coordinates[1] = b;
+ return length(object);
+}
+
+var containsObjectType = {
+ Feature: function(object, point) {
+ return containsGeometry(object.geometry, point);
+ },
+ FeatureCollection: function(object, point) {
+ var features = object.features, i = -1, n = features.length;
+ while (++i < n) if (containsGeometry(features[i].geometry, point)) return true;
+ return false;
+ }
+};
+
+var containsGeometryType = {
+ Sphere: function() {
+ return true;
+ },
+ Point: function(object, point) {
+ return containsPoint(object.coordinates, point);
+ },
+ MultiPoint: function(object, point) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) if (containsPoint(coordinates[i], point)) return true;
+ return false;
+ },
+ LineString: function(object, point) {
+ return containsLine(object.coordinates, point);
+ },
+ MultiLineString: function(object, point) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) if (containsLine(coordinates[i], point)) return true;
+ return false;
+ },
+ Polygon: function(object, point) {
+ return containsPolygon(object.coordinates, point);
+ },
+ MultiPolygon: function(object, point) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) if (containsPolygon(coordinates[i], point)) return true;
+ return false;
+ },
+ GeometryCollection: function(object, point) {
+ var geometries = object.geometries, i = -1, n = geometries.length;
+ while (++i < n) if (containsGeometry(geometries[i], point)) return true;
+ return false;
+ }
+};
+
+function containsGeometry(geometry, point) {
+ return geometry && containsGeometryType.hasOwnProperty(geometry.type)
+ ? containsGeometryType[geometry.type](geometry, point)
+ : false;
+}
+
+function containsPoint(coordinates, point) {
+ return distance(coordinates, point) === 0;
+}
+
+function containsLine(coordinates, point) {
+ var ao, bo, ab;
+ for (var i = 0, n = coordinates.length; i < n; i++) {
+ bo = distance(coordinates[i], point);
+ if (bo === 0) return true;
+ if (i > 0) {
+ ab = distance(coordinates[i], coordinates[i - 1]);
+ if (
+ ab > 0 &&
+ ao <= ab &&
+ bo <= ab &&
+ (ao + bo - ab) * (1 - Math.pow((ao - bo) / ab, 2)) < epsilon2 * ab
+ )
+ return true;
+ }
+ ao = bo;
+ }
+ return false;
+}
+
+function containsPolygon(coordinates, point) {
+ return !!polygonContains(coordinates.map(ringRadians), pointRadians(point));
+}
+
+function ringRadians(ring) {
+ return ring = ring.map(pointRadians), ring.pop(), ring;
+}
+
+function pointRadians(point) {
+ return [point[0] * radians, point[1] * radians];
+}
+
+function contains(object, point) {
+ return (object && containsObjectType.hasOwnProperty(object.type)
+ ? containsObjectType[object.type]
+ : containsGeometry)(object, point);
+}
+
+function graticuleX(y0, y1, dy) {
+ var y = d3Array.range(y0, y1 - epsilon, dy).concat(y1);
+ return function(x) { return y.map(function(y) { return [x, y]; }); };
+}
+
+function graticuleY(x0, x1, dx) {
+ var x = d3Array.range(x0, x1 - epsilon, dx).concat(x1);
+ return function(y) { return x.map(function(x) { return [x, y]; }); };
+}
+
+function graticule() {
+ 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 d3Array.range(ceil(X0 / DX) * DX, X1, DX).map(X)
+ .concat(d3Array.range(ceil(Y0 / DY) * DY, Y1, DY).map(Y))
+ .concat(d3Array.range(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs(x % DX) > epsilon; }).map(x))
+ .concat(d3Array.range(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs(y % DY) > epsilon; }).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.extentMinor();
+ return graticule.extentMajor(_).extentMinor(_);
+ };
+
+ graticule.extentMajor = 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.extentMinor = 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.stepMinor();
+ return graticule.stepMajor(_).stepMinor(_);
+ };
+
+ graticule.stepMajor = function(_) {
+ if (!arguments.length) return [DX, DY];
+ DX = +_[0], DY = +_[1];
+ return graticule;
+ };
+
+ graticule.stepMinor = function(_) {
+ if (!arguments.length) return [dx, dy];
+ dx = +_[0], dy = +_[1];
+ return graticule;
+ };
+
+ graticule.precision = function(_) {
+ if (!arguments.length) return precision;
+ precision = +_;
+ x = graticuleX(y0, y1, 90);
+ y = graticuleY(x0, x1, precision);
+ X = graticuleX(Y0, Y1, 90);
+ Y = graticuleY(X0, X1, precision);
+ return graticule;
+ };
+
+ return graticule
+ .extentMajor([[-180, -90 + epsilon], [180, 90 - epsilon]])
+ .extentMinor([[-180, -80 - epsilon], [180, 80 + epsilon]]);
+}
+
+function graticule10() {
+ return graticule()();
+}
+
+function interpolate(a, b) {
+ var x0 = a[0] * radians,
+ y0 = a[1] * radians,
+ x1 = b[0] * radians,
+ y1 = b[1] * radians,
+ cy0 = cos(y0),
+ sy0 = sin(y0),
+ cy1 = cos(y1),
+ sy1 = sin(y1),
+ kx0 = cy0 * cos(x0),
+ ky0 = cy0 * sin(x0),
+ kx1 = cy1 * cos(x1),
+ ky1 = cy1 * sin(x1),
+ d = 2 * asin(sqrt(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
+ k = sin(d);
+
+ var interpolate = d ? function(t) {
+ var B = sin(t *= d) / k,
+ A = sin(d - t) / k,
+ x = A * kx0 + B * kx1,
+ y = A * ky0 + B * ky1,
+ z = A * sy0 + B * sy1;
+ return [
+ atan2(y, x) * degrees,
+ atan2(z, sqrt(x * x + y * y)) * degrees
+ ];
+ } : function() {
+ return [x0 * degrees, y0 * degrees];
+ };
+
+ interpolate.distance = d;
+
+ return interpolate;
+}
+
+var identity = x => x;
+
+var areaSum$1 = new d3Array.Adder(),
+ areaRingSum$1 = new d3Array.Adder(),
+ x00,
+ y00,
+ x0$1,
+ y0$1;
+
+var areaStream$1 = {
+ point: noop,
+ lineStart: noop,
+ lineEnd: noop,
+ polygonStart: function() {
+ areaStream$1.lineStart = areaRingStart$1;
+ areaStream$1.lineEnd = areaRingEnd$1;
+ },
+ polygonEnd: function() {
+ areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop;
+ areaSum$1.add(abs(areaRingSum$1));
+ areaRingSum$1 = new d3Array.Adder();
+ },
+ result: function() {
+ var area = areaSum$1 / 2;
+ areaSum$1 = new d3Array.Adder();
+ return area;
+ }
+};
+
+function areaRingStart$1() {
+ areaStream$1.point = areaPointFirst$1;
+}
+
+function areaPointFirst$1(x, y) {
+ areaStream$1.point = areaPoint$1;
+ x00 = x0$1 = x, y00 = y0$1 = y;
+}
+
+function areaPoint$1(x, y) {
+ areaRingSum$1.add(y0$1 * x - x0$1 * y);
+ x0$1 = x, y0$1 = y;
+}
+
+function areaRingEnd$1() {
+ areaPoint$1(x00, y00);
+}
+
+var x0$2 = Infinity,
+ y0$2 = x0$2,
+ x1 = -x0$2,
+ y1 = x1;
+
+var boundsStream$1 = {
+ point: boundsPoint$1,
+ lineStart: noop,
+ lineEnd: noop,
+ polygonStart: noop,
+ polygonEnd: noop,
+ result: function() {
+ var bounds = [[x0$2, y0$2], [x1, y1]];
+ x1 = y1 = -(y0$2 = x0$2 = Infinity);
+ return bounds;
+ }
+};
+
+function boundsPoint$1(x, y) {
+ if (x < x0$2) x0$2 = x;
+ if (x > x1) x1 = x;
+ if (y < y0$2) y0$2 = y;
+ if (y > y1) y1 = y;
+}
+
+// TODO Enforce positive area for exterior, negative area for interior?
+
+var X0$1 = 0,
+ Y0$1 = 0,
+ Z0$1 = 0,
+ X1$1 = 0,
+ Y1$1 = 0,
+ Z1$1 = 0,
+ X2$1 = 0,
+ Y2$1 = 0,
+ Z2$1 = 0,
+ x00$1,
+ y00$1,
+ x0$3,
+ y0$3;
+
+var centroidStream$1 = {
+ point: centroidPoint$1,
+ lineStart: centroidLineStart$1,
+ lineEnd: centroidLineEnd$1,
+ polygonStart: function() {
+ centroidStream$1.lineStart = centroidRingStart$1;
+ centroidStream$1.lineEnd = centroidRingEnd$1;
+ },
+ polygonEnd: function() {
+ centroidStream$1.point = centroidPoint$1;
+ centroidStream$1.lineStart = centroidLineStart$1;
+ centroidStream$1.lineEnd = centroidLineEnd$1;
+ },
+ result: function() {
+ var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1]
+ : Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1]
+ : Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1]
+ : [NaN, NaN];
+ X0$1 = Y0$1 = Z0$1 =
+ X1$1 = Y1$1 = Z1$1 =
+ X2$1 = Y2$1 = Z2$1 = 0;
+ return centroid;
+ }
+};
+
+function centroidPoint$1(x, y) {
+ X0$1 += x;
+ Y0$1 += y;
+ ++Z0$1;
+}
+
+function centroidLineStart$1() {
+ centroidStream$1.point = centroidPointFirstLine;
+}
+
+function centroidPointFirstLine(x, y) {
+ centroidStream$1.point = centroidPointLine;
+ centroidPoint$1(x0$3 = x, y0$3 = y);
+}
+
+function centroidPointLine(x, y) {
+ var dx = x - x0$3, dy = y - y0$3, z = sqrt(dx * dx + dy * dy);
+ X1$1 += z * (x0$3 + x) / 2;
+ Y1$1 += z * (y0$3 + y) / 2;
+ Z1$1 += z;
+ centroidPoint$1(x0$3 = x, y0$3 = y);
+}
+
+function centroidLineEnd$1() {
+ centroidStream$1.point = centroidPoint$1;
+}
+
+function centroidRingStart$1() {
+ centroidStream$1.point = centroidPointFirstRing;
+}
+
+function centroidRingEnd$1() {
+ centroidPointRing(x00$1, y00$1);
+}
+
+function centroidPointFirstRing(x, y) {
+ centroidStream$1.point = centroidPointRing;
+ centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
+}
+
+function centroidPointRing(x, y) {
+ var dx = x - x0$3,
+ dy = y - y0$3,
+ z = sqrt(dx * dx + dy * dy);
+
+ X1$1 += z * (x0$3 + x) / 2;
+ Y1$1 += z * (y0$3 + y) / 2;
+ Z1$1 += z;
+
+ z = y0$3 * x - x0$3 * y;
+ X2$1 += z * (x0$3 + x);
+ Y2$1 += z * (y0$3 + y);
+ Z2$1 += z * 3;
+ centroidPoint$1(x0$3 = x, y0$3 = y);
+}
+
+function PathContext(context) {
+ this._context = context;
+}
+
+PathContext.prototype = {
+ _radius: 4.5,
+ pointRadius: function(_) {
+ return this._radius = _, this;
+ },
+ polygonStart: function() {
+ this._line = 0;
+ },
+ polygonEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._line === 0) this._context.closePath();
+ this._point = NaN;
+ },
+ point: function(x, y) {
+ switch (this._point) {
+ case 0: {
+ this._context.moveTo(x, y);
+ this._point = 1;
+ break;
+ }
+ case 1: {
+ this._context.lineTo(x, y);
+ break;
+ }
+ default: {
+ this._context.moveTo(x + this._radius, y);
+ this._context.arc(x, y, this._radius, 0, tau);
+ break;
+ }
+ }
+ },
+ result: noop
+};
+
+var lengthSum$1 = new d3Array.Adder(),
+ lengthRing,
+ x00$2,
+ y00$2,
+ x0$4,
+ y0$4;
+
+var lengthStream$1 = {
+ point: noop,
+ lineStart: function() {
+ lengthStream$1.point = lengthPointFirst$1;
+ },
+ lineEnd: function() {
+ if (lengthRing) lengthPoint$1(x00$2, y00$2);
+ lengthStream$1.point = noop;
+ },
+ polygonStart: function() {
+ lengthRing = true;
+ },
+ polygonEnd: function() {
+ lengthRing = null;
+ },
+ result: function() {
+ var length = +lengthSum$1;
+ lengthSum$1 = new d3Array.Adder();
+ return length;
+ }
+};
+
+function lengthPointFirst$1(x, y) {
+ lengthStream$1.point = lengthPoint$1;
+ x00$2 = x0$4 = x, y00$2 = y0$4 = y;
+}
+
+function lengthPoint$1(x, y) {
+ x0$4 -= x, y0$4 -= y;
+ lengthSum$1.add(sqrt(x0$4 * x0$4 + y0$4 * y0$4));
+ x0$4 = x, y0$4 = y;
+}
+
+function PathString() {
+ this._string = [];
+}
+
+PathString.prototype = {
+ _radius: 4.5,
+ _circle: circle$1(4.5),
+ pointRadius: function(_) {
+ if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
+ return this;
+ },
+ polygonStart: function() {
+ this._line = 0;
+ },
+ polygonEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._line === 0) this._string.push("Z");
+ this._point = NaN;
+ },
+ point: function(x, y) {
+ switch (this._point) {
+ case 0: {
+ this._string.push("M", x, ",", y);
+ this._point = 1;
+ break;
+ }
+ case 1: {
+ this._string.push("L", x, ",", y);
+ break;
+ }
+ default: {
+ if (this._circle == null) this._circle = circle$1(this._radius);
+ this._string.push("M", x, ",", y, this._circle);
+ break;
+ }
+ }
+ },
+ result: function() {
+ if (this._string.length) {
+ var result = this._string.join("");
+ this._string = [];
+ return result;
+ } else {
+ return null;
+ }
+ }
+};
+
+function circle$1(radius) {
+ return "m0," + radius
+ + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
+ + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
+ + "z";
+}
+
+function index(projection, context) {
+ var pointRadius = 4.5,
+ projectionStream,
+ contextStream;
+
+ function path(object) {
+ if (object) {
+ if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
+ geoStream(object, projectionStream(contextStream));
+ }
+ return contextStream.result();
+ }
+
+ path.area = function(object) {
+ geoStream(object, projectionStream(areaStream$1));
+ return areaStream$1.result();
+ };
+
+ path.measure = function(object) {
+ geoStream(object, projectionStream(lengthStream$1));
+ return lengthStream$1.result();
+ };
+
+ path.bounds = function(object) {
+ geoStream(object, projectionStream(boundsStream$1));
+ return boundsStream$1.result();
+ };
+
+ path.centroid = function(object) {
+ geoStream(object, projectionStream(centroidStream$1));
+ return centroidStream$1.result();
+ };
+
+ path.projection = function(_) {
+ return arguments.length ? (projectionStream = _ == null ? (projection = null, identity) : (projection = _).stream, path) : projection;
+ };
+
+ path.context = function(_) {
+ if (!arguments.length) return context;
+ contextStream = _ == null ? (context = null, new PathString) : new PathContext(context = _);
+ if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
+ return path;
+ };
+
+ path.pointRadius = function(_) {
+ if (!arguments.length) return pointRadius;
+ pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
+ return path;
+ };
+
+ return path.projection(projection).context(context);
+}
+
+function transform(methods) {
+ return {
+ stream: transformer(methods)
+ };
+}
+
+function transformer(methods) {
+ return function(stream) {
+ var s = new TransformStream;
+ for (var key in methods) s[key] = methods[key];
+ s.stream = stream;
+ return s;
+ };
+}
+
+function TransformStream() {}
+
+TransformStream.prototype = {
+ constructor: TransformStream,
+ point: function(x, y) { this.stream.point(x, y); },
+ sphere: function() { this.stream.sphere(); },
+ lineStart: function() { this.stream.lineStart(); },
+ lineEnd: function() { this.stream.lineEnd(); },
+ polygonStart: function() { this.stream.polygonStart(); },
+ polygonEnd: function() { this.stream.polygonEnd(); }
+};
+
+function fit(projection, fitBounds, object) {
+ var clip = projection.clipExtent && projection.clipExtent();
+ projection.scale(150).translate([0, 0]);
+ if (clip != null) projection.clipExtent(null);
+ geoStream(object, projection.stream(boundsStream$1));
+ fitBounds(boundsStream$1.result());
+ if (clip != null) projection.clipExtent(clip);
+ return projection;
+}
+
+function fitExtent(projection, extent, object) {
+ return fit(projection, function(b) {
+ var w = extent[1][0] - extent[0][0],
+ h = extent[1][1] - extent[0][1],
+ k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
+ x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
+ y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
+ projection.scale(150 * k).translate([x, y]);
+ }, object);
+}
+
+function fitSize(projection, size, object) {
+ return fitExtent(projection, [[0, 0], size], object);
+}
+
+function fitWidth(projection, width, object) {
+ return fit(projection, function(b) {
+ var w = +width,
+ k = w / (b[1][0] - b[0][0]),
+ x = (w - k * (b[1][0] + b[0][0])) / 2,
+ y = -k * b[0][1];
+ projection.scale(150 * k).translate([x, y]);
+ }, object);
+}
+
+function fitHeight(projection, height, object) {
+ return fit(projection, function(b) {
+ var h = +height,
+ k = h / (b[1][1] - b[0][1]),
+ x = -k * b[0][0],
+ y = (h - k * (b[1][1] + b[0][1])) / 2;
+ projection.scale(150 * k).translate([x, y]);
+ }, object);
+}
+
+var maxDepth = 16, // maximum depth of subdivision
+ cosMinDistance = cos(30 * radians); // cos(minimum angular distance)
+
+function resample(project, delta2) {
+ return +delta2 ? resample$1(project, delta2) : resampleNone(project);
+}
+
+function resampleNone(project) {
+ return transformer({
+ point: function(x, y) {
+ x = project(x, y);
+ this.stream.point(x[0], x[1]);
+ }
+ });
+}
+
+function resample$1(project, delta2) {
+
+ function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
+ var dx = x1 - x0,
+ dy = y1 - y0,
+ d2 = dx * dx + dy * dy;
+ if (d2 > 4 * delta2 && depth--) {
+ var a = a0 + a1,
+ b = b0 + b1,
+ c = c0 + c1,
+ m = sqrt(a * a + b * b + c * c),
+ phi2 = asin(c /= m),
+ lambda2 = abs(abs(c) - 1) < epsilon || abs(lambda0 - lambda1) < epsilon ? (lambda0 + lambda1) / 2 : atan2(b, a),
+ p = project(lambda2, phi2),
+ x2 = p[0],
+ y2 = p[1],
+ dx2 = x2 - x0,
+ dy2 = y2 - y0,
+ dz = dy * dx2 - dx * dy2;
+ if (dz * dz / d2 > delta2 // perpendicular projected distance
+ || abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
+ || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
+ resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
+ stream.point(x2, y2);
+ resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
+ }
+ }
+ }
+ return function(stream) {
+ var lambda00, x00, y00, a00, b00, c00, // first point
+ lambda0, x0, y0, a0, b0, c0; // previous point
+
+ var resampleStream = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; },
+ polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; }
+ };
+
+ function point(x, y) {
+ x = project(x, y);
+ stream.point(x[0], x[1]);
+ }
+
+ function lineStart() {
+ x0 = NaN;
+ resampleStream.point = linePoint;
+ stream.lineStart();
+ }
+
+ function linePoint(lambda, phi) {
+ var c = cartesian([lambda, phi]), p = project(lambda, phi);
+ resampleLineTo(x0, y0, lambda0, a0, b0, c0, x0 = p[0], y0 = p[1], lambda0 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
+ stream.point(x0, y0);
+ }
+
+ function lineEnd() {
+ resampleStream.point = point;
+ stream.lineEnd();
+ }
+
+ function ringStart() {
+ lineStart();
+ resampleStream.point = ringPoint;
+ resampleStream.lineEnd = ringEnd;
+ }
+
+ function ringPoint(lambda, phi) {
+ linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
+ resampleStream.point = linePoint;
+ }
+
+ function ringEnd() {
+ resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
+ resampleStream.lineEnd = lineEnd;
+ lineEnd();
+ }
+
+ return resampleStream;
+ };
+}
+
+var transformRadians = transformer({
+ point: function(x, y) {
+ this.stream.point(x * radians, y * radians);
+ }
+});
+
+function transformRotate(rotate) {
+ return transformer({
+ point: function(x, y) {
+ var r = rotate(x, y);
+ return this.stream.point(r[0], r[1]);
+ }
+ });
+}
+
+function scaleTranslate(k, dx, dy, sx, sy) {
+ function transform(x, y) {
+ x *= sx; y *= sy;
+ return [dx + k * x, dy - k * y];
+ }
+ transform.invert = function(x, y) {
+ return [(x - dx) / k * sx, (dy - y) / k * sy];
+ };
+ return transform;
+}
+
+function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) {
+ if (!alpha) return scaleTranslate(k, dx, dy, sx, sy);
+ var cosAlpha = cos(alpha),
+ sinAlpha = sin(alpha),
+ a = cosAlpha * k,
+ b = sinAlpha * k,
+ ai = cosAlpha / k,
+ bi = sinAlpha / k,
+ ci = (sinAlpha * dy - cosAlpha * dx) / k,
+ fi = (sinAlpha * dx + cosAlpha * dy) / k;
+ function transform(x, y) {
+ x *= sx; y *= sy;
+ return [a * x - b * y + dx, dy - b * x - a * y];
+ }
+ transform.invert = function(x, y) {
+ return [sx * (ai * x - bi * y + ci), sy * (fi - bi * x - ai * y)];
+ };
+ return transform;
+}
+
+function projection(project) {
+ return projectionMutator(function() { return project; })();
+}
+
+function projectionMutator(projectAt) {
+ var project,
+ k = 150, // scale
+ x = 480, y = 250, // translate
+ lambda = 0, phi = 0, // center
+ deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, // pre-rotate
+ alpha = 0, // post-rotate angle
+ sx = 1, // reflectX
+ sy = 1, // reflectX
+ theta = null, preclip = clipAntimeridian, // pre-clip angle
+ x0 = null, y0, x1, y1, postclip = identity, // post-clip extent
+ delta2 = 0.5, // precision
+ projectResample,
+ projectTransform,
+ projectRotateTransform,
+ cache,
+ cacheStream;
+
+ function projection(point) {
+ return projectRotateTransform(point[0] * radians, point[1] * radians);
+ }
+
+ function invert(point) {
+ point = projectRotateTransform.invert(point[0], point[1]);
+ return point && [point[0] * degrees, point[1] * degrees];
+ }
+
+ projection.stream = function(stream) {
+ return cache && cacheStream === stream ? cache : cache = transformRadians(transformRotate(rotate)(preclip(projectResample(postclip(cacheStream = stream)))));
+ };
+
+ projection.preclip = function(_) {
+ return arguments.length ? (preclip = _, theta = undefined, reset()) : preclip;
+ };
+
+ projection.postclip = function(_) {
+ return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
+ };
+
+ projection.clipAngle = function(_) {
+ return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees;
+ };
+
+ projection.clipExtent = function(_) {
+ return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
+ };
+
+ projection.scale = function(_) {
+ return arguments.length ? (k = +_, recenter()) : k;
+ };
+
+ projection.translate = function(_) {
+ return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
+ };
+
+ projection.center = function(_) {
+ return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees, phi * degrees];
+ };
+
+ projection.rotate = function(_) {
+ return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees, deltaPhi * degrees, deltaGamma * degrees];
+ };
+
+ projection.angle = function(_) {
+ return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees;
+ };
+
+ projection.reflectX = function(_) {
+ return arguments.length ? (sx = _ ? -1 : 1, recenter()) : sx < 0;
+ };
+
+ projection.reflectY = function(_) {
+ return arguments.length ? (sy = _ ? -1 : 1, recenter()) : sy < 0;
+ };
+
+ projection.precision = function(_) {
+ return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
+ };
+
+ projection.fitExtent = function(extent, object) {
+ return fitExtent(projection, extent, object);
+ };
+
+ projection.fitSize = function(size, object) {
+ return fitSize(projection, size, object);
+ };
+
+ projection.fitWidth = function(width, object) {
+ return fitWidth(projection, width, object);
+ };
+
+ projection.fitHeight = function(height, object) {
+ return fitHeight(projection, height, object);
+ };
+
+ function recenter() {
+ var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)),
+ transform = scaleTranslateRotate(k, x - center[0], y - center[1], sx, sy, alpha);
+ rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma);
+ projectTransform = compose(project, transform);
+ projectRotateTransform = compose(rotate, projectTransform);
+ projectResample = resample(projectTransform, delta2);
+ return reset();
+ }
+
+ function reset() {
+ cache = cacheStream = null;
+ return projection;
+ }
+
+ return function() {
+ project = projectAt.apply(this, arguments);
+ projection.invert = project.invert && invert;
+ return recenter();
+ };
+}
+
+function conicProjection(projectAt) {
+ var phi0 = 0,
+ phi1 = pi / 3,
+ m = projectionMutator(projectAt),
+ p = m(phi0, phi1);
+
+ p.parallels = function(_) {
+ return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees, phi1 * degrees];
+ };
+
+ return p;
+}
+
+function cylindricalEqualAreaRaw(phi0) {
+ var cosPhi0 = cos(phi0);
+
+ function forward(lambda, phi) {
+ return [lambda * cosPhi0, sin(phi) / cosPhi0];
+ }
+
+ forward.invert = function(x, y) {
+ return [x / cosPhi0, asin(y * cosPhi0)];
+ };
+
+ return forward;
+}
+
+function conicEqualAreaRaw(y0, y1) {
+ var sy0 = sin(y0), n = (sy0 + sin(y1)) / 2;
+
+ // Are the parallels symmetrical around the Equator?
+ if (abs(n) < epsilon) return cylindricalEqualAreaRaw(y0);
+
+ var c = 1 + sy0 * (2 * n - sy0), r0 = sqrt(c) / n;
+
+ function project(x, y) {
+ var r = sqrt(c - 2 * n * sin(y)) / n;
+ return [r * sin(x *= n), r0 - r * cos(x)];
+ }
+
+ project.invert = function(x, y) {
+ var r0y = r0 - y,
+ l = atan2(x, abs(r0y)) * sign(r0y);
+ if (r0y * n < 0)
+ l -= pi * sign(x) * sign(r0y);
+ return [l / n, asin((c - (x * x + r0y * r0y) * n * n) / (2 * n))];
+ };
+
+ return project;
+}
+
+function conicEqualArea() {
+ return conicProjection(conicEqualAreaRaw)
+ .scale(155.424)
+ .center([0, 33.6442]);
+}
+
+function albers() {
+ return conicEqualArea()
+ .parallels([29.5, 45.5])
+ .scale(1070)
+ .translate([480, 250])
+ .rotate([96, 0])
+ .center([-0.6, 38.7]);
+}
+
+// The projections must have mutually exclusive clip regions on the sphere,
+// as this will avoid emitting interleaving lines and polygons.
+function multiplex(streams) {
+ var n = streams.length;
+ return {
+ point: function(x, y) { var i = -1; while (++i < n) streams[i].point(x, y); },
+ sphere: function() { var i = -1; while (++i < n) streams[i].sphere(); },
+ lineStart: function() { var i = -1; while (++i < n) streams[i].lineStart(); },
+ lineEnd: function() { var i = -1; while (++i < n) streams[i].lineEnd(); },
+ polygonStart: function() { var i = -1; while (++i < n) streams[i].polygonStart(); },
+ polygonEnd: function() { var i = -1; while (++i < n) streams[i].polygonEnd(); }
+ };
+}
+
+// A composite projection for the United States, configured by default for
+// 960×500. The projection also works quite well at 960×600 if you change the
+// scale to 1285 and adjust the translate accordingly. 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
+function albersUsa() {
+ var cache,
+ cacheStream,
+ lower48 = albers(), lower48Point,
+ alaska = conicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]), alaskaPoint, // EPSG:3338
+ hawaii = conicEqualArea().rotate([157, 0]).center([-3, 19.9]).parallels([8, 18]), hawaiiPoint, // ESRI:102007
+ point, pointStream = {point: function(x, y) { point = [x, y]; }};
+
+ function albersUsa(coordinates) {
+ var x = coordinates[0], y = coordinates[1];
+ return point = null,
+ (lower48Point.point(x, y), point)
+ || (alaskaPoint.point(x, y), point)
+ || (hawaiiPoint.point(x, y), point);
+ }
+
+ albersUsa.invert = function(coordinates) {
+ var k = lower48.scale(),
+ t = lower48.translate(),
+ x = (coordinates[0] - t[0]) / k,
+ y = (coordinates[1] - t[1]) / k;
+ return (y >= 0.120 && y < 0.234 && x >= -0.425 && x < -0.214 ? alaska
+ : y >= 0.166 && y < 0.234 && x >= -0.214 && x < -0.115 ? hawaii
+ : lower48).invert(coordinates);
+ };
+
+ albersUsa.stream = function(stream) {
+ return cache && cacheStream === stream ? cache : cache = multiplex([lower48.stream(cacheStream = stream), alaska.stream(stream), hawaii.stream(stream)]);
+ };
+
+ albersUsa.precision = function(_) {
+ if (!arguments.length) return lower48.precision();
+ lower48.precision(_), alaska.precision(_), hawaii.precision(_);
+ return reset();
+ };
+
+ albersUsa.scale = function(_) {
+ if (!arguments.length) return lower48.scale();
+ lower48.scale(_), alaska.scale(_ * 0.35), hawaii.scale(_);
+ return albersUsa.translate(lower48.translate());
+ };
+
+ albersUsa.translate = function(_) {
+ if (!arguments.length) return lower48.translate();
+ var k = lower48.scale(), x = +_[0], y = +_[1];
+
+ lower48Point = lower48
+ .translate(_)
+ .clipExtent([[x - 0.455 * k, y - 0.238 * k], [x + 0.455 * k, y + 0.238 * k]])
+ .stream(pointStream);
+
+ alaskaPoint = alaska
+ .translate([x - 0.307 * k, y + 0.201 * k])
+ .clipExtent([[x - 0.425 * k + epsilon, y + 0.120 * k + epsilon], [x - 0.214 * k - epsilon, y + 0.234 * k - epsilon]])
+ .stream(pointStream);
+
+ hawaiiPoint = hawaii
+ .translate([x - 0.205 * k, y + 0.212 * k])
+ .clipExtent([[x - 0.214 * k + epsilon, y + 0.166 * k + epsilon], [x - 0.115 * k - epsilon, y + 0.234 * k - epsilon]])
+ .stream(pointStream);
+
+ return reset();
+ };
+
+ albersUsa.fitExtent = function(extent, object) {
+ return fitExtent(albersUsa, extent, object);
+ };
+
+ albersUsa.fitSize = function(size, object) {
+ return fitSize(albersUsa, size, object);
+ };
+
+ albersUsa.fitWidth = function(width, object) {
+ return fitWidth(albersUsa, width, object);
+ };
+
+ albersUsa.fitHeight = function(height, object) {
+ return fitHeight(albersUsa, height, object);
+ };
+
+ function reset() {
+ cache = cacheStream = null;
+ return albersUsa;
+ }
+
+ return albersUsa.scale(1070);
+}
+
+function azimuthalRaw(scale) {
+ return function(x, y) {
+ var cx = cos(x),
+ cy = cos(y),
+ k = scale(cx * cy);
+ if (k === Infinity) return [2, 0];
+ return [
+ k * cy * sin(x),
+ k * sin(y)
+ ];
+ }
+}
+
+function azimuthalInvert(angle) {
+ return function(x, y) {
+ var z = sqrt(x * x + y * y),
+ c = angle(z),
+ sc = sin(c),
+ cc = cos(c);
+ return [
+ atan2(x * sc, z * cc),
+ asin(z && y * sc / z)
+ ];
+ }
+}
+
+var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) {
+ return sqrt(2 / (1 + cxcy));
+});
+
+azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) {
+ return 2 * asin(z / 2);
+});
+
+function azimuthalEqualArea() {
+ return projection(azimuthalEqualAreaRaw)
+ .scale(124.75)
+ .clipAngle(180 - 1e-3);
+}
+
+var azimuthalEquidistantRaw = azimuthalRaw(function(c) {
+ return (c = acos(c)) && c / sin(c);
+});
+
+azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) {
+ return z;
+});
+
+function azimuthalEquidistant() {
+ return projection(azimuthalEquidistantRaw)
+ .scale(79.4188)
+ .clipAngle(180 - 1e-3);
+}
+
+function mercatorRaw(lambda, phi) {
+ return [lambda, log(tan((halfPi + phi) / 2))];
+}
+
+mercatorRaw.invert = function(x, y) {
+ return [x, 2 * atan(exp(y)) - halfPi];
+};
+
+function mercator() {
+ return mercatorProjection(mercatorRaw)
+ .scale(961 / tau);
+}
+
+function mercatorProjection(project) {
+ var m = projection(project),
+ center = m.center,
+ scale = m.scale,
+ translate = m.translate,
+ clipExtent = m.clipExtent,
+ x0 = null, y0, x1, y1; // clip extent
+
+ m.scale = function(_) {
+ return arguments.length ? (scale(_), reclip()) : scale();
+ };
+
+ m.translate = function(_) {
+ return arguments.length ? (translate(_), reclip()) : translate();
+ };
+
+ m.center = function(_) {
+ return arguments.length ? (center(_), reclip()) : center();
+ };
+
+ m.clipExtent = function(_) {
+ return arguments.length ? ((_ == null ? x0 = y0 = x1 = y1 = null : (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1])), reclip()) : x0 == null ? null : [[x0, y0], [x1, y1]];
+ };
+
+ function reclip() {
+ var k = pi * scale(),
+ t = m(rotation(m.rotate()).invert([0, 0]));
+ return clipExtent(x0 == null
+ ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw
+ ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]]
+ : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]);
+ }
+
+ return reclip();
+}
+
+function tany(y) {
+ return tan((halfPi + y) / 2);
+}
+
+function conicConformalRaw(y0, y1) {
+ var cy0 = cos(y0),
+ n = y0 === y1 ? sin(y0) : log(cy0 / cos(y1)) / log(tany(y1) / tany(y0)),
+ f = cy0 * pow(tany(y0), n) / n;
+
+ if (!n) return mercatorRaw;
+
+ function project(x, y) {
+ if (f > 0) { if (y < -halfPi + epsilon) y = -halfPi + epsilon; }
+ else { if (y > halfPi - epsilon) y = halfPi - epsilon; }
+ var r = f / pow(tany(y), n);
+ return [r * sin(n * x), f - r * cos(n * x)];
+ }
+
+ project.invert = function(x, y) {
+ var fy = f - y, r = sign(n) * sqrt(x * x + fy * fy),
+ l = atan2(x, abs(fy)) * sign(fy);
+ if (fy * n < 0)
+ l -= pi * sign(x) * sign(fy);
+ return [l / n, 2 * atan(pow(f / r, 1 / n)) - halfPi];
+ };
+
+ return project;
+}
+
+function conicConformal() {
+ return conicProjection(conicConformalRaw)
+ .scale(109.5)
+ .parallels([30, 30]);
+}
+
+function equirectangularRaw(lambda, phi) {
+ return [lambda, phi];
+}
+
+equirectangularRaw.invert = equirectangularRaw;
+
+function equirectangular() {
+ return projection(equirectangularRaw)
+ .scale(152.63);
+}
+
+function conicEquidistantRaw(y0, y1) {
+ var cy0 = cos(y0),
+ n = y0 === y1 ? sin(y0) : (cy0 - cos(y1)) / (y1 - y0),
+ g = cy0 / n + y0;
+
+ if (abs(n) < epsilon) return equirectangularRaw;
+
+ function project(x, y) {
+ var gy = g - y, nx = n * x;
+ return [gy * sin(nx), g - gy * cos(nx)];
+ }
+
+ project.invert = function(x, y) {
+ var gy = g - y,
+ l = atan2(x, abs(gy)) * sign(gy);
+ if (gy * n < 0)
+ l -= pi * sign(x) * sign(gy);
+ return [l / n, g - sign(n) * sqrt(x * x + gy * gy)];
+ };
+
+ return project;
+}
+
+function conicEquidistant() {
+ return conicProjection(conicEquidistantRaw)
+ .scale(131.154)
+ .center([0, 13.9389]);
+}
+
+var A1 = 1.340264,
+ A2 = -0.081106,
+ A3 = 0.000893,
+ A4 = 0.003796,
+ M = sqrt(3) / 2,
+ iterations = 12;
+
+function equalEarthRaw(lambda, phi) {
+ var l = asin(M * sin(phi)), l2 = l * l, l6 = l2 * l2 * l2;
+ return [
+ lambda * cos(l) / (M * (A1 + 3 * A2 * l2 + l6 * (7 * A3 + 9 * A4 * l2))),
+ l * (A1 + A2 * l2 + l6 * (A3 + A4 * l2))
+ ];
+}
+
+equalEarthRaw.invert = function(x, y) {
+ var l = y, l2 = l * l, l6 = l2 * l2 * l2;
+ for (var i = 0, delta, fy, fpy; i < iterations; ++i) {
+ fy = l * (A1 + A2 * l2 + l6 * (A3 + A4 * l2)) - y;
+ fpy = A1 + 3 * A2 * l2 + l6 * (7 * A3 + 9 * A4 * l2);
+ l -= delta = fy / fpy, l2 = l * l, l6 = l2 * l2 * l2;
+ if (abs(delta) < epsilon2) break;
+ }
+ return [
+ M * x * (A1 + 3 * A2 * l2 + l6 * (7 * A3 + 9 * A4 * l2)) / cos(l),
+ asin(sin(l) / M)
+ ];
+};
+
+function equalEarth() {
+ return projection(equalEarthRaw)
+ .scale(177.158);
+}
+
+function gnomonicRaw(x, y) {
+ var cy = cos(y), k = cos(x) * cy;
+ return [cy * sin(x) / k, sin(y) / k];
+}
+
+gnomonicRaw.invert = azimuthalInvert(atan);
+
+function gnomonic() {
+ return projection(gnomonicRaw)
+ .scale(144.049)
+ .clipAngle(60);
+}
+
+function identity$1() {
+ var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, // scale, translate and reflect
+ alpha = 0, ca, sa, // angle
+ x0 = null, y0, x1, y1, // clip extent
+ kx = 1, ky = 1,
+ transform = transformer({
+ point: function(x, y) {
+ var p = projection([x, y]);
+ this.stream.point(p[0], p[1]);
+ }
+ }),
+ postclip = identity,
+ cache,
+ cacheStream;
+
+ function reset() {
+ kx = k * sx;
+ ky = k * sy;
+ cache = cacheStream = null;
+ return projection;
+ }
+
+ function projection (p) {
+ var x = p[0] * kx, y = p[1] * ky;
+ if (alpha) {
+ var t = y * ca - x * sa;
+ x = x * ca + y * sa;
+ y = t;
+ }
+ return [x + tx, y + ty];
+ }
+ projection.invert = function(p) {
+ var x = p[0] - tx, y = p[1] - ty;
+ if (alpha) {
+ var t = y * ca + x * sa;
+ x = x * ca - y * sa;
+ y = t;
+ }
+ return [x / kx, y / ky];
+ };
+ projection.stream = function(stream) {
+ return cache && cacheStream === stream ? cache : cache = transform(postclip(cacheStream = stream));
+ };
+ projection.postclip = function(_) {
+ return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
+ };
+ projection.clipExtent = function(_) {
+ return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
+ };
+ projection.scale = function(_) {
+ return arguments.length ? (k = +_, reset()) : k;
+ };
+ projection.translate = function(_) {
+ return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty];
+ };
+ projection.angle = function(_) {
+ return arguments.length ? (alpha = _ % 360 * radians, sa = sin(alpha), ca = cos(alpha), reset()) : alpha * degrees;
+ };
+ projection.reflectX = function(_) {
+ return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0;
+ };
+ projection.reflectY = function(_) {
+ return arguments.length ? (sy = _ ? -1 : 1, reset()) : sy < 0;
+ };
+ projection.fitExtent = function(extent, object) {
+ return fitExtent(projection, extent, object);
+ };
+ projection.fitSize = function(size, object) {
+ return fitSize(projection, size, object);
+ };
+ projection.fitWidth = function(width, object) {
+ return fitWidth(projection, width, object);
+ };
+ projection.fitHeight = function(height, object) {
+ return fitHeight(projection, height, object);
+ };
+
+ return projection;
+}
+
+function naturalEarth1Raw(lambda, phi) {
+ var phi2 = phi * phi, phi4 = phi2 * phi2;
+ return [
+ lambda * (0.8707 - 0.131979 * phi2 + phi4 * (-0.013791 + phi4 * (0.003971 * phi2 - 0.001529 * phi4))),
+ phi * (1.007226 + phi2 * (0.015085 + phi4 * (-0.044475 + 0.028874 * phi2 - 0.005916 * phi4)))
+ ];
+}
+
+naturalEarth1Raw.invert = function(x, y) {
+ var phi = y, i = 25, delta;
+ do {
+ var phi2 = phi * phi, phi4 = phi2 * phi2;
+ phi -= delta = (phi * (1.007226 + phi2 * (0.015085 + phi4 * (-0.044475 + 0.028874 * phi2 - 0.005916 * phi4))) - y) /
+ (1.007226 + phi2 * (0.015085 * 3 + phi4 * (-0.044475 * 7 + 0.028874 * 9 * phi2 - 0.005916 * 11 * phi4)));
+ } while (abs(delta) > epsilon && --i > 0);
+ return [
+ x / (0.8707 + (phi2 = phi * phi) * (-0.131979 + phi2 * (-0.013791 + phi2 * phi2 * phi2 * (0.003971 - 0.001529 * phi2)))),
+ phi
+ ];
+};
+
+function naturalEarth1() {
+ return projection(naturalEarth1Raw)
+ .scale(175.295);
+}
+
+function orthographicRaw(x, y) {
+ return [cos(y) * sin(x), sin(y)];
+}
+
+orthographicRaw.invert = azimuthalInvert(asin);
+
+function orthographic() {
+ return projection(orthographicRaw)
+ .scale(249.5)
+ .clipAngle(90 + epsilon);
+}
+
+function stereographicRaw(x, y) {
+ var cy = cos(y), k = 1 + cos(x) * cy;
+ return [cy * sin(x) / k, sin(y) / k];
+}
+
+stereographicRaw.invert = azimuthalInvert(function(z) {
+ return 2 * atan(z);
+});
+
+function stereographic() {
+ return projection(stereographicRaw)
+ .scale(250)
+ .clipAngle(142);
+}
+
+function transverseMercatorRaw(lambda, phi) {
+ return [log(tan((halfPi + phi) / 2)), -lambda];
+}
+
+transverseMercatorRaw.invert = function(x, y) {
+ return [-y, 2 * atan(exp(x)) - halfPi];
+};
+
+function transverseMercator() {
+ var m = mercatorProjection(transverseMercatorRaw),
+ center = m.center,
+ rotate = m.rotate;
+
+ m.center = function(_) {
+ return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]);
+ };
+
+ m.rotate = function(_) {
+ return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]);
+ };
+
+ return rotate([0, 0, 90])
+ .scale(159.155);
+}
+
+exports.geoAlbers = albers;
+exports.geoAlbersUsa = albersUsa;
+exports.geoArea = area;
+exports.geoAzimuthalEqualArea = azimuthalEqualArea;
+exports.geoAzimuthalEqualAreaRaw = azimuthalEqualAreaRaw;
+exports.geoAzimuthalEquidistant = azimuthalEquidistant;
+exports.geoAzimuthalEquidistantRaw = azimuthalEquidistantRaw;
+exports.geoBounds = bounds;
+exports.geoCentroid = centroid;
+exports.geoCircle = circle;
+exports.geoClipAntimeridian = clipAntimeridian;
+exports.geoClipCircle = clipCircle;
+exports.geoClipExtent = extent;
+exports.geoClipRectangle = clipRectangle;
+exports.geoConicConformal = conicConformal;
+exports.geoConicConformalRaw = conicConformalRaw;
+exports.geoConicEqualArea = conicEqualArea;
+exports.geoConicEqualAreaRaw = conicEqualAreaRaw;
+exports.geoConicEquidistant = conicEquidistant;
+exports.geoConicEquidistantRaw = conicEquidistantRaw;
+exports.geoContains = contains;
+exports.geoDistance = distance;
+exports.geoEqualEarth = equalEarth;
+exports.geoEqualEarthRaw = equalEarthRaw;
+exports.geoEquirectangular = equirectangular;
+exports.geoEquirectangularRaw = equirectangularRaw;
+exports.geoGnomonic = gnomonic;
+exports.geoGnomonicRaw = gnomonicRaw;
+exports.geoGraticule = graticule;
+exports.geoGraticule10 = graticule10;
+exports.geoIdentity = identity$1;
+exports.geoInterpolate = interpolate;
+exports.geoLength = length;
+exports.geoMercator = mercator;
+exports.geoMercatorRaw = mercatorRaw;
+exports.geoNaturalEarth1 = naturalEarth1;
+exports.geoNaturalEarth1Raw = naturalEarth1Raw;
+exports.geoOrthographic = orthographic;
+exports.geoOrthographicRaw = orthographicRaw;
+exports.geoPath = index;
+exports.geoProjection = projection;
+exports.geoProjectionMutator = projectionMutator;
+exports.geoRotation = rotation;
+exports.geoStereographic = stereographic;
+exports.geoStereographicRaw = stereographicRaw;
+exports.geoStream = geoStream;
+exports.geoTransform = transform;
+exports.geoTransverseMercator = transverseMercator;
+exports.geoTransverseMercatorRaw = transverseMercatorRaw;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-geo/dist/d3-geo.min.js b/node_modules/d3-geo/dist/d3-geo.min.js
new file mode 100644
index 00000000..ddb21690
--- /dev/null
+++ b/node_modules/d3-geo/dist/d3-geo.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-geo/ v2.0.1 Copyright 2020 Mike Bostock
+!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-array")):"function"==typeof define&&define.amd?define(["exports","d3-array"],t):t((n=n||self).d3=n.d3||{},n.d3)}(this,function(n,t){"use strict";var r=1e-6,e=1e-12,i=Math.PI,o=i/2,u=i/4,a=2*i,c=180/i,l=i/180,f=Math.abs,p=Math.atan,s=Math.atan2,h=Math.cos,g=Math.ceil,v=Math.exp,d=Math.hypot,E=Math.log,y=Math.pow,S=Math.sin,m=Math.sign||function(n){return n>0?1:n<0?-1:0},M=Math.sqrt,x=Math.tan;function w(n){return n>1?0:n<-1?i:Math.acos(n)}function _(n){return n>1?o:n<-1?-o:Math.asin(n)}function N(n){return(n=S(n/2))*n}function A(){}function R(n,t){n&&P.hasOwnProperty(n.type)&&P[n.type](n,t)}var C={Feature:function(n,t){R(n.geometry,t)},FeatureCollection:function(n,t){for(var r=n.features,e=-1,i=r.length;++e=0?1:-1,i=e*r,o=h(t=(t*=l)/2+u),a=S(t),c=T*a,f=G*o+c*h(i),p=c*e*S(i);J.add(s(p,f)),O=n,G=o,T=a}function rn(n){return[s(n[1],n[0]),_(n[2])]}function en(n){var t=n[0],r=n[1],e=h(r);return[e*h(t),e*S(t),S(r)]}function on(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function un(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function an(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function cn(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function ln(n){var t=M(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}var fn,pn,sn,hn,gn,vn,dn,En,yn,Sn,mn,Mn,xn,wn,_n,Nn,An={point:Rn,lineStart:Pn,lineEnd:jn,polygonStart:function(){An.point=qn,An.lineStart=zn,An.lineEnd=bn,D=new t.Adder,Q.polygonStart()},polygonEnd:function(){Q.polygonEnd(),An.point=Rn,An.lineStart=Pn,An.lineEnd=jn,J<0?(k=-(H=180),F=-(I=90)):D>r?I=90:D<-r&&(F=-90),Z[0]=k,Z[1]=H},sphere:function(){k=-(H=180),F=-(I=90)}};function Rn(n,t){U.push(Z=[k=n,H=n]),ter&&(er=t)},lineStart:A,lineEnd:A,polygonStart:A,polygonEnd:A,result:function(){var n=[[nr,tr],[rr,er]];return rr=er=-(tr=nr=1/0),n}};var or,ur,ar,cr,lr=0,fr=0,pr=0,sr=0,hr=0,gr=0,vr=0,dr=0,Er=0,yr={point:Sr,lineStart:mr,lineEnd:wr,polygonStart:function(){yr.lineStart=_r,yr.lineEnd=Nr},polygonEnd:function(){yr.point=Sr,yr.lineStart=mr,yr.lineEnd=wr},result:function(){var n=Er?[vr/Er,dr/Er]:gr?[sr/gr,hr/gr]:pr?[lr/pr,fr/pr]:[NaN,NaN];return lr=fr=pr=sr=hr=gr=vr=dr=Er=0,n}};function Sr(n,t){lr+=n,fr+=t,++pr}function mr(){yr.point=Mr}function Mr(n,t){yr.point=xr,Sr(ar=n,cr=t)}function xr(n,t){var r=n-ar,e=t-cr,i=M(r*r+e*e);sr+=i*(ar+n)/2,hr+=i*(cr+t)/2,gr+=i,Sr(ar=n,cr=t)}function wr(){yr.point=Sr}function _r(){yr.point=Ar}function Nr(){Rr(or,ur)}function Ar(n,t){yr.point=Rr,Sr(or=ar=n,ur=cr=t)}function Rr(n,t){var r=n-ar,e=t-cr,i=M(r*r+e*e);sr+=i*(ar+n)/2,hr+=i*(cr+t)/2,gr+=i,vr+=(i=cr*n-ar*t)*(ar+n),dr+=i*(cr+t),Er+=3*i,Sr(ar=n,cr=t)}function Cr(n){this._context=n}Cr.prototype={_radius:4.5,pointRadius:function(n){return this._radius=n,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(n,t){switch(this._point){case 0:this._context.moveTo(n,t),this._point=1;break;case 1:this._context.lineTo(n,t);break;default:this._context.moveTo(n+this._radius,t),this._context.arc(n,t,this._radius,0,a)}},result:A};var Pr,jr,qr,zr,br,Lr=new t.Adder,Or={point:A,lineStart:function(){Or.point=Gr},lineEnd:function(){Pr&&Tr(jr,qr),Or.point=A},polygonStart:function(){Pr=!0},polygonEnd:function(){Pr=null},result:function(){var n=+Lr;return Lr=new t.Adder,n}};function Gr(n,t){Or.point=Tr,jr=zr=n,qr=br=t}function Tr(n,t){zr-=n,br-=t,Lr.add(M(zr*zr+br*br)),zr=n,br=t}function kr(){this._string=[]}function Fr(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Hr(n){return function(t){var r=new Ir;for(var e in n)r[e]=n[e];return r.stream=t,r}}function Ir(){}function Wr(n,t,r){var e=n.clipExtent&&n.clipExtent();return n.scale(150).translate([0,0]),null!=e&&n.clipExtent(null),z(r,n.stream(ir)),t(ir.result()),null!=e&&n.clipExtent(e),n}function Xr(n,t,r){return Wr(n,function(r){var e=t[1][0]-t[0][0],i=t[1][1]-t[0][1],o=Math.min(e/(r[1][0]-r[0][0]),i/(r[1][1]-r[0][1])),u=+t[0][0]+(e-o*(r[1][0]+r[0][0]))/2,a=+t[0][1]+(i-o*(r[1][1]+r[0][1]))/2;n.scale(150*o).translate([u,a])},r)}function Yr(n,t,r){return Xr(n,[[0,0],t],r)}function Br(n,t,r){return Wr(n,function(r){var e=+t,i=e/(r[1][0]-r[0][0]),o=(e-i*(r[1][0]+r[0][0]))/2,u=-i*r[0][1];n.scale(150*i).translate([o,u])},r)}function Dr(n,t,r){return Wr(n,function(r){var e=+t,i=e/(r[1][1]-r[0][1]),o=-i*r[0][0],u=(e-i*(r[1][1]+r[0][1]))/2;n.scale(150*i).translate([o,u])},r)}kr.prototype={_radius:4.5,_circle:Fr(4.5),pointRadius:function(n){return(n=+n)!==this._radius&&(this._radius=n,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(n,t){switch(this._point){case 0:this._string.push("M",n,",",t),this._point=1;break;case 1:this._string.push("L",n,",",t);break;default:null==this._circle&&(this._circle=Fr(this._radius)),this._string.push("M",n,",",t,this._circle)}},result:function(){if(this._string.length){var n=this._string.join("");return this._string=[],n}return null}},Ir.prototype={constructor:Ir,point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var Ur=16,Zr=h(30*l);function Jr(n,t){return+t?function(n,t){function e(i,o,u,a,c,l,p,h,g,v,d,E,y,S){var m=p-i,x=h-o,w=m*m+x*x;if(w>4*t&&y--){var N=a+v,A=c+d,R=l+E,C=M(N*N+A*A+R*R),P=_(R/=C),j=f(f(R)-1)
](https://runkit.com/mbostock/56fed33d8630b01300f72daa)
+
+This hierarchy can now be passed to a hierarchical layout, such as [d3.tree](#_tree), for visualization.
+
+# d3.stratify() · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/stratify.js), [Examples](https://observablehq.com/@d3/d3-stratify)
+
+Constructs a new stratify operator with the default settings.
+
+# stratify(data) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/stratify.js), [Examples](https://observablehq.com/@d3/d3-stratify)
+
+Generates a new hierarchy from the specified tabular *data*.
+
+# stratify.id([id]) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/stratify.js), [Examples](https://observablehq.com/@d3/d3-stratify)
+
+If *id* is specified, sets the id accessor to the given function and returns this stratify operator. Otherwise, returns the current id accessor, which defaults to:
+
+```js
+function id(d) {
+ return d.id;
+}
+```
+
+The id accessor is invoked for each element in the input data passed to the [stratify operator](#_stratify), being passed the current datum (*d*) and the current index (*i*). The returned string is then used to identify the node’s relationships in conjunction with the [parent id](#stratify_parentId). For leaf nodes, the id may be undefined; otherwise, the id must be unique. (Null and the empty string are equivalent to undefined.)
+
+# stratify.parentId([parentId]) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/stratify.js), [Examples](https://observablehq.com/@d3/d3-stratify)
+
+If *parentId* is specified, sets the parent id accessor to the given function and returns this stratify operator. Otherwise, returns the current parent id accessor, which defaults to:
+
+```js
+function parentId(d) {
+ return d.parentId;
+}
+```
+
+The parent id accessor is invoked for each element in the input data passed to the [stratify operator](#_stratify), being passed the current datum (*d*) and the current index (*i*). The returned string is then used to identify the node’s relationships in conjunction with the [id](#stratify_id). For the root node, the parent id should be undefined. (Null and the empty string are equivalent to undefined.) There must be exactly one root node in the input data, and no circular relationships.
+
+### Cluster
+
+[
](https://observablehq.com/@d3/cluster-dendrogram)
+
+The **cluster layout** produces [dendrograms](http://en.wikipedia.org/wiki/Dendrogram): node-link diagrams that place leaf nodes of the tree at the same depth. Dendrograms are typically less compact than [tidy trees](#tree), but are useful when all the leaves should be at the same level, such as for hierarchical clustering or [phylogenetic tree diagrams](https://observablehq.com/@mbostock/tree-of-life).
+
+# d3.cluster() · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/cluster.js), [Examples](https://observablehq.com/@d3/cluster-dendrogram)
+
+Creates a new cluster layout with default settings.
+
+# cluster(root)
+
+Lays out the specified *root* [hierarchy](#hierarchy), assigning the following properties on *root* and its descendants:
+
+* *node*.x - the *x*-coordinate of the node
+* *node*.y - the *y*-coordinate of the node
+
+The coordinates *x* and *y* represent an arbitrary coordinate system; for example, you can treat *x* as an angle and *y* as a radius to produce a [radial layout](https://observablehq.com/@d3/radial-dendrogram). You may want to call [*root*.sort](#node_sort) before passing the hierarchy to the cluster layout.
+
+# cluster.size([size])
+
+If *size* is specified, sets this cluster layout’s size to the specified two-element array of numbers [*width*, *height*] and returns this cluster layout. If *size* is not specified, returns the current layout size, which defaults to [1, 1]. A layout size of null indicates that a [node size](#cluster_nodeSize) will be used instead. The coordinates *x* and *y* represent an arbitrary coordinate system; for example, to produce a [radial layout](https://observablehq.com/@d3/radial-dendrogram), a size of [360, *radius*] corresponds to a breadth of 360° and a depth of *radius*.
+
+# cluster.nodeSize([size])
+
+If *size* is specified, sets this cluster layout’s node size to the specified two-element array of numbers [*width*, *height*] and returns this cluster layout. If *size* is not specified, returns the current node size, which defaults to null. A node size of null indicates that a [layout size](#cluster_size) will be used instead. When a node size is specified, the root node is always positioned at ⟨0, 0⟩.
+
+# cluster.separation([separation])
+
+If *separation* is specified, sets the separation accessor to the specified function and returns this cluster layout. If *separation* is not specified, returns the current separation accessor, which defaults to:
+
+```js
+function separation(a, b) {
+ return a.parent == b.parent ? 1 : 2;
+}
+```
+
+The separation accessor is used to separate neighboring leaves. The separation function is passed two leaves *a* and *b*, and must return the desired separation. The nodes are typically siblings, though the nodes may be more distantly related if the layout decides to place such nodes adjacent.
+
+### Tree
+
+[
](https://observablehq.com/@d3/tidy-tree)
+
+The **tree** layout produces tidy node-link diagrams of trees using the [Reingold–Tilford “tidy†algorithm](http://reingold.co/tidier-drawings.pdf), improved to run in linear time by [Buchheim *et al.*](http://dirk.jivas.de/papers/buchheim02improving.pdf) Tidy trees are typically more compact than [dendrograms](#cluster).
+
+# d3.tree() · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/tree.js), [Examples](https://observablehq.com/@d3/tidy-tree)
+
+Creates a new tree layout with default settings.
+
+# tree(root)
+
+Lays out the specified *root* [hierarchy](#hierarchy), assigning the following properties on *root* and its descendants:
+
+* *node*.x - the *x*-coordinate of the node
+* *node*.y - the *y*-coordinate of the node
+
+The coordinates *x* and *y* represent an arbitrary coordinate system; for example, you can treat *x* as an angle and *y* as a radius to produce a [radial layout](https://observablehq.com/@d3/radial-tidy-tree). You may want to call [*root*.sort](#node_sort) before passing the hierarchy to the tree layout.
+
+# tree.size([size])
+
+If *size* is specified, sets this tree layout’s size to the specified two-element array of numbers [*width*, *height*] and returns this tree layout. If *size* is not specified, returns the current layout size, which defaults to [1, 1]. A layout size of null indicates that a [node size](#tree_nodeSize) will be used instead. The coordinates *x* and *y* represent an arbitrary coordinate system; for example, to produce a [radial layout](https://observablehq.com/@d3/radial-tidy-tree), a size of [360, *radius*] corresponds to a breadth of 360° and a depth of *radius*.
+
+# tree.nodeSize([size])
+
+If *size* is specified, sets this tree layout’s node size to the specified two-element array of numbers [*width*, *height*] and returns this tree layout. If *size* is not specified, returns the current node size, which defaults to null. A node size of null indicates that a [layout size](#tree_size) will be used instead. When a node size is specified, the root node is always positioned at ⟨0, 0⟩.
+
+# tree.separation([separation])
+
+If *separation* is specified, sets the separation accessor to the specified function and returns this tree layout. If *separation* is not specified, returns the current separation accessor, which defaults to:
+
+```js
+function separation(a, b) {
+ return a.parent == b.parent ? 1 : 2;
+}
+```
+
+A variation that is more appropriate for radial layouts reduces the separation gap proportionally to the radius:
+
+```js
+function separation(a, b) {
+ return (a.parent == b.parent ? 1 : 2) / a.depth;
+}
+```
+
+The separation accessor is used to separate neighboring nodes. The separation function is passed two nodes *a* and *b*, and must return the desired separation. The nodes are typically siblings, though the nodes may be more distantly related if the layout decides to place such nodes adjacent.
+
+### Treemap
+
+[
](https://observablehq.com/@d3/treemap)
+
+Introduced by [Ben Shneiderman](http://www.cs.umd.edu/hcil/treemap-history/) in 1991, a **treemap** recursively subdivides area into rectangles according to each node’s associated value. D3’s treemap implementation supports an extensible [tiling method](#treemap_tile): the default [squarified](#treemapSquarify) method seeks to generate rectangles with a [golden](https://en.wikipedia.org/wiki/Golden_ratio) aspect ratio; this offers better readability and size estimation than [slice-and-dice](#treemapSliceDice), which simply alternates between horizontal and vertical subdivision by depth.
+
+# d3.treemap() · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/treemap/index.js), [Examples](https://observablehq.com/@d3/treemap)
+
+Creates a new treemap layout with default settings.
+
+# treemap(root)
+
+Lays out the specified *root* [hierarchy](#hierarchy), assigning the following properties on *root* and its descendants:
+
+* *node*.x0 - the left edge of the rectangle
+* *node*.y0 - the top edge of the rectangle
+* *node*.x1 - the right edge of the rectangle
+* *node*.y1 - the bottom edge of the rectangle
+
+You must call [*root*.sum](#node_sum) before passing the hierarchy to the treemap layout. You probably also want to call [*root*.sort](#node_sort) to order the hierarchy before computing the layout.
+
+# treemap.tile([tile])
+
+If *tile* is specified, sets the [tiling method](#treemap-tiling) to the specified function and returns this treemap layout. If *tile* is not specified, returns the current tiling method, which defaults to [d3.treemapSquarify](#treemapSquarify) with the golden ratio.
+
+# treemap.size([size])
+
+If *size* is specified, sets this treemap layout’s size to the specified two-element array of numbers [*width*, *height*] and returns this treemap layout. If *size* is not specified, returns the current size, which defaults to [1, 1].
+
+# treemap.round([round])
+
+If *round* is specified, enables or disables rounding according to the given boolean and returns this treemap layout. If *round* is not specified, returns the current rounding state, which defaults to false.
+
+# treemap.padding([padding])
+
+If *padding* is specified, sets the [inner](#treemap_paddingInner) and [outer](#treemap_paddingOuter) padding to the specified number or function and returns this treemap layout. If *padding* is not specified, returns the current inner padding function.
+
+# treemap.paddingInner([padding])
+
+If *padding* is specified, sets the inner padding to the specified number or function and returns this treemap layout. If *padding* is not specified, returns the current inner padding function, which defaults to the constant zero. If *padding* is a function, it is invoked for each node with children, being passed the current node. The inner padding is used to separate a node’s adjacent children.
+
+# treemap.paddingOuter([padding])
+
+If *padding* is specified, sets the [top](#treemap_paddingTop), [right](#treemap_paddingRight), [bottom](#treemap_paddingBottom) and [left](#treemap_paddingLeft) padding to the specified number or function and returns this treemap layout. If *padding* is not specified, returns the current top padding function.
+
+# treemap.paddingTop([padding])
+
+If *padding* is specified, sets the top padding to the specified number or function and returns this treemap layout. If *padding* is not specified, returns the current top padding function, which defaults to the constant zero. If *padding* is a function, it is invoked for each node with children, being passed the current node. The top padding is used to separate the top edge of a node from its children.
+
+# treemap.paddingRight([padding])
+
+If *padding* is specified, sets the right padding to the specified number or function and returns this treemap layout. If *padding* is not specified, returns the current right padding function, which defaults to the constant zero. If *padding* is a function, it is invoked for each node with children, being passed the current node. The right padding is used to separate the right edge of a node from its children.
+
+# treemap.paddingBottom([padding])
+
+If *padding* is specified, sets the bottom padding to the specified number or function and returns this treemap layout. If *padding* is not specified, returns the current bottom padding function, which defaults to the constant zero. If *padding* is a function, it is invoked for each node with children, being passed the current node. The bottom padding is used to separate the bottom edge of a node from its children.
+
+# treemap.paddingLeft([padding])
+
+If *padding* is specified, sets the left padding to the specified number or function and returns this treemap layout. If *padding* is not specified, returns the current left padding function, which defaults to the constant zero. If *padding* is a function, it is invoked for each node with children, being passed the current node. The left padding is used to separate the left edge of a node from its children.
+
+#### Treemap Tiling
+
+Several built-in tiling methods are provided for use with [*treemap*.tile](#treemap_tile).
+
+# d3.treemapBinary(node, x0, y0, x1, y1) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/treemap/binary.js), [Examples](https://observablehq.com/@d3/treemap)
+
+Recursively partitions the specified *nodes* into an approximately-balanced binary tree, choosing horizontal partitioning for wide rectangles and vertical partitioning for tall rectangles.
+
+# d3.treemapDice(node, x0, y0, x1, y1) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/treemap/dice.js), [Examples](https://observablehq.com/@d3/treemap)
+
+Divides the rectangular area specified by *x0*, *y0*, *x1*, *y1* horizontally according the value of each of the specified *node*’s children. The children are positioned in order, starting with the left edge (*x0*) of the given rectangle. If the sum of the children’s values is less than the specified *node*’s value (*i.e.*, if the specified *node* has a non-zero internal value), the remaining empty space will be positioned on the right edge (*x1*) of the given rectangle.
+
+# d3.treemapSlice(node, x0, y0, x1, y1) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/treemap/slice.js), [Examples](https://observablehq.com/@d3/treemap)
+
+Divides the rectangular area specified by *x0*, *y0*, *x1*, *y1* vertically according the value of each of the specified *node*’s children. The children are positioned in order, starting with the top edge (*y0*) of the given rectangle. If the sum of the children’s values is less than the specified *node*’s value (*i.e.*, if the specified *node* has a non-zero internal value), the remaining empty space will be positioned on the bottom edge (*y1*) of the given rectangle.
+
+# d3.treemapSliceDice(node, x0, y0, x1, y1) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/treemap/sliceDice.js), [Examples](https://observablehq.com/@d3/treemap)
+
+If the specified *node* has odd depth, delegates to [treemapSlice](#treemapSlice); otherwise delegates to [treemapDice](#treemapDice).
+
+# d3.treemapSquarify(node, x0, y0, x1, y1) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/treemap/squarify.js), [Examples](https://observablehq.com/@d3/treemap)
+
+Implements the [squarified treemap](https://www.win.tue.nl/~vanwijk/stm.pdf) algorithm by Bruls *et al.*, which seeks to produce rectangles of a given [aspect ratio](#squarify_ratio).
+
+# d3.treemapResquarify(node, x0, y0, x1, y1) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/treemap/resquarify.js), [Examples](https://observablehq.com/@d3/animated-treemap)
+
+Like [d3.treemapSquarify](#treemapSquarify), except preserves the topology (node adjacencies) of the previous layout computed by d3.treemapResquarify, if there is one and it used the same [target aspect ratio](#squarify_ratio). This tiling method is good for animating changes to treemaps because it only changes node sizes and not their relative positions, thus avoiding distracting shuffling and occlusion. The downside of a stable update, however, is a suboptimal layout for subsequent updates: only the first layout uses the Bruls *et al.* squarified algorithm.
+
+# squarify.ratio(ratio) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/treemap/squarify.js), [Examples](https://observablehq.com/@d3/treemap)
+
+Specifies the desired aspect ratio of the generated rectangles. The *ratio* must be specified as a number greater than or equal to one. Note that the orientation of the generated rectangles (tall or wide) is not implied by the ratio; for example, a ratio of two will attempt to produce a mixture of rectangles whose *width*:*height* ratio is either 2:1 or 1:2. (However, you can approximately achieve this result by generating a square treemap at different dimensions, and then [stretching the treemap](https://observablehq.com/@d3/stretched-treemap) to the desired aspect ratio.) Furthermore, the specified *ratio* is merely a hint to the tiling algorithm; the rectangles are not guaranteed to have the specified aspect ratio. If not specified, the aspect ratio defaults to the golden ratio, φ = (1 + sqrt(5)) / 2, per [Kong *et al.*](http://vis.stanford.edu/papers/perception-treemaps)
+
+### Partition
+
+[
](https://observablehq.com/@d3/icicle)
+
+The **partition layout** produces adjacency diagrams: a space-filling variant of a node-link tree diagram. Rather than drawing a link between parent and child in the hierarchy, nodes are drawn as solid areas (either arcs or rectangles), and their placement relative to other nodes reveals their position in the hierarchy. The size of the nodes encodes a quantitative dimension that would be difficult to show in a node-link diagram.
+
+# d3.partition() · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/partition.js), [Examples](https://observablehq.com/@d3/icicle)
+
+Creates a new partition layout with the default settings.
+
+# partition(root)
+
+Lays out the specified *root* [hierarchy](#hierarchy), assigning the following properties on *root* and its descendants:
+
+* *node*.x0 - the left edge of the rectangle
+* *node*.y0 - the top edge of the rectangle
+* *node*.x1 - the right edge of the rectangle
+* *node*.y1 - the bottom edge of the rectangle
+
+You must call [*root*.sum](#node_sum) before passing the hierarchy to the partition layout. You probably also want to call [*root*.sort](#node_sort) to order the hierarchy before computing the layout.
+
+# partition.size([size])
+
+If *size* is specified, sets this partition layout’s size to the specified two-element array of numbers [*width*, *height*] and returns this partition layout. If *size* is not specified, returns the current size, which defaults to [1, 1].
+
+# partition.round([round])
+
+If *round* is specified, enables or disables rounding according to the given boolean and returns this partition layout. If *round* is not specified, returns the current rounding state, which defaults to false.
+
+# partition.padding([padding])
+
+If *padding* is specified, sets the padding to the specified number and returns this partition layout. If *padding* is not specified, returns the current padding, which defaults to zero. The padding is used to separate a node’s adjacent children.
+
+### Pack
+
+[
](https://observablehq.com/@d3/circle-packing)
+
+Enclosure diagrams use containment (nesting) to represent a hierarchy. The size of the leaf circles encodes a quantitative dimension of the data. The enclosing circles show the approximate cumulative size of each subtree, but due to wasted space there is some distortion; only the leaf nodes can be compared accurately. Although [circle packing](http://en.wikipedia.org/wiki/Circle_packing) does not use space as efficiently as a [treemap](#treemap), the “wasted†space more prominently reveals the hierarchical structure.
+
+# d3.pack() · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/pack/index.js), [Examples](https://observablehq.com/@d3/circle-packing)
+
+Creates a new pack layout with the default settings.
+
+# pack(root)
+
+Lays out the specified *root* [hierarchy](#hierarchy), assigning the following properties on *root* and its descendants:
+
+* *node*.x - the *x*-coordinate of the circle’s center
+* *node*.y - the *y*-coordinate of the circle’s center
+* *node*.r - the radius of the circle
+
+You must call [*root*.sum](#node_sum) before passing the hierarchy to the pack layout. You probably also want to call [*root*.sort](#node_sort) to order the hierarchy before computing the layout.
+
+# pack.radius([radius])
+
+If *radius* is specified, sets the pack layout’s radius accessor to the specified function and returns this pack layout. If *radius* is not specified, returns the current radius accessor, which defaults to null. If the radius accessor is null, the radius of each leaf circle is derived from the leaf *node*.value (computed by [*node*.sum](#node_sum)); the radii are then scaled proportionally to fit the [layout size](#pack_size). If the radius accessor is not null, the radius of each leaf circle is specified exactly by the function.
+
+# pack.size([size])
+
+If *size* is specified, sets this pack layout’s size to the specified two-element array of numbers [*width*, *height*] and returns this pack layout. If *size* is not specified, returns the current size, which defaults to [1, 1].
+
+# pack.padding([padding])
+
+If *padding* is specified, sets this pack layout’s padding accessor to the specified number or function and returns this pack layout. If *padding* is not specified, returns the current padding accessor, which defaults to the constant zero. When siblings are packed, tangent siblings will be separated by approximately the specified padding; the enclosing parent circle will also be separated from its children by approximately the specified padding. If an [explicit radius](#pack_radius) is not specified, the padding is approximate because a two-pass algorithm is needed to fit within the [layout size](#pack_size): the circles are first packed without padding; a scaling factor is computed and applied to the specified padding; and lastly the circles are re-packed with padding.
+
+# d3.packSiblings(circles) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/pack/siblings.js)
+
+Packs the specified array of *circles*, each of which must have a *circle*.r property specifying the circle’s radius. Assigns the following properties to each circle:
+
+* *circle*.x - the *x*-coordinate of the circle’s center
+* *circle*.y - the *y*-coordinate of the circle’s center
+
+The circles are positioned according to the front-chain packing algorithm by [Wang *et al.*](https://dl.acm.org/citation.cfm?id=1124851)
+
+# d3.packEnclose(circles) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/pack/enclose.js), [Examples](https://observablehq.com/@d3/d3-packenclose)
+
+Computes the [smallest circle](https://en.wikipedia.org/wiki/Smallest-circle_problem) that encloses the specified array of *circles*, each of which must have a *circle*.r property specifying the circle’s radius, and *circle*.x and *circle*.y properties specifying the circle’s center. The enclosing circle is computed using the [Matoušek-Sharir-Welzl algorithm](http://www.inf.ethz.ch/personal/emo/PublFiles/SubexLinProg_ALG16_96.pdf). (See also [Apollonius’ Problem](https://bl.ocks.org/mbostock/751fdd637f4bc2e3f08b).)
diff --git a/node_modules/d3-hierarchy/dist/d3-hierarchy.js b/node_modules/d3-hierarchy/dist/d3-hierarchy.js
new file mode 100644
index 00000000..83d6212b
--- /dev/null
+++ b/node_modules/d3-hierarchy/dist/d3-hierarchy.js
@@ -0,0 +1,1324 @@
+// https://d3js.org/d3-hierarchy/ v2.0.0 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+typeof define === 'function' && define.amd ? define(['exports'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}));
+}(this, function (exports) { 'use strict';
+
+function defaultSeparation(a, b) {
+ return a.parent === b.parent ? 1 : 2;
+}
+
+function meanX(children) {
+ return children.reduce(meanXReduce, 0) / children.length;
+}
+
+function meanXReduce(x, c) {
+ return x + c.x;
+}
+
+function maxY(children) {
+ return 1 + children.reduce(maxYReduce, 0);
+}
+
+function maxYReduce(y, c) {
+ return Math.max(y, c.y);
+}
+
+function leafLeft(node) {
+ var children;
+ while (children = node.children) node = children[0];
+ return node;
+}
+
+function leafRight(node) {
+ var children;
+ while (children = node.children) node = children[children.length - 1];
+ return node;
+}
+
+function cluster() {
+ var separation = defaultSeparation,
+ dx = 1,
+ dy = 1,
+ nodeSize = false;
+
+ function cluster(root) {
+ var previousNode,
+ x = 0;
+
+ // First walk, computing the initial x & y values.
+ root.eachAfter(function(node) {
+ var children = node.children;
+ if (children) {
+ node.x = meanX(children);
+ node.y = maxY(children);
+ } else {
+ node.x = previousNode ? x += separation(node, previousNode) : 0;
+ node.y = 0;
+ previousNode = node;
+ }
+ });
+
+ var left = leafLeft(root),
+ right = leafRight(root),
+ x0 = left.x - separation(left, right) / 2,
+ x1 = right.x + separation(right, left) / 2;
+
+ // Second walk, normalizing x & y to the desired size.
+ return root.eachAfter(nodeSize ? function(node) {
+ node.x = (node.x - root.x) * dx;
+ node.y = (root.y - node.y) * dy;
+ } : function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * dx;
+ node.y = (1 - (root.y ? node.y / root.y : 1)) * dy;
+ });
+ }
+
+ cluster.separation = function(x) {
+ return arguments.length ? (separation = x, cluster) : separation;
+ };
+
+ cluster.size = function(x) {
+ return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? null : [dx, dy]);
+ };
+
+ cluster.nodeSize = function(x) {
+ return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? [dx, dy] : null);
+ };
+
+ return cluster;
+}
+
+function count(node) {
+ var sum = 0,
+ children = node.children,
+ i = children && children.length;
+ if (!i) sum = 1;
+ else while (--i >= 0) sum += children[i].value;
+ node.value = sum;
+}
+
+function node_count() {
+ return this.eachAfter(count);
+}
+
+function node_each(callback, that) {
+ let index = -1;
+ for (const node of this) {
+ callback.call(that, node, ++index, this);
+ }
+ return this;
+}
+
+function node_eachBefore(callback, that) {
+ var node = this, nodes = [node], children, i, index = -1;
+ while (node = nodes.pop()) {
+ callback.call(that, node, ++index, this);
+ if (children = node.children) {
+ for (i = children.length - 1; i >= 0; --i) {
+ nodes.push(children[i]);
+ }
+ }
+ }
+ return this;
+}
+
+function node_eachAfter(callback, that) {
+ var node = this, nodes = [node], next = [], children, i, n, index = -1;
+ while (node = nodes.pop()) {
+ next.push(node);
+ if (children = node.children) {
+ for (i = 0, n = children.length; i < n; ++i) {
+ nodes.push(children[i]);
+ }
+ }
+ }
+ while (node = next.pop()) {
+ callback.call(that, node, ++index, this);
+ }
+ return this;
+}
+
+function node_find(callback, that) {
+ let index = -1;
+ for (const node of this) {
+ if (callback.call(that, node, ++index, this)) {
+ return node;
+ }
+ }
+}
+
+function node_sum(value) {
+ return this.eachAfter(function(node) {
+ var sum = +value(node.data) || 0,
+ children = node.children,
+ i = children && children.length;
+ while (--i >= 0) sum += children[i].value;
+ node.value = sum;
+ });
+}
+
+function node_sort(compare) {
+ return this.eachBefore(function(node) {
+ if (node.children) {
+ node.children.sort(compare);
+ }
+ });
+}
+
+function node_path(end) {
+ var start = this,
+ ancestor = leastCommonAncestor(start, end),
+ nodes = [start];
+ while (start !== ancestor) {
+ start = start.parent;
+ nodes.push(start);
+ }
+ var k = nodes.length;
+ while (end !== ancestor) {
+ nodes.splice(k, 0, end);
+ end = end.parent;
+ }
+ return nodes;
+}
+
+function leastCommonAncestor(a, b) {
+ if (a === b) return a;
+ var aNodes = a.ancestors(),
+ bNodes = b.ancestors(),
+ c = null;
+ a = aNodes.pop();
+ b = bNodes.pop();
+ while (a === b) {
+ c = a;
+ a = aNodes.pop();
+ b = bNodes.pop();
+ }
+ return c;
+}
+
+function node_ancestors() {
+ var node = this, nodes = [node];
+ while (node = node.parent) {
+ nodes.push(node);
+ }
+ return nodes;
+}
+
+function node_descendants() {
+ return Array.from(this);
+}
+
+function node_leaves() {
+ var leaves = [];
+ this.eachBefore(function(node) {
+ if (!node.children) {
+ leaves.push(node);
+ }
+ });
+ return leaves;
+}
+
+function node_links() {
+ var root = this, links = [];
+ root.each(function(node) {
+ if (node !== root) { // Don’t include the root’s parent, if any.
+ links.push({source: node.parent, target: node});
+ }
+ });
+ return links;
+}
+
+function* node_iterator() {
+ var node = this, current, next = [node], children, i, n;
+ do {
+ current = next.reverse(), next = [];
+ while (node = current.pop()) {
+ yield node;
+ if (children = node.children) {
+ for (i = 0, n = children.length; i < n; ++i) {
+ next.push(children[i]);
+ }
+ }
+ }
+ } while (next.length);
+}
+
+function hierarchy(data, children) {
+ if (data instanceof Map) {
+ data = [undefined, data];
+ if (children === undefined) children = mapChildren;
+ } else if (children === undefined) {
+ children = objectChildren;
+ }
+
+ var root = new Node(data),
+ node,
+ nodes = [root],
+ child,
+ childs,
+ i,
+ n;
+
+ while (node = nodes.pop()) {
+ if ((childs = children(node.data)) && (n = (childs = Array.from(childs)).length)) {
+ node.children = childs;
+ for (i = n - 1; i >= 0; --i) {
+ nodes.push(child = childs[i] = new Node(childs[i]));
+ child.parent = node;
+ child.depth = node.depth + 1;
+ }
+ }
+ }
+
+ return root.eachBefore(computeHeight);
+}
+
+function node_copy() {
+ return hierarchy(this).eachBefore(copyData);
+}
+
+function objectChildren(d) {
+ return d.children;
+}
+
+function mapChildren(d) {
+ return Array.isArray(d) ? d[1] : null;
+}
+
+function copyData(node) {
+ if (node.data.value !== undefined) node.value = node.data.value;
+ node.data = node.data.data;
+}
+
+function computeHeight(node) {
+ var height = 0;
+ do node.height = height;
+ while ((node = node.parent) && (node.height < ++height));
+}
+
+function Node(data) {
+ this.data = data;
+ this.depth =
+ this.height = 0;
+ this.parent = null;
+}
+
+Node.prototype = hierarchy.prototype = {
+ constructor: Node,
+ count: node_count,
+ each: node_each,
+ eachAfter: node_eachAfter,
+ eachBefore: node_eachBefore,
+ find: node_find,
+ sum: node_sum,
+ sort: node_sort,
+ path: node_path,
+ ancestors: node_ancestors,
+ descendants: node_descendants,
+ leaves: node_leaves,
+ links: node_links,
+ copy: node_copy,
+ [Symbol.iterator]: node_iterator
+};
+
+function array(x) {
+ return typeof x === "object" && "length" in x
+ ? x // Array, TypedArray, NodeList, array-like
+ : Array.from(x); // Map, Set, iterable, string, or anything else
+}
+
+function shuffle(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;
+}
+
+function enclose(circles) {
+ var i = 0, n = (circles = shuffle(Array.from(circles))).length, B = [], p, e;
+
+ while (i < n) {
+ p = circles[i];
+ if (e && enclosesWeak(e, p)) ++i;
+ else e = encloseBasis(B = extendBasis(B, p)), i = 0;
+ }
+
+ return e;
+}
+
+function extendBasis(B, p) {
+ var i, j;
+
+ if (enclosesWeakAll(p, B)) return [p];
+
+ // If we get here then B must have at least one element.
+ for (i = 0; i < B.length; ++i) {
+ if (enclosesNot(p, B[i])
+ && enclosesWeakAll(encloseBasis2(B[i], p), B)) {
+ return [B[i], p];
+ }
+ }
+
+ // If we get here then B must have at least two elements.
+ for (i = 0; i < B.length - 1; ++i) {
+ for (j = i + 1; j < B.length; ++j) {
+ if (enclosesNot(encloseBasis2(B[i], B[j]), p)
+ && enclosesNot(encloseBasis2(B[i], p), B[j])
+ && enclosesNot(encloseBasis2(B[j], p), B[i])
+ && enclosesWeakAll(encloseBasis3(B[i], B[j], p), B)) {
+ return [B[i], B[j], p];
+ }
+ }
+ }
+
+ // If we get here then something is very wrong.
+ throw new Error;
+}
+
+function enclosesNot(a, b) {
+ var dr = a.r - b.r, dx = b.x - a.x, dy = b.y - a.y;
+ return dr < 0 || dr * dr < dx * dx + dy * dy;
+}
+
+function enclosesWeak(a, b) {
+ var dr = a.r - b.r + Math.max(a.r, b.r, 1) * 1e-9, dx = b.x - a.x, dy = b.y - a.y;
+ return dr > 0 && dr * dr > dx * dx + dy * dy;
+}
+
+function enclosesWeakAll(a, B) {
+ for (var i = 0; i < B.length; ++i) {
+ if (!enclosesWeak(a, B[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function encloseBasis(B) {
+ switch (B.length) {
+ case 1: return encloseBasis1(B[0]);
+ case 2: return encloseBasis2(B[0], B[1]);
+ case 3: return encloseBasis3(B[0], B[1], B[2]);
+ }
+}
+
+function encloseBasis1(a) {
+ return {
+ x: a.x,
+ y: a.y,
+ r: a.r
+ };
+}
+
+function encloseBasis2(a, b) {
+ var x1 = a.x, y1 = a.y, r1 = a.r,
+ x2 = b.x, y2 = b.y, r2 = b.r,
+ x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
+ l = Math.sqrt(x21 * x21 + y21 * y21);
+ return {
+ x: (x1 + x2 + x21 / l * r21) / 2,
+ y: (y1 + y2 + y21 / l * r21) / 2,
+ r: (l + r1 + r2) / 2
+ };
+}
+
+function encloseBasis3(a, b, c) {
+ var x1 = a.x, y1 = a.y, r1 = a.r,
+ x2 = b.x, y2 = b.y, r2 = b.r,
+ x3 = c.x, y3 = c.y, r3 = c.r,
+ a2 = x1 - x2,
+ a3 = x1 - x3,
+ b2 = y1 - y2,
+ b3 = y1 - y3,
+ c2 = r2 - r1,
+ c3 = r3 - r1,
+ d1 = x1 * x1 + y1 * y1 - r1 * r1,
+ d2 = d1 - x2 * x2 - y2 * y2 + r2 * r2,
+ d3 = d1 - x3 * x3 - y3 * y3 + r3 * r3,
+ ab = a3 * b2 - a2 * b3,
+ xa = (b2 * d3 - b3 * d2) / (ab * 2) - x1,
+ xb = (b3 * c2 - b2 * c3) / ab,
+ ya = (a3 * d2 - a2 * d3) / (ab * 2) - y1,
+ yb = (a2 * c3 - a3 * c2) / ab,
+ A = xb * xb + yb * yb - 1,
+ B = 2 * (r1 + xa * xb + ya * yb),
+ C = xa * xa + ya * ya - r1 * r1,
+ r = -(A ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B);
+ return {
+ x: x1 + xa + xb * r,
+ y: y1 + ya + yb * r,
+ r: r
+ };
+}
+
+function place(b, a, c) {
+ var dx = b.x - a.x, x, a2,
+ dy = b.y - a.y, y, b2,
+ d2 = dx * dx + dy * dy;
+ if (d2) {
+ a2 = a.r + c.r, a2 *= a2;
+ b2 = b.r + c.r, b2 *= b2;
+ if (a2 > b2) {
+ x = (d2 + b2 - a2) / (2 * d2);
+ y = Math.sqrt(Math.max(0, b2 / d2 - x * x));
+ c.x = b.x - x * dx - y * dy;
+ c.y = b.y - x * dy + y * dx;
+ } else {
+ x = (d2 + a2 - b2) / (2 * d2);
+ y = Math.sqrt(Math.max(0, a2 / d2 - x * x));
+ c.x = a.x + x * dx - y * dy;
+ c.y = a.y + x * dy + y * dx;
+ }
+ } else {
+ c.x = a.x + c.r;
+ c.y = a.y;
+ }
+}
+
+function intersects(a, b) {
+ var dr = a.r + b.r - 1e-6, dx = b.x - a.x, dy = b.y - a.y;
+ return dr > 0 && dr * dr > dx * dx + dy * dy;
+}
+
+function score(node) {
+ var a = node._,
+ b = node.next._,
+ ab = a.r + b.r,
+ dx = (a.x * b.r + b.x * a.r) / ab,
+ dy = (a.y * b.r + b.y * a.r) / ab;
+ return dx * dx + dy * dy;
+}
+
+function Node$1(circle) {
+ this._ = circle;
+ this.next = null;
+ this.previous = null;
+}
+
+function packEnclose(circles) {
+ if (!(n = (circles = array(circles)).length)) return 0;
+
+ var a, b, c, n, aa, ca, i, j, k, sj, sk;
+
+ // Place the first circle.
+ a = circles[0], a.x = 0, a.y = 0;
+ if (!(n > 1)) return a.r;
+
+ // Place the second circle.
+ b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0;
+ if (!(n > 2)) return a.r + b.r;
+
+ // Place the third circle.
+ place(b, a, c = circles[2]);
+
+ // Initialize the front-chain using the first three circles a, b and c.
+ a = new Node$1(a), b = new Node$1(b), c = new Node$1(c);
+ a.next = c.previous = b;
+ b.next = a.previous = c;
+ c.next = b.previous = a;
+
+ // Attempt to place each remaining circle…
+ pack: for (i = 3; i < n; ++i) {
+ place(a._, b._, c = circles[i]), c = new Node$1(c);
+
+ // Find the closest intersecting circle on the front-chain, if any.
+ // “Closeness†is determined by linear distance along the front-chain.
+ // “Ahead†or “behind†is likewise determined by linear distance.
+ j = b.next, k = a.previous, sj = b._.r, sk = a._.r;
+ do {
+ if (sj <= sk) {
+ if (intersects(j._, c._)) {
+ b = j, a.next = b, b.previous = a, --i;
+ continue pack;
+ }
+ sj += j._.r, j = j.next;
+ } else {
+ if (intersects(k._, c._)) {
+ a = k, a.next = b, b.previous = a, --i;
+ continue pack;
+ }
+ sk += k._.r, k = k.previous;
+ }
+ } while (j !== k.next);
+
+ // Success! Insert the new circle c between a and b.
+ c.previous = a, c.next = b, a.next = b.previous = b = c;
+
+ // Compute the new closest circle pair to the centroid.
+ aa = score(a);
+ while ((c = c.next) !== b) {
+ if ((ca = score(c)) < aa) {
+ a = c, aa = ca;
+ }
+ }
+ b = a.next;
+ }
+
+ // Compute the enclosing circle of the front chain.
+ a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a);
+
+ // Translate the circles to put the enclosing circle around the origin.
+ for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
+
+ return c.r;
+}
+
+function siblings(circles) {
+ packEnclose(circles);
+ return circles;
+}
+
+function optional(f) {
+ return f == null ? null : required(f);
+}
+
+function required(f) {
+ if (typeof f !== "function") throw new Error;
+ return f;
+}
+
+function constantZero() {
+ return 0;
+}
+
+function constant(x) {
+ return function() {
+ return x;
+ };
+}
+
+function defaultRadius(d) {
+ return Math.sqrt(d.value);
+}
+
+function index() {
+ var radius = null,
+ dx = 1,
+ dy = 1,
+ padding = constantZero;
+
+ function pack(root) {
+ root.x = dx / 2, root.y = dy / 2;
+ if (radius) {
+ root.eachBefore(radiusLeaf(radius))
+ .eachAfter(packChildren(padding, 0.5))
+ .eachBefore(translateChild(1));
+ } else {
+ root.eachBefore(radiusLeaf(defaultRadius))
+ .eachAfter(packChildren(constantZero, 1))
+ .eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))
+ .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));
+ }
+ return root;
+ }
+
+ pack.radius = function(x) {
+ return arguments.length ? (radius = optional(x), pack) : radius;
+ };
+
+ pack.size = function(x) {
+ return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy];
+ };
+
+ pack.padding = function(x) {
+ return arguments.length ? (padding = typeof x === "function" ? x : constant(+x), pack) : padding;
+ };
+
+ return pack;
+}
+
+function radiusLeaf(radius) {
+ return function(node) {
+ if (!node.children) {
+ node.r = Math.max(0, +radius(node) || 0);
+ }
+ };
+}
+
+function packChildren(padding, k) {
+ return function(node) {
+ if (children = node.children) {
+ var children,
+ i,
+ n = children.length,
+ r = padding(node) * k || 0,
+ e;
+
+ if (r) for (i = 0; i < n; ++i) children[i].r += r;
+ e = packEnclose(children);
+ if (r) for (i = 0; i < n; ++i) children[i].r -= r;
+ node.r = e + r;
+ }
+ };
+}
+
+function translateChild(k) {
+ return function(node) {
+ var parent = node.parent;
+ node.r *= k;
+ if (parent) {
+ node.x = parent.x + k * node.x;
+ node.y = parent.y + k * node.y;
+ }
+ };
+}
+
+function roundNode(node) {
+ node.x0 = Math.round(node.x0);
+ node.y0 = Math.round(node.y0);
+ node.x1 = Math.round(node.x1);
+ node.y1 = Math.round(node.y1);
+}
+
+function treemapDice(parent, x0, y0, x1, y1) {
+ var nodes = parent.children,
+ node,
+ i = -1,
+ n = nodes.length,
+ k = parent.value && (x1 - x0) / parent.value;
+
+ while (++i < n) {
+ node = nodes[i], node.y0 = y0, node.y1 = y1;
+ node.x0 = x0, node.x1 = x0 += node.value * k;
+ }
+}
+
+function partition() {
+ var dx = 1,
+ dy = 1,
+ padding = 0,
+ round = false;
+
+ function partition(root) {
+ var n = root.height + 1;
+ root.x0 =
+ root.y0 = padding;
+ root.x1 = dx;
+ root.y1 = dy / n;
+ root.eachBefore(positionNode(dy, n));
+ if (round) root.eachBefore(roundNode);
+ return root;
+ }
+
+ function positionNode(dy, n) {
+ return function(node) {
+ if (node.children) {
+ treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n);
+ }
+ var x0 = node.x0,
+ y0 = node.y0,
+ x1 = node.x1 - padding,
+ y1 = node.y1 - padding;
+ if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
+ if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
+ node.x0 = x0;
+ node.y0 = y0;
+ node.x1 = x1;
+ node.y1 = y1;
+ };
+ }
+
+ partition.round = function(x) {
+ return arguments.length ? (round = !!x, partition) : round;
+ };
+
+ partition.size = function(x) {
+ return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy];
+ };
+
+ partition.padding = function(x) {
+ return arguments.length ? (padding = +x, partition) : padding;
+ };
+
+ return partition;
+}
+
+var preroot = {depth: -1},
+ ambiguous = {};
+
+function defaultId(d) {
+ return d.id;
+}
+
+function defaultParentId(d) {
+ return d.parentId;
+}
+
+function stratify() {
+ var id = defaultId,
+ parentId = defaultParentId;
+
+ function stratify(data) {
+ var nodes = Array.from(data),
+ n = nodes.length,
+ d,
+ i,
+ root,
+ parent,
+ node,
+ nodeId,
+ nodeKey,
+ nodeByKey = new Map;
+
+ for (i = 0; i < n; ++i) {
+ d = nodes[i], node = nodes[i] = new Node(d);
+ if ((nodeId = id(d, i, data)) != null && (nodeId += "")) {
+ nodeKey = node.id = nodeId;
+ nodeByKey.set(nodeKey, nodeByKey.has(nodeKey) ? ambiguous : node);
+ }
+ if ((nodeId = parentId(d, i, data)) != null && (nodeId += "")) {
+ node.parent = nodeId;
+ }
+ }
+
+ for (i = 0; i < n; ++i) {
+ node = nodes[i];
+ if (nodeId = node.parent) {
+ parent = nodeByKey.get(nodeId);
+ if (!parent) throw new Error("missing: " + nodeId);
+ if (parent === ambiguous) throw new Error("ambiguous: " + nodeId);
+ if (parent.children) parent.children.push(node);
+ else parent.children = [node];
+ node.parent = parent;
+ } else {
+ if (root) throw new Error("multiple roots");
+ root = node;
+ }
+ }
+
+ if (!root) throw new Error("no root");
+ root.parent = preroot;
+ root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
+ root.parent = null;
+ if (n > 0) throw new Error("cycle");
+
+ return root;
+ }
+
+ stratify.id = function(x) {
+ return arguments.length ? (id = required(x), stratify) : id;
+ };
+
+ stratify.parentId = function(x) {
+ return arguments.length ? (parentId = required(x), stratify) : parentId;
+ };
+
+ return stratify;
+}
+
+function defaultSeparation$1(a, b) {
+ return a.parent === b.parent ? 1 : 2;
+}
+
+// function radialSeparation(a, b) {
+// return (a.parent === b.parent ? 1 : 2) / a.depth;
+// }
+
+// This function is used to traverse the left contour of a subtree (or
+// subforest). It returns the successor of v on this contour. This successor is
+// either given by the leftmost child of v or by the thread of v. The function
+// returns null if and only if v is on the highest level of its subtree.
+function nextLeft(v) {
+ var children = v.children;
+ return children ? children[0] : v.t;
+}
+
+// This function works analogously to nextLeft.
+function nextRight(v) {
+ var children = v.children;
+ return children ? children[children.length - 1] : v.t;
+}
+
+// Shifts the current subtree rooted at w+. This is done by increasing
+// prelim(w+) and mod(w+) by shift.
+function moveSubtree(wm, wp, shift) {
+ var change = shift / (wp.i - wm.i);
+ wp.c -= change;
+ wp.s += shift;
+ wm.c += change;
+ wp.z += shift;
+ wp.m += shift;
+}
+
+// All other shifts, applied to the smaller subtrees between w- and w+, are
+// performed by this function. To prepare the shifts, we have to adjust
+// change(w+), shift(w+), and change(w-).
+function executeShifts(v) {
+ var shift = 0,
+ change = 0,
+ children = v.children,
+ i = children.length,
+ w;
+ while (--i >= 0) {
+ w = children[i];
+ w.z += shift;
+ w.m += shift;
+ shift += w.s + (change += w.c);
+ }
+}
+
+// If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise,
+// returns the specified (default) ancestor.
+function nextAncestor(vim, v, ancestor) {
+ return vim.a.parent === v.parent ? vim.a : ancestor;
+}
+
+function TreeNode(node, i) {
+ this._ = node;
+ this.parent = null;
+ this.children = null;
+ this.A = null; // default ancestor
+ this.a = this; // ancestor
+ this.z = 0; // prelim
+ this.m = 0; // mod
+ this.c = 0; // change
+ this.s = 0; // shift
+ this.t = null; // thread
+ this.i = i; // number
+}
+
+TreeNode.prototype = Object.create(Node.prototype);
+
+function treeRoot(root) {
+ var tree = new TreeNode(root, 0),
+ node,
+ nodes = [tree],
+ child,
+ children,
+ i,
+ n;
+
+ while (node = nodes.pop()) {
+ if (children = node._.children) {
+ node.children = new Array(n = children.length);
+ for (i = n - 1; i >= 0; --i) {
+ nodes.push(child = node.children[i] = new TreeNode(children[i], i));
+ child.parent = node;
+ }
+ }
+ }
+
+ (tree.parent = new TreeNode(null, 0)).children = [tree];
+ return tree;
+}
+
+// Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
+function tree() {
+ var separation = defaultSeparation$1,
+ dx = 1,
+ dy = 1,
+ nodeSize = null;
+
+ function tree(root) {
+ var t = treeRoot(root);
+
+ // Compute the layout using Buchheim et al.’s algorithm.
+ t.eachAfter(firstWalk), t.parent.m = -t.z;
+ t.eachBefore(secondWalk);
+
+ // If a fixed node size is specified, scale x and y.
+ if (nodeSize) root.eachBefore(sizeNode);
+
+ // If a fixed tree size is specified, scale x and y based on the extent.
+ // Compute the left-most, right-most, and depth-most nodes for extents.
+ else {
+ var left = root,
+ right = root,
+ bottom = root;
+ root.eachBefore(function(node) {
+ if (node.x < left.x) left = node;
+ if (node.x > right.x) right = node;
+ if (node.depth > bottom.depth) bottom = node;
+ });
+ var s = left === right ? 1 : separation(left, right) / 2,
+ tx = s - left.x,
+ kx = dx / (right.x + s + tx),
+ ky = dy / (bottom.depth || 1);
+ root.eachBefore(function(node) {
+ node.x = (node.x + tx) * kx;
+ node.y = node.depth * ky;
+ });
+ }
+
+ return root;
+ }
+
+ // Computes a preliminary x-coordinate for v. Before that, FIRST WALK is
+ // applied recursively to the children of v, as well as the function
+ // APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the
+ // node v is placed to the midpoint of its outermost children.
+ function firstWalk(v) {
+ var children = v.children,
+ siblings = v.parent.children,
+ w = v.i ? siblings[v.i - 1] : null;
+ if (children) {
+ executeShifts(v);
+ var midpoint = (children[0].z + children[children.length - 1].z) / 2;
+ if (w) {
+ v.z = w.z + separation(v._, w._);
+ v.m = v.z - midpoint;
+ } else {
+ v.z = midpoint;
+ }
+ } else if (w) {
+ v.z = w.z + separation(v._, w._);
+ }
+ v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
+ }
+
+ // Computes all real x-coordinates by summing up the modifiers recursively.
+ function secondWalk(v) {
+ v._.x = v.z + v.parent.m;
+ v.m += v.parent.m;
+ }
+
+ // The core of the algorithm. Here, a new subtree is combined with the
+ // previous subtrees. Threads are used to traverse the inside and outside
+ // contours of the left and right subtree up to the highest common level. The
+ // vertices used for the traversals are vi+, vi-, vo-, and vo+, where the
+ // superscript o means outside and i means inside, the subscript - means left
+ // subtree and + means right subtree. For summing up the modifiers along the
+ // contour, we use respective variables si+, si-, so-, and so+. Whenever two
+ // nodes of the inside contours conflict, we compute the left one of the
+ // greatest uncommon ancestors using the function ANCESTOR and call MOVE
+ // SUBTREE to shift the subtree and prepare the shifts of smaller subtrees.
+ // Finally, we add a new thread (if necessary).
+ function apportion(v, w, ancestor) {
+ if (w) {
+ var vip = v,
+ vop = v,
+ vim = w,
+ vom = vip.parent.children[0],
+ sip = vip.m,
+ sop = vop.m,
+ sim = vim.m,
+ som = vom.m,
+ shift;
+ while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) {
+ vom = nextLeft(vom);
+ vop = nextRight(vop);
+ vop.a = v;
+ shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
+ if (shift > 0) {
+ moveSubtree(nextAncestor(vim, v, ancestor), v, shift);
+ sip += shift;
+ sop += shift;
+ }
+ sim += vim.m;
+ sip += vip.m;
+ som += vom.m;
+ sop += vop.m;
+ }
+ if (vim && !nextRight(vop)) {
+ vop.t = vim;
+ vop.m += sim - sop;
+ }
+ if (vip && !nextLeft(vom)) {
+ vom.t = vip;
+ vom.m += sip - som;
+ ancestor = v;
+ }
+ }
+ return ancestor;
+ }
+
+ function sizeNode(node) {
+ node.x *= dx;
+ node.y = node.depth * dy;
+ }
+
+ tree.separation = function(x) {
+ return arguments.length ? (separation = x, tree) : separation;
+ };
+
+ tree.size = function(x) {
+ return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]);
+ };
+
+ tree.nodeSize = function(x) {
+ return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null);
+ };
+
+ return tree;
+}
+
+function treemapSlice(parent, x0, y0, x1, y1) {
+ var nodes = parent.children,
+ node,
+ i = -1,
+ n = nodes.length,
+ k = parent.value && (y1 - y0) / parent.value;
+
+ while (++i < n) {
+ node = nodes[i], node.x0 = x0, node.x1 = x1;
+ node.y0 = y0, node.y1 = y0 += node.value * k;
+ }
+}
+
+var phi = (1 + Math.sqrt(5)) / 2;
+
+function squarifyRatio(ratio, parent, x0, y0, x1, y1) {
+ var rows = [],
+ nodes = parent.children,
+ row,
+ nodeValue,
+ i0 = 0,
+ i1 = 0,
+ n = nodes.length,
+ dx, dy,
+ value = parent.value,
+ sumValue,
+ minValue,
+ maxValue,
+ newRatio,
+ minRatio,
+ alpha,
+ beta;
+
+ while (i0 < n) {
+ dx = x1 - x0, dy = y1 - y0;
+
+ // Find the next non-empty node.
+ do sumValue = nodes[i1++].value; while (!sumValue && i1 < n);
+ minValue = maxValue = sumValue;
+ alpha = Math.max(dy / dx, dx / dy) / (value * ratio);
+ beta = sumValue * sumValue * alpha;
+ minRatio = Math.max(maxValue / beta, beta / minValue);
+
+ // Keep adding nodes while the aspect ratio maintains or improves.
+ for (; i1 < n; ++i1) {
+ sumValue += nodeValue = nodes[i1].value;
+ if (nodeValue < minValue) minValue = nodeValue;
+ if (nodeValue > maxValue) maxValue = nodeValue;
+ beta = sumValue * sumValue * alpha;
+ newRatio = Math.max(maxValue / beta, beta / minValue);
+ if (newRatio > minRatio) { sumValue -= nodeValue; break; }
+ minRatio = newRatio;
+ }
+
+ // Position and record the row orientation.
+ rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)});
+ if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1);
+ else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1);
+ value -= sumValue, i0 = i1;
+ }
+
+ return rows;
+}
+
+var squarify = (function custom(ratio) {
+
+ function squarify(parent, x0, y0, x1, y1) {
+ squarifyRatio(ratio, parent, x0, y0, x1, y1);
+ }
+
+ squarify.ratio = function(x) {
+ return custom((x = +x) > 1 ? x : 1);
+ };
+
+ return squarify;
+})(phi);
+
+function index$1() {
+ var tile = squarify,
+ round = false,
+ dx = 1,
+ dy = 1,
+ paddingStack = [0],
+ paddingInner = constantZero,
+ paddingTop = constantZero,
+ paddingRight = constantZero,
+ paddingBottom = constantZero,
+ paddingLeft = constantZero;
+
+ function treemap(root) {
+ root.x0 =
+ root.y0 = 0;
+ root.x1 = dx;
+ root.y1 = dy;
+ root.eachBefore(positionNode);
+ paddingStack = [0];
+ if (round) root.eachBefore(roundNode);
+ return root;
+ }
+
+ function positionNode(node) {
+ var p = paddingStack[node.depth],
+ x0 = node.x0 + p,
+ y0 = node.y0 + p,
+ x1 = node.x1 - p,
+ y1 = node.y1 - p;
+ if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
+ if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
+ node.x0 = x0;
+ node.y0 = y0;
+ node.x1 = x1;
+ node.y1 = y1;
+ if (node.children) {
+ p = paddingStack[node.depth + 1] = paddingInner(node) / 2;
+ x0 += paddingLeft(node) - p;
+ y0 += paddingTop(node) - p;
+ x1 -= paddingRight(node) - p;
+ y1 -= paddingBottom(node) - p;
+ if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
+ if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
+ tile(node, x0, y0, x1, y1);
+ }
+ }
+
+ treemap.round = function(x) {
+ return arguments.length ? (round = !!x, treemap) : round;
+ };
+
+ treemap.size = function(x) {
+ return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy];
+ };
+
+ treemap.tile = function(x) {
+ return arguments.length ? (tile = required(x), treemap) : tile;
+ };
+
+ treemap.padding = function(x) {
+ return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner();
+ };
+
+ treemap.paddingInner = function(x) {
+ return arguments.length ? (paddingInner = typeof x === "function" ? x : constant(+x), treemap) : paddingInner;
+ };
+
+ treemap.paddingOuter = function(x) {
+ return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop();
+ };
+
+ treemap.paddingTop = function(x) {
+ return arguments.length ? (paddingTop = typeof x === "function" ? x : constant(+x), treemap) : paddingTop;
+ };
+
+ treemap.paddingRight = function(x) {
+ return arguments.length ? (paddingRight = typeof x === "function" ? x : constant(+x), treemap) : paddingRight;
+ };
+
+ treemap.paddingBottom = function(x) {
+ return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant(+x), treemap) : paddingBottom;
+ };
+
+ treemap.paddingLeft = function(x) {
+ return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant(+x), treemap) : paddingLeft;
+ };
+
+ return treemap;
+}
+
+function binary(parent, x0, y0, x1, y1) {
+ var nodes = parent.children,
+ i, n = nodes.length,
+ sum, sums = new Array(n + 1);
+
+ for (sums[0] = sum = i = 0; i < n; ++i) {
+ sums[i + 1] = sum += nodes[i].value;
+ }
+
+ partition(0, n, parent.value, x0, y0, x1, y1);
+
+ function partition(i, j, value, x0, y0, x1, y1) {
+ if (i >= j - 1) {
+ var node = nodes[i];
+ node.x0 = x0, node.y0 = y0;
+ node.x1 = x1, node.y1 = y1;
+ return;
+ }
+
+ var valueOffset = sums[i],
+ valueTarget = (value / 2) + valueOffset,
+ k = i + 1,
+ hi = j - 1;
+
+ while (k < hi) {
+ var mid = k + hi >>> 1;
+ if (sums[mid] < valueTarget) k = mid + 1;
+ else hi = mid;
+ }
+
+ if ((valueTarget - sums[k - 1]) < (sums[k] - valueTarget) && i + 1 < k) --k;
+
+ var valueLeft = sums[k] - valueOffset,
+ valueRight = value - valueLeft;
+
+ if ((x1 - x0) > (y1 - y0)) {
+ var xk = value ? (x0 * valueRight + x1 * valueLeft) / value : x1;
+ partition(i, k, valueLeft, x0, y0, xk, y1);
+ partition(k, j, valueRight, xk, y0, x1, y1);
+ } else {
+ var yk = value ? (y0 * valueRight + y1 * valueLeft) / value : y1;
+ partition(i, k, valueLeft, x0, y0, x1, yk);
+ partition(k, j, valueRight, x0, yk, x1, y1);
+ }
+ }
+}
+
+function sliceDice(parent, x0, y0, x1, y1) {
+ (parent.depth & 1 ? treemapSlice : treemapDice)(parent, x0, y0, x1, y1);
+}
+
+var resquarify = (function custom(ratio) {
+
+ function resquarify(parent, x0, y0, x1, y1) {
+ if ((rows = parent._squarify) && (rows.ratio === ratio)) {
+ var rows,
+ row,
+ nodes,
+ i,
+ j = -1,
+ n,
+ m = rows.length,
+ value = parent.value;
+
+ while (++j < m) {
+ row = rows[j], nodes = row.children;
+ for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value;
+ if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += (y1 - y0) * row.value / value : y1);
+ else treemapSlice(row, x0, y0, value ? x0 += (x1 - x0) * row.value / value : x1, y1);
+ value -= row.value;
+ }
+ } else {
+ parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1);
+ rows.ratio = ratio;
+ }
+ }
+
+ resquarify.ratio = function(x) {
+ return custom((x = +x) > 1 ? x : 1);
+ };
+
+ return resquarify;
+})(phi);
+
+exports.cluster = cluster;
+exports.hierarchy = hierarchy;
+exports.pack = index;
+exports.packEnclose = enclose;
+exports.packSiblings = siblings;
+exports.partition = partition;
+exports.stratify = stratify;
+exports.tree = tree;
+exports.treemap = index$1;
+exports.treemapBinary = binary;
+exports.treemapDice = treemapDice;
+exports.treemapResquarify = resquarify;
+exports.treemapSlice = treemapSlice;
+exports.treemapSliceDice = sliceDice;
+exports.treemapSquarify = squarify;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-hierarchy/dist/d3-hierarchy.min.js b/node_modules/d3-hierarchy/dist/d3-hierarchy.min.js
new file mode 100644
index 00000000..23f6f723
--- /dev/null
+++ b/node_modules/d3-hierarchy/dist/d3-hierarchy.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-hierarchy/ v2.0.0 Copyright 2020 Mike Bostock
+!function(n,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r((n=n||self).d3=n.d3||{})}(this,function(n){"use strict";function r(n,r){return n.parent===r.parent?1:2}function t(n,r){return n+r.x}function e(n,r){return Math.max(n,r.y)}function i(n){var r=0,t=n.children,e=t&&t.length;if(e)for(;--e>=0;)r+=t[e].value;else r=1;n.value=r}function u(n,r){n instanceof Map?(n=[void 0,n],void 0===r&&(r=a)):void 0===r&&(r=o);for(var t,e,i,u,f,h=new Node(n),l=[h];t=l.pop();)if((i=r(t.data))&&(f=(i=Array.from(i)).length))for(t.children=i,u=f-1;u>=0;--u)l.push(e=i[u]=new Node(i[u])),e.parent=t,e.depth=t.depth+1;return h.eachBefore(c)}function o(n){return n.children}function a(n){return Array.isArray(n)?n[1]:null}function f(n){void 0!==n.data.value&&(n.value=n.data.value),n.data=n.data.data}function c(n){var r=0;do{n.height=r}while((n=n.parent)&&n.height<++r)}function Node(n){this.data=n,this.depth=this.height=0,this.parent=null}function h(n){for(var r,t,e=0,i=(n=function(n){for(var r,t,e=n.length;e;)t=Math.random()*e--|0,r=n[e],n[e]=n[t],n[t]=r;return n}(Array.from(n))).length,u=[];e0&&t*t>e*e+i*i}function s(n,r){for(var t=0;t>>1;c[v]
+
+Or, with a corrected [gamma](#interpolate_gamma) of 2.2:
+
+
+
+Returns an RGB color space interpolator between the two colors *a* and *b* with a configurable [gamma](#interpolate_gamma). If the gamma is not specified, it defaults to 1.0. The colors *a* and *b* need not be in RGB; they will be converted to RGB using [d3.rgb](https://github.com/d3/d3-color/blob/master/README.md#rgb). The return value of the interpolator is an RGB string.
+
+# d3.interpolateRgbBasis(colors) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/rgb.js#L54), [Examples](https://observablehq.com/@d3/working-with-color)
+
+Returns a uniform nonrational B-spline interpolator through the specified array of *colors*, which are converted to [RGB color space](https://github.com/d3/d3-color/blob/master/README.md#rgb). Implicit control points are generated such that the interpolator returns *colors*[0] at *t* = 0 and *colors*[*colors*.length - 1] at *t* = 1. Opacity interpolation is not currently supported. See also [d3.interpolateBasis](#interpolateBasis), and see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic) for examples.
+
+# d3.interpolateRgbBasisClosed(colors) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/rgb.js#L55), [Examples](https://observablehq.com/@d3/working-with-color)
+
+Returns a uniform nonrational B-spline interpolator through the specified array of *colors*, which are converted to [RGB color space](https://github.com/d3/d3-color/blob/master/README.md#rgb). The control points are implicitly repeated such that the resulting spline has cyclical C² continuity when repeated around *t* in [0,1]; this is useful, for example, to create cyclical color scales. Opacity interpolation is not currently supported. See also [d3.interpolateBasisClosed](#interpolateBasisClosed), and see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic) for examples.
+
+# d3.interpolateHsl(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/hsl.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Returns an HSL color space interpolator between the two colors *a* and *b*. The colors *a* and *b* need not be in HSL; they will be converted to HSL using [d3.hsl](https://github.com/d3/d3-color/blob/master/README.md#hsl). If either color’s hue or saturation is NaN, the opposing color’s channel value is used. The shortest path between hues is used. The return value of the interpolator is an RGB string.
+
+# d3.interpolateHslLong(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/hsl.js#L21), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Like [interpolateHsl](#interpolateHsl), but does not use the shortest path between hues.
+
+# d3.interpolateLab(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/lab.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Returns a [CIELAB color space](https://en.wikipedia.org/wiki/Lab_color_space#CIELAB) interpolator between the two colors *a* and *b*. The colors *a* and *b* need not be in CIELAB; they will be converted to CIELAB using [d3.lab](https://github.com/d3/d3-color/blob/master/README.md#lab). The return value of the interpolator is an RGB string.
+
+# d3.interpolateHcl(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/hcl.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Returns a [CIELChab color space](https://en.wikipedia.org/wiki/CIELAB_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC) interpolator between the two colors *a* and *b*. The colors *a* and *b* need not be in CIELChab; they will be converted to CIELChab using [d3.hcl](https://github.com/d3/d3-color/blob/master/README.md#hcl). If either color’s hue or chroma is NaN, the opposing color’s channel value is used. The shortest path between hues is used. The return value of the interpolator is an RGB string.
+
+# d3.interpolateHclLong(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/hcl.js#L21), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Like [interpolateHcl](#interpolateHcl), but does not use the shortest path between hues.
+
+# d3.interpolateCubehelix(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/cubehelix.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Or, with a [gamma](#interpolate_gamma) of 3.0 to emphasize high-intensity values:
+
+
+
+Returns a Cubehelix color space interpolator between the two colors *a* and *b* using a configurable [gamma](#interpolate_gamma). If the gamma is not specified, it defaults to 1.0. The colors *a* and *b* need not be in Cubehelix; they will be converted to Cubehelix using [d3.cubehelix](https://github.com/d3/d3-color/blob/master/README.md#cubehelix). If either color’s hue or saturation is NaN, the opposing color’s channel value is used. The shortest path between hues is used. The return value of the interpolator is an RGB string.
+
+# d3.interpolateCubehelixLong(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/cubehelix.js#L29), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Or, with a [gamma](#interpolate_gamma) of 3.0 to emphasize high-intensity values:
+
+
+
+Like [interpolateCubehelix](#interpolateCubehelix), but does not use the shortest path between hues.
+
+# interpolate.gamma(gamma)
+
+Given that *interpolate* is one of [interpolateRgb](#interpolateRgb), [interpolateCubehelix](#interpolateCubehelix) or [interpolateCubehelixLong](#interpolateCubehelixLong), returns a new interpolator factory of the same type using the specified *gamma*. For example, to interpolate from purple to orange with a gamma of 2.2 in RGB space:
+
+```js
+var interpolator = d3.interpolateRgb.gamma(2.2)("purple", "orange");
+```
+
+See Eric Brasseur’s article, [Gamma error in picture scaling](http://www.ericbrasseur.org/gamma.html), for more on gamma correction.
+
+# d3.interpolateHue(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/hue.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+Returns an interpolator between the two hue angles *a* and *b*. If either hue is NaN, the opposing value is used. The shortest path between hues is used. The return value of the interpolator is a number in [0, 360).
+
+### Splines
+
+Whereas standard interpolators blend from a starting value *a* at *t* = 0 to an ending value *b* at *t* = 1, spline interpolators smoothly blend multiple input values for *t* in [0,1] using piecewise polynomial functions. Only cubic uniform nonrational [B-splines](https://en.wikipedia.org/wiki/B-spline) are currently supported, also known as basis splines.
+
+# d3.interpolateBasis(values) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/basis.js), [Examples](https://observablehq.com/@d3/d3-interpolatebasis)
+
+Returns a uniform nonrational B-spline interpolator through the specified array of *values*, which must be numbers. Implicit control points are generated such that the interpolator returns *values*[0] at *t* = 0 and *values*[*values*.length - 1] at *t* = 1. See also [d3.curveBasis](https://github.com/d3/d3-shape/blob/master/README.md#curveBasis).
+
+# d3.interpolateBasisClosed(values) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/basisClosed.js), [Examples](https://observablehq.com/@d3/d3-interpolatebasis)
+
+Returns a uniform nonrational B-spline interpolator through the specified array of *values*, which must be numbers. The control points are implicitly repeated such that the resulting one-dimensional spline has cyclical C² continuity when repeated around *t* in [0,1]. See also [d3.curveBasisClosed](https://github.com/d3/d3-shape/blob/master/README.md#curveBasisClosed).
+
+### Piecewise
+
+# d3.piecewise([interpolate, ]values) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/piecewise.js), [Examples](https://observablehq.com/@d3/d3-piecewise)
+
+Returns a piecewise interpolator, composing interpolators for each adjacent pair of *values*. The returned interpolator maps *t* in [0, 1 / (*n* - 1)] to *interpolate*(*values*[0], *values*[1]), *t* in [1 / (*n* - 1), 2 / (*n* - 1)] to *interpolate*(*values*[1], *values*[2]), and so on, where *n* = *values*.length. In effect, this is a lightweight [linear scale](https://github.com/d3/d3-scale/blob/master/README.md#linear-scales). For example, to blend through red, green and blue:
+
+```js
+var interpolate = d3.piecewise(d3.interpolateRgb.gamma(2.2), ["red", "green", "blue"]);
+```
+
+If *interpolate* is not specified, defaults to [d3.interpolate](#interpolate).
diff --git a/node_modules/d3-interpolate/dist/d3-interpolate.js b/node_modules/d3-interpolate/dist/d3-interpolate.js
new file mode 100644
index 00000000..387e7a65
--- /dev/null
+++ b/node_modules/d3-interpolate/dist/d3-interpolate.js
@@ -0,0 +1,590 @@
+// https://d3js.org/d3-interpolate/ v2.0.1 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-color')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-color'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}, global.d3));
+}(this, function (exports, d3Color) { 'use strict';
+
+function basis(t1, v0, v1, v2, v3) {
+ var t2 = t1 * t1, t3 = t2 * t1;
+ return ((1 - 3 * t1 + 3 * t2 - t3) * v0
+ + (4 - 6 * t2 + 3 * t3) * v1
+ + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
+ + t3 * v3) / 6;
+}
+
+function basis$1(values) {
+ var n = values.length - 1;
+ return function(t) {
+ var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
+ v1 = values[i],
+ v2 = values[i + 1],
+ v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
+ v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
+ return basis((t - i / n) * n, v0, v1, v2, v3);
+ };
+}
+
+function basisClosed(values) {
+ var n = values.length;
+ return function(t) {
+ var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
+ v0 = values[(i + n - 1) % n],
+ v1 = values[i % n],
+ v2 = values[(i + 1) % n],
+ v3 = values[(i + 2) % n];
+ return basis((t - i / n) * n, v0, v1, v2, v3);
+ };
+}
+
+var constant = x => () => x;
+
+function linear(a, d) {
+ return function(t) {
+ return a + t * d;
+ };
+}
+
+function exponential(a, b, y) {
+ return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
+ return Math.pow(a + t * b, y);
+ };
+}
+
+function hue(a, b) {
+ var d = b - a;
+ return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant(isNaN(a) ? b : a);
+}
+
+function gamma(y) {
+ return (y = +y) === 1 ? nogamma : function(a, b) {
+ return b - a ? exponential(a, b, y) : constant(isNaN(a) ? b : a);
+ };
+}
+
+function nogamma(a, b) {
+ var d = b - a;
+ return d ? linear(a, d) : constant(isNaN(a) ? b : a);
+}
+
+var rgb = (function rgbGamma(y) {
+ var color = gamma(y);
+
+ function rgb(start, end) {
+ var r = color((start = d3Color.rgb(start)).r, (end = d3Color.rgb(end)).r),
+ g = color(start.g, end.g),
+ b = color(start.b, end.b),
+ opacity = nogamma(start.opacity, end.opacity);
+ return function(t) {
+ start.r = r(t);
+ start.g = g(t);
+ start.b = b(t);
+ start.opacity = opacity(t);
+ return start + "";
+ };
+ }
+
+ rgb.gamma = rgbGamma;
+
+ return rgb;
+})(1);
+
+function rgbSpline(spline) {
+ return function(colors) {
+ var n = colors.length,
+ r = new Array(n),
+ g = new Array(n),
+ b = new Array(n),
+ i, color;
+ for (i = 0; i < n; ++i) {
+ color = d3Color.rgb(colors[i]);
+ r[i] = color.r || 0;
+ g[i] = color.g || 0;
+ b[i] = color.b || 0;
+ }
+ r = spline(r);
+ g = spline(g);
+ b = spline(b);
+ color.opacity = 1;
+ return function(t) {
+ color.r = r(t);
+ color.g = g(t);
+ color.b = b(t);
+ return color + "";
+ };
+ };
+}
+
+var rgbBasis = rgbSpline(basis$1);
+var rgbBasisClosed = rgbSpline(basisClosed);
+
+function numberArray(a, b) {
+ if (!b) b = [];
+ var n = a ? Math.min(b.length, a.length) : 0,
+ c = b.slice(),
+ i;
+ return function(t) {
+ for (i = 0; i < n; ++i) c[i] = a[i] * (1 - t) + b[i] * t;
+ return c;
+ };
+}
+
+function isNumberArray(x) {
+ return ArrayBuffer.isView(x) && !(x instanceof DataView);
+}
+
+function array(a, b) {
+ return (isNumberArray(b) ? numberArray : genericArray)(a, b);
+}
+
+function genericArray(a, b) {
+ var nb = b ? b.length : 0,
+ na = a ? Math.min(nb, a.length) : 0,
+ x = new Array(na),
+ c = new Array(nb),
+ i;
+
+ for (i = 0; i < na; ++i) x[i] = value(a[i], b[i]);
+ for (; i < nb; ++i) c[i] = b[i];
+
+ return function(t) {
+ for (i = 0; i < na; ++i) c[i] = x[i](t);
+ return c;
+ };
+}
+
+function date(a, b) {
+ var d = new Date;
+ return a = +a, b = +b, function(t) {
+ return d.setTime(a * (1 - t) + b * t), d;
+ };
+}
+
+function number(a, b) {
+ return a = +a, b = +b, function(t) {
+ return a * (1 - t) + b * t;
+ };
+}
+
+function object(a, b) {
+ var i = {},
+ c = {},
+ k;
+
+ if (a === null || typeof a !== "object") a = {};
+ if (b === null || typeof b !== "object") b = {};
+
+ for (k in b) {
+ if (k in a) {
+ i[k] = value(a[k], b[k]);
+ } else {
+ c[k] = b[k];
+ }
+ }
+
+ return function(t) {
+ for (k in i) c[k] = i[k](t);
+ return c;
+ };
+}
+
+var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
+ reB = new RegExp(reA.source, "g");
+
+function zero(b) {
+ return function() {
+ return b;
+ };
+}
+
+function one(b) {
+ return function(t) {
+ return b(t) + "";
+ };
+}
+
+function string(a, b) {
+ var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
+ am, // current match in a
+ bm, // current match in b
+ bs, // string preceding current number in b, if any
+ i = -1, // index in s
+ s = [], // string constants and placeholders
+ q = []; // number interpolators
+
+ // Coerce inputs to strings.
+ a = a + "", b = b + "";
+
+ // Interpolate pairs of numbers in a & b.
+ while ((am = reA.exec(a))
+ && (bm = reB.exec(b))) {
+ if ((bs = bm.index) > bi) { // a string precedes the next number in b
+ bs = b.slice(bi, bs);
+ if (s[i]) s[i] += bs; // coalesce with previous string
+ else s[++i] = bs;
+ }
+ if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
+ if (s[i]) s[i] += bm; // coalesce with previous string
+ else s[++i] = bm;
+ } else { // interpolate non-matching numbers
+ s[++i] = null;
+ q.push({i: i, x: number(am, bm)});
+ }
+ bi = reB.lastIndex;
+ }
+
+ // Add remains of b.
+ if (bi < b.length) {
+ bs = b.slice(bi);
+ if (s[i]) s[i] += bs; // coalesce with previous string
+ else s[++i] = bs;
+ }
+
+ // Special optimization for only a single match.
+ // Otherwise, interpolate each of the numbers and rejoin the string.
+ return s.length < 2 ? (q[0]
+ ? one(q[0].x)
+ : zero(b))
+ : (b = q.length, function(t) {
+ for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ });
+}
+
+function value(a, b) {
+ var t = typeof b, c;
+ return b == null || t === "boolean" ? constant(b)
+ : (t === "number" ? number
+ : t === "string" ? ((c = d3Color.color(b)) ? (b = c, rgb) : string)
+ : b instanceof d3Color.color ? rgb
+ : b instanceof Date ? date
+ : isNumberArray(b) ? numberArray
+ : Array.isArray(b) ? genericArray
+ : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
+ : number)(a, b);
+}
+
+function discrete(range) {
+ var n = range.length;
+ return function(t) {
+ return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
+ };
+}
+
+function hue$1(a, b) {
+ var i = hue(+a, +b);
+ return function(t) {
+ var x = i(t);
+ return x - 360 * Math.floor(x / 360);
+ };
+}
+
+function round(a, b) {
+ return a = +a, b = +b, function(t) {
+ return Math.round(a * (1 - t) + b * t);
+ };
+}
+
+var degrees = 180 / Math.PI;
+
+var identity = {
+ translateX: 0,
+ translateY: 0,
+ rotate: 0,
+ skewX: 0,
+ scaleX: 1,
+ scaleY: 1
+};
+
+function decompose(a, b, c, d, e, f) {
+ var scaleX, scaleY, skewX;
+ if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
+ if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
+ if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
+ if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
+ return {
+ translateX: e,
+ translateY: f,
+ rotate: Math.atan2(b, a) * degrees,
+ skewX: Math.atan(skewX) * degrees,
+ scaleX: scaleX,
+ scaleY: scaleY
+ };
+}
+
+var svgNode;
+
+/* eslint-disable no-undef */
+function parseCss(value) {
+ const m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
+ return m.isIdentity ? identity : decompose(m.a, m.b, m.c, m.d, m.e, m.f);
+}
+
+function parseSvg(value) {
+ if (value == null) return identity;
+ if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
+ svgNode.setAttribute("transform", value);
+ if (!(value = svgNode.transform.baseVal.consolidate())) return identity;
+ value = value.matrix;
+ return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
+}
+
+function interpolateTransform(parse, pxComma, pxParen, degParen) {
+
+ function pop(s) {
+ return s.length ? s.pop() + " " : "";
+ }
+
+ function translate(xa, ya, xb, yb, s, q) {
+ if (xa !== xb || ya !== yb) {
+ var i = s.push("translate(", null, pxComma, null, pxParen);
+ q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});
+ } else if (xb || yb) {
+ s.push("translate(" + xb + pxComma + yb + pxParen);
+ }
+ }
+
+ function rotate(a, b, s, q) {
+ if (a !== b) {
+ if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
+ q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: number(a, b)});
+ } else if (b) {
+ s.push(pop(s) + "rotate(" + b + degParen);
+ }
+ }
+
+ function skewX(a, b, s, q) {
+ if (a !== b) {
+ q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: number(a, b)});
+ } else if (b) {
+ s.push(pop(s) + "skewX(" + b + degParen);
+ }
+ }
+
+ function scale(xa, ya, xb, yb, s, q) {
+ if (xa !== xb || ya !== yb) {
+ var i = s.push(pop(s) + "scale(", null, ",", null, ")");
+ q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});
+ } else if (xb !== 1 || yb !== 1) {
+ s.push(pop(s) + "scale(" + xb + "," + yb + ")");
+ }
+ }
+
+ return function(a, b) {
+ var s = [], // string constants and placeholders
+ q = []; // number interpolators
+ a = parse(a), b = parse(b);
+ translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
+ rotate(a.rotate, b.rotate, s, q);
+ skewX(a.skewX, b.skewX, s, q);
+ scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
+ a = b = null; // gc
+ return function(t) {
+ var i = -1, n = q.length, o;
+ while (++i < n) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ };
+ };
+}
+
+var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
+var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
+
+var epsilon2 = 1e-12;
+
+function cosh(x) {
+ return ((x = Math.exp(x)) + 1 / x) / 2;
+}
+
+function sinh(x) {
+ return ((x = Math.exp(x)) - 1 / x) / 2;
+}
+
+function tanh(x) {
+ return ((x = Math.exp(2 * x)) - 1) / (x + 1);
+}
+
+var zoom = (function zoomRho(rho, rho2, rho4) {
+
+ // p0 = [ux0, uy0, w0]
+ // p1 = [ux1, uy1, w1]
+ function zoom(p0, p1) {
+ var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
+ ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
+ dx = ux1 - ux0,
+ dy = uy1 - uy0,
+ d2 = dx * dx + dy * dy,
+ i,
+ S;
+
+ // Special case for u0 ≅ u1.
+ if (d2 < epsilon2) {
+ S = Math.log(w1 / w0) / rho;
+ i = function(t) {
+ return [
+ ux0 + t * dx,
+ uy0 + t * dy,
+ w0 * Math.exp(rho * t * S)
+ ];
+ };
+ }
+
+ // General case.
+ else {
+ var d1 = Math.sqrt(d2),
+ b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
+ b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
+ r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
+ r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
+ S = (r1 - r0) / rho;
+ i = function(t) {
+ var s = t * S,
+ coshr0 = cosh(r0),
+ u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
+ return [
+ ux0 + u * dx,
+ uy0 + u * dy,
+ w0 * coshr0 / cosh(rho * s + r0)
+ ];
+ };
+ }
+
+ i.duration = S * 1000 * rho / Math.SQRT2;
+
+ return i;
+ }
+
+ zoom.rho = function(_) {
+ var _1 = Math.max(1e-3, +_), _2 = _1 * _1, _4 = _2 * _2;
+ return zoomRho(_1, _2, _4);
+ };
+
+ return zoom;
+})(Math.SQRT2, 2, 4);
+
+function hsl(hue) {
+ return function(start, end) {
+ var h = hue((start = d3Color.hsl(start)).h, (end = d3Color.hsl(end)).h),
+ s = nogamma(start.s, end.s),
+ l = nogamma(start.l, end.l),
+ opacity = nogamma(start.opacity, end.opacity);
+ return function(t) {
+ start.h = h(t);
+ start.s = s(t);
+ start.l = l(t);
+ start.opacity = opacity(t);
+ return start + "";
+ };
+ }
+}
+
+var hsl$1 = hsl(hue);
+var hslLong = hsl(nogamma);
+
+function lab(start, end) {
+ var l = nogamma((start = d3Color.lab(start)).l, (end = d3Color.lab(end)).l),
+ a = nogamma(start.a, end.a),
+ b = nogamma(start.b, end.b),
+ opacity = nogamma(start.opacity, end.opacity);
+ return function(t) {
+ start.l = l(t);
+ start.a = a(t);
+ start.b = b(t);
+ start.opacity = opacity(t);
+ return start + "";
+ };
+}
+
+function hcl(hue) {
+ return function(start, end) {
+ var h = hue((start = d3Color.hcl(start)).h, (end = d3Color.hcl(end)).h),
+ c = nogamma(start.c, end.c),
+ l = nogamma(start.l, end.l),
+ opacity = nogamma(start.opacity, end.opacity);
+ return function(t) {
+ start.h = h(t);
+ start.c = c(t);
+ start.l = l(t);
+ start.opacity = opacity(t);
+ return start + "";
+ };
+ }
+}
+
+var hcl$1 = hcl(hue);
+var hclLong = hcl(nogamma);
+
+function cubehelix(hue) {
+ return (function cubehelixGamma(y) {
+ y = +y;
+
+ function cubehelix(start, end) {
+ var h = hue((start = d3Color.cubehelix(start)).h, (end = d3Color.cubehelix(end)).h),
+ s = nogamma(start.s, end.s),
+ l = nogamma(start.l, end.l),
+ opacity = nogamma(start.opacity, end.opacity);
+ return function(t) {
+ start.h = h(t);
+ start.s = s(t);
+ start.l = l(Math.pow(t, y));
+ start.opacity = opacity(t);
+ return start + "";
+ };
+ }
+
+ cubehelix.gamma = cubehelixGamma;
+
+ return cubehelix;
+ })(1);
+}
+
+var cubehelix$1 = cubehelix(hue);
+var cubehelixLong = cubehelix(nogamma);
+
+function piecewise(interpolate, values) {
+ if (values === undefined) values = interpolate, interpolate = value;
+ var i = 0, n = values.length - 1, v = values[0], I = new Array(n < 0 ? 0 : n);
+ while (i < n) I[i] = interpolate(v, v = values[++i]);
+ return function(t) {
+ var i = Math.max(0, Math.min(n - 1, Math.floor(t *= n)));
+ return I[i](t - i);
+ };
+}
+
+function quantize(interpolator, n) {
+ var samples = new Array(n);
+ for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
+ return samples;
+}
+
+exports.interpolate = value;
+exports.interpolateArray = array;
+exports.interpolateBasis = basis$1;
+exports.interpolateBasisClosed = basisClosed;
+exports.interpolateCubehelix = cubehelix$1;
+exports.interpolateCubehelixLong = cubehelixLong;
+exports.interpolateDate = date;
+exports.interpolateDiscrete = discrete;
+exports.interpolateHcl = hcl$1;
+exports.interpolateHclLong = hclLong;
+exports.interpolateHsl = hsl$1;
+exports.interpolateHslLong = hslLong;
+exports.interpolateHue = hue$1;
+exports.interpolateLab = lab;
+exports.interpolateNumber = number;
+exports.interpolateNumberArray = numberArray;
+exports.interpolateObject = object;
+exports.interpolateRgb = rgb;
+exports.interpolateRgbBasis = rgbBasis;
+exports.interpolateRgbBasisClosed = rgbBasisClosed;
+exports.interpolateRound = round;
+exports.interpolateString = string;
+exports.interpolateTransformCss = interpolateTransformCss;
+exports.interpolateTransformSvg = interpolateTransformSvg;
+exports.interpolateZoom = zoom;
+exports.piecewise = piecewise;
+exports.quantize = quantize;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-interpolate/dist/d3-interpolate.min.js b/node_modules/d3-interpolate/dist/d3-interpolate.min.js
new file mode 100644
index 00000000..46dd1c0e
--- /dev/null
+++ b/node_modules/d3-interpolate/dist/d3-interpolate.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-interpolate/ v2.0.1 Copyright 2020 Mike Bostock
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("d3-color")):"function"==typeof define&&define.amd?define(["exports","d3-color"],n):n((t=t||self).d3=t.d3||{},t.d3)}(this,function(t,n){"use strict";function r(t,n,r,e,a){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*r+(1+3*t+3*o-3*u)*e+u*a)/6}function e(t){var n=t.length-1;return function(e){var a=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),o=t[a],u=t[a+1],i=a>0?t[a-1]:2*o-u,c=a
+
+Returns the [convex hull](https://en.wikipedia.org/wiki/Convex_hull) of the specified *points* using [Andrew’s monotone chain algorithm](http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain). The returned hull is represented as an array containing a subset of the input *points* arranged in counterclockwise order. Returns null if *points* has fewer than three elements.
+
+# d3.polygonContains(polygon, point) [<>](https://github.com/d3/d3-polygon/blob/master/src/contains.js#L1 "Source Code")
+
+Returns true if and only if the specified *point* is inside the specified *polygon*.
+
+# d3.polygonLength(polygon) [<>](https://github.com/d3/d3-polygon/blob/master/src/length.js#L1 "Source Code")
+
+Returns the length of the perimeter of the specified *polygon*.
diff --git a/node_modules/d3-polygon/dist/d3-polygon.js b/node_modules/d3-polygon/dist/d3-polygon.js
new file mode 100644
index 00000000..244a55fa
--- /dev/null
+++ b/node_modules/d3-polygon/dist/d3-polygon.js
@@ -0,0 +1,150 @@
+// https://d3js.org/d3-polygon/ v2.0.0 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+typeof define === 'function' && define.amd ? define(['exports'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}));
+}(this, function (exports) { 'use strict';
+
+function area(polygon) {
+ var i = -1,
+ n = polygon.length,
+ a,
+ b = polygon[n - 1],
+ area = 0;
+
+ while (++i < n) {
+ a = b;
+ b = polygon[i];
+ area += a[1] * b[0] - a[0] * b[1];
+ }
+
+ return area / 2;
+}
+
+function centroid(polygon) {
+ var i = -1,
+ n = polygon.length,
+ x = 0,
+ y = 0,
+ a,
+ b = polygon[n - 1],
+ c,
+ k = 0;
+
+ while (++i < n) {
+ a = b;
+ b = polygon[i];
+ k += c = a[0] * b[1] - b[0] * a[1];
+ x += (a[0] + b[0]) * c;
+ y += (a[1] + b[1]) * c;
+ }
+
+ return k *= 3, [x / k, y / k];
+}
+
+// Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
+// the 3D cross product in a quadrant I Cartesian coordinate system (+x is
+// right, +y is up). Returns a positive value if ABC is counter-clockwise,
+// negative if clockwise, and zero if the points are collinear.
+function cross(a, b, c) {
+ return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
+}
+
+function lexicographicOrder(a, b) {
+ return a[0] - b[0] || a[1] - b[1];
+}
+
+// Computes the upper convex hull per the monotone chain algorithm.
+// Assumes points.length >= 3, is sorted by x, unique in y.
+// Returns an array of indices into points in left-to-right order.
+function computeUpperHullIndexes(points) {
+ const n = points.length,
+ indexes = [0, 1];
+ let size = 2, i;
+
+ for (i = 2; i < n; ++i) {
+ while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size;
+ indexes[size++] = i;
+ }
+
+ return indexes.slice(0, size); // remove popped points
+}
+
+function hull(points) {
+ if ((n = points.length) < 3) return null;
+
+ var i,
+ n,
+ sortedPoints = new Array(n),
+ flippedPoints = new Array(n);
+
+ for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i];
+ sortedPoints.sort(lexicographicOrder);
+ for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
+
+ var upperIndexes = computeUpperHullIndexes(sortedPoints),
+ lowerIndexes = computeUpperHullIndexes(flippedPoints);
+
+ // Construct the hull polygon, removing possible duplicate endpoints.
+ var skipLeft = lowerIndexes[0] === upperIndexes[0],
+ skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
+ hull = [];
+
+ // Add upper hull in right-to-l order.
+ // Then add lower hull in left-to-right order.
+ for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]);
+ for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
+
+ return hull;
+}
+
+function contains(polygon, point) {
+ var n = polygon.length,
+ p = polygon[n - 1],
+ x = point[0], y = point[1],
+ x0 = p[0], y0 = p[1],
+ x1, y1,
+ inside = false;
+
+ for (var i = 0; i < n; ++i) {
+ p = polygon[i], x1 = p[0], y1 = p[1];
+ if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside;
+ x0 = x1, y0 = y1;
+ }
+
+ return inside;
+}
+
+function length(polygon) {
+ var i = -1,
+ n = polygon.length,
+ b = polygon[n - 1],
+ xa,
+ ya,
+ xb = b[0],
+ yb = b[1],
+ perimeter = 0;
+
+ while (++i < n) {
+ xa = xb;
+ ya = yb;
+ b = polygon[i];
+ xb = b[0];
+ yb = b[1];
+ xa -= xb;
+ ya -= yb;
+ perimeter += Math.hypot(xa, ya);
+ }
+
+ return perimeter;
+}
+
+exports.polygonArea = area;
+exports.polygonCentroid = centroid;
+exports.polygonContains = contains;
+exports.polygonHull = hull;
+exports.polygonLength = length;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-polygon/dist/d3-polygon.min.js b/node_modules/d3-polygon/dist/d3-polygon.min.js
new file mode 100644
index 00000000..f5f44647
--- /dev/null
+++ b/node_modules/d3-polygon/dist/d3-polygon.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-polygon/ v2.0.0 Copyright 2020 Mike Bostock
+!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n=n||self).d3=n.d3||{})}(this,function(n){"use strict";function e(n,e){return n[0]-e[0]||n[1]-e[1]}function t(n){const e=n.length,t=[0,1];let r,o=2;for(r=2;r
+
+
+## Installing
+
+If you use NPM, `npm install d3-quadtree`. Otherwise, download the [latest release](https://github.com/d3/d3-quadtree/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-quadtree.v2.min.js) or as part of [D3](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:
+
+```html
+
+
+```
+
+## API Reference
+
+# d3.quadtree([data[, x, y]])
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/quadtree.js "Source")
+
+Creates a new, empty quadtree with an empty [extent](#quadtree_extent) and the default [*x*-](#quadtree_x) and [*y*-](#quadtree_y)accessors. If *data* is specified, [adds](#quadtree_addAll) the specified array of data to the quadtree. This is equivalent to:
+
+```js
+var tree = d3.quadtree()
+ .addAll(data);
+```
+
+If *x* and *y* are also specified, sets the [*x*-](#quadtree_x) and [*y*-](#quadtree_y) accessors to the specified functions before adding the specified array of data to the quadtree, equivalent to:
+
+```js
+var tree = d3.quadtree()
+ .x(x)
+ .y(y)
+ .addAll(data);
+```
+
+# quadtree.x([x]) [<>](https://github.com/d3/d3-quadtree/blob/master/src/x.js "Source")
+
+If *x* is specified, sets the current *x*-coordinate accessor and returns the quadtree. If *x* is not specified, returns the current *x*-accessor, which defaults to:
+
+```js
+function x(d) {
+ return d[0];
+}
+```
+
+The *x*-acccessor is used to derive the *x*-coordinate of data when [adding](#quadtree_add) to and [removing](#quadtree_remove) from the tree. It is also used when [finding](#quadtree_find) to re-access the coordinates of data previously added to the tree; therefore, the *x*- and *y*-accessors must be consistent, returning the same value given the same input.
+
+# quadtree.y([y])
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/y.js "Source")
+
+If *y* is specified, sets the current *y*-coordinate accessor and returns the quadtree. If *y* is not specified, returns the current *y*-accessor, which defaults to:
+
+```js
+function y(d) {
+ return d[1];
+}
+```
+
+The *y*-acccessor is used to derive the *y*-coordinate of data when [adding](#quadtree_add) to and [removing](#quadtree_remove) from the tree. It is also used when [finding](#quadtree_find) to re-access the coordinates of data previously added to the tree; therefore, the *x*- and *y*-accessors must be consistent, returning the same value given the same input.
+
+# quadtree.extent([*extent*])
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/extent.js "Source")
+
+If *extent* is specified, expands the quadtree to [cover](#quadtree_cover) the specified points [[*x0*, *y0*], [*x1*, *y1*]] and returns the quadtree. If *extent* is not specified, returns the quadtree’s current extent [[*x0*, *y0*], [*x1*, *y1*]], where *x0* and *y0* are the inclusive lower bounds and *x1* and *y1* are the inclusive upper bounds, or undefined if the quadtree has no extent. The extent may also be expanded by calling [*quadtree*.cover](#quadtree_cover) or [*quadtree*.add](#quadtree_add).
+
+# quadtree.cover(x, y)
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/cover.js "Source")
+
+Expands the quadtree to cover the specified point ⟨*x*,*y*⟩, and returns the quadtree. If the quadtree’s extent already covers the specified point, this method does nothing. If the quadtree has an extent, the extent is repeatedly doubled to cover the specified point, wrapping the [root](#quadtree_root) [node](#nodes) as necessary; if the quadtree is empty, the extent is initialized to the extent [[⌊*x*⌋, ⌊*y*⌋], [⌈*x*⌉, ⌈*y*⌉]]. (Rounding is necessary such that if the extent is later doubled, the boundaries of existing quadrants do not change due to floating point error.)
+
+# quadtree.add(datum)
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/add.js "Source")
+
+Adds the specified *datum* to the quadtree, deriving its coordinates ⟨*x*,*y*⟩ using the current [*x*-](#quadtree_x) and [*y*-](#quadtree_y)accessors, and returns the quadtree. If the new point is outside the current [extent](#quadtree_extent) of the quadtree, the quadtree is automatically expanded to [cover](#quadtree_cover) the new point.
+
+# quadtree.addAll(data)
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/add.js "Source")
+
+Adds the specified array of *data* to the quadtree, deriving each element’s coordinates ⟨*x*,*y*⟩ using the current [*x*-](#quadtree_x) and [*y*-](#quadtree_y)accessors, and return this quadtree. This is approximately equivalent to calling [*quadtree*.add](#quadtree_add) repeatedly:
+
+```js
+for (var i = 0, n = data.length; i < n; ++i) {
+ quadtree.add(data[i]);
+}
+```
+
+However, this method results in a more compact quadtree because the extent of the *data* is computed first before adding the data.
+
+# quadtree.remove(datum)
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/remove.js "Source")
+
+Removes the specified *datum* from the quadtree, deriving its coordinates ⟨*x*,*y*⟩ using the current [*x*-](#quadtree_x) and [*y*-](#quadtree_y)accessors, and returns the quadtree. If the specified *datum* does not exist in this quadtree, this method does nothing.
+
+# quadtree.removeAll(data)
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/remove.js "Source")
+
+Removes the specified *data* from the quadtree, deriving their coordinates ⟨*x*,*y*⟩ using the current [*x*-](#quadtree_x) and [*y*-](#quadtree_y)accessors, and returns the quadtree. If a specified datum does not exist in this quadtree, it is ignored.
+
+# quadtree.copy()
+
+Returns a copy of the quadtree. All [nodes](#nodes) in the returned quadtree are identical copies of the corresponding node in the quadtree; however, any data in the quadtree is shared by reference and not copied.
+
+# quadtree.root()
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/root.js "Source")
+
+Returns the root [node](#nodes) of the quadtree.
+
+# quadtree.data()
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/data.js "Source")
+
+Returns an array of all data in the quadtree.
+
+# quadtree.size()
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/size.js "Source")
+
+Returns the total number of data in the quadtree.
+
+# quadtree.find(x, y[, radius])
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/find.js "Source")
+
+Returns the datum closest to the position ⟨*x*,*y*⟩ with the given search *radius*. If *radius* is not specified, it defaults to infinity. If there is no datum within the search area, returns undefined.
+
+# quadtree.visit(callback)
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/visit.js "Source")
+
+Visits each [node](#nodes) in the quadtree in pre-order traversal, invoking the specified *callback* with arguments *node*, *x0*, *y0*, *x1*, *y1* for each node, where *node* is the node being visited, ⟨*x0*, *y0*⟩ are the lower bounds of the node, and ⟨*x1*, *y1*⟩ are the upper bounds, and returns the quadtree. (Assuming that positive *x* is right and positive *y* is down, as is typically the case in Canvas and SVG, ⟨*x0*, *y0*⟩ is the top-left corner and ⟨*x1*, *y1*⟩ is the lower-right corner; however, the coordinate system is arbitrary, so more formally *x0* <= *x1* and *y0* <= *y1*.)
+
+If the *callback* returns true for a given node, then the children of that node are not visited; otherwise, all child nodes are visited. This can be used to quickly visit only parts of the tree, for example when using the [Barnes–Hut approximation](https://en.wikipedia.org/wiki/Barnes–Hut_simulation). Note, however, that child quadrants are always visited in sibling order: top-left, top-right, bottom-left, bottom-right. In cases such as [search](#quadtree_find), visiting siblings in a specific order may be faster.
+
+As an example, the following visits the quadtree and returns all the nodes within a rectangular extent [xmin, ymin, xmax, ymax], ignoring quads that cannot possibly contain any such node:
+
+```js
+function search(quadtree, xmin, ymin, xmax, ymax) {
+ const results = [];
+ quadtree.visit(function(node, x1, y1, x2, y2) {
+ if (!node.length) {
+ do {
+ var d = node.data;
+ if (d[0] >= xmin && d[0] < xmax && d[1] >= ymin && d[1] < ymax) {
+ results.push(d);
+ }
+ } while (node = node.next);
+ }
+ return x1 >= xmax || y1 >= ymax || x2 < xmin || y2 < ymin;
+ });
+ return results;
+}
+```
+
+# quadtree.visitAfter(callback)
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/visitAfter.js "Source")
+
+Visits each [node](#nodes) in the quadtree in post-order traversal, invoking the specified *callback* with arguments *node*, *x0*, *y0*, *x1*, *y1* for each node, where *node* is the node being visited, ⟨*x0*, *y0*⟩ are the lower bounds of the node, and ⟨*x1*, *y1*⟩ are the upper bounds, and returns the quadtree. (Assuming that positive *x* is right and positive *y* is down, as is typically the case in Canvas and SVG, ⟨*x0*, *y0*⟩ is the top-left corner and ⟨*x1*, *y1*⟩ is the lower-right corner; however, the coordinate system is arbitrary, so more formally *x0* <= *x1* and *y0* <= *y1*.) Returns *root*.
+
+### Nodes
+
+Internal nodes of the quadtree are represented as four-element arrays in left-to-right, top-to-bottom order:
+
+* `0` - the top-left quadrant, if any.
+* `1` - the top-right quadrant, if any.
+* `2` - the bottom-left quadrant, if any.
+* `3` - the bottom-right quadrant, if any.
+
+A child quadrant may be undefined if it is empty.
+
+Leaf nodes are represented as objects with the following properties:
+
+* `data` - the data associated with this point, as passed to [*quadtree*.add](#quadtree_add).
+* `next` - the next datum in this leaf, if any.
+
+The `length` property may be used to distinguish leaf nodes from internal nodes: it is undefined for leaf nodes, and 4 for internal nodes. For example, to iterate over all data in a leaf node:
+
+```js
+if (!node.length) do console.log(node.data); while (node = node.next);
+```
+
+The point’s *x*- and *y*-coordinates **must not be modified** while the point is in the quadtree. To update a point’s position, [remove](#quadtree_remove) the point and then re-[add](#quadtree_add) it to the quadtree at the new position. Alternatively, you may discard the existing quadtree entirely and create a new one from scratch; this may be more efficient if many of the points have moved.
diff --git a/node_modules/d3-quadtree/dist/d3-quadtree.js b/node_modules/d3-quadtree/dist/d3-quadtree.js
new file mode 100644
index 00000000..4e2c117d
--- /dev/null
+++ b/node_modules/d3-quadtree/dist/d3-quadtree.js
@@ -0,0 +1,419 @@
+// https://d3js.org/d3-quadtree/ v2.0.0 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+typeof define === 'function' && define.amd ? define(['exports'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}));
+}(this, function (exports) { 'use strict';
+
+function tree_add(d) {
+ const x = +this._x.call(null, d),
+ y = +this._y.call(null, d);
+ return add(this.cover(x, y), x, y, d);
+}
+
+function add(tree, x, y, d) {
+ if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points
+
+ var parent,
+ node = tree._root,
+ leaf = {data: d},
+ x0 = tree._x0,
+ y0 = tree._y0,
+ x1 = tree._x1,
+ y1 = tree._y1,
+ xm,
+ ym,
+ xp,
+ yp,
+ right,
+ bottom,
+ i,
+ j;
+
+ // If the tree is empty, initialize the root as a leaf.
+ if (!node) return tree._root = leaf, tree;
+
+ // Find the existing leaf for the new point, or add it.
+ while (node.length) {
+ if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
+ if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
+ if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree;
+ }
+
+ // Is the new point is exactly coincident with the existing point?
+ xp = +tree._x.call(null, node.data);
+ yp = +tree._y.call(null, node.data);
+ if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
+
+ // Otherwise, split the leaf node until the old and new point are separated.
+ do {
+ parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
+ if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
+ if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
+ } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm)));
+ return parent[j] = node, parent[i] = leaf, tree;
+}
+
+function addAll(data) {
+ var d, i, n = data.length,
+ x,
+ y,
+ xz = new Array(n),
+ yz = new Array(n),
+ x0 = Infinity,
+ y0 = Infinity,
+ x1 = -Infinity,
+ y1 = -Infinity;
+
+ // Compute the points and their extent.
+ for (i = 0; i < n; ++i) {
+ if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue;
+ xz[i] = x;
+ yz[i] = y;
+ if (x < x0) x0 = x;
+ if (x > x1) x1 = x;
+ if (y < y0) y0 = y;
+ if (y > y1) y1 = y;
+ }
+
+ // If there were no (valid) points, abort.
+ if (x0 > x1 || y0 > y1) return this;
+
+ // Expand the tree to cover the new points.
+ this.cover(x0, y0).cover(x1, y1);
+
+ // Add the new points.
+ for (i = 0; i < n; ++i) {
+ add(this, xz[i], yz[i], data[i]);
+ }
+
+ return this;
+}
+
+function tree_cover(x, y) {
+ if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points
+
+ var x0 = this._x0,
+ y0 = this._y0,
+ x1 = this._x1,
+ y1 = this._y1;
+
+ // If the quadtree has no extent, initialize them.
+ // Integer extent are necessary so that if we later double the extent,
+ // the existing quadrant boundaries don’t change due to floating point error!
+ if (isNaN(x0)) {
+ x1 = (x0 = Math.floor(x)) + 1;
+ y1 = (y0 = Math.floor(y)) + 1;
+ }
+
+ // Otherwise, double repeatedly to cover.
+ else {
+ var z = x1 - x0 || 1,
+ node = this._root,
+ parent,
+ i;
+
+ while (x0 > x || x >= x1 || y0 > y || y >= y1) {
+ i = (y < y0) << 1 | (x < x0);
+ parent = new Array(4), parent[i] = node, node = parent, z *= 2;
+ switch (i) {
+ case 0: x1 = x0 + z, y1 = y0 + z; break;
+ case 1: x0 = x1 - z, y1 = y0 + z; break;
+ case 2: x1 = x0 + z, y0 = y1 - z; break;
+ case 3: x0 = x1 - z, y0 = y1 - z; break;
+ }
+ }
+
+ if (this._root && this._root.length) this._root = node;
+ }
+
+ this._x0 = x0;
+ this._y0 = y0;
+ this._x1 = x1;
+ this._y1 = y1;
+ return this;
+}
+
+function tree_data() {
+ var data = [];
+ this.visit(function(node) {
+ if (!node.length) do data.push(node.data); while (node = node.next)
+ });
+ return data;
+}
+
+function tree_extent(_) {
+ return arguments.length
+ ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1])
+ : isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]];
+}
+
+function Quad(node, x0, y0, x1, y1) {
+ this.node = node;
+ this.x0 = x0;
+ this.y0 = y0;
+ this.x1 = x1;
+ this.y1 = y1;
+}
+
+function tree_find(x, y, radius) {
+ var data,
+ x0 = this._x0,
+ y0 = this._y0,
+ x1,
+ y1,
+ x2,
+ y2,
+ x3 = this._x1,
+ y3 = this._y1,
+ quads = [],
+ node = this._root,
+ q,
+ i;
+
+ if (node) quads.push(new Quad(node, x0, y0, x3, y3));
+ if (radius == null) radius = Infinity;
+ else {
+ x0 = x - radius, y0 = y - radius;
+ x3 = x + radius, y3 = y + radius;
+ radius *= radius;
+ }
+
+ while (q = quads.pop()) {
+
+ // Stop searching if this quadrant can’t contain a closer node.
+ if (!(node = q.node)
+ || (x1 = q.x0) > x3
+ || (y1 = q.y0) > y3
+ || (x2 = q.x1) < x0
+ || (y2 = q.y1) < y0) continue;
+
+ // Bisect the current quadrant.
+ if (node.length) {
+ var xm = (x1 + x2) / 2,
+ ym = (y1 + y2) / 2;
+
+ quads.push(
+ new Quad(node[3], xm, ym, x2, y2),
+ new Quad(node[2], x1, ym, xm, y2),
+ new Quad(node[1], xm, y1, x2, ym),
+ new Quad(node[0], x1, y1, xm, ym)
+ );
+
+ // Visit the closest quadrant first.
+ if (i = (y >= ym) << 1 | (x >= xm)) {
+ q = quads[quads.length - 1];
+ quads[quads.length - 1] = quads[quads.length - 1 - i];
+ quads[quads.length - 1 - i] = q;
+ }
+ }
+
+ // Visit this point. (Visiting coincident points isn’t necessary!)
+ else {
+ var dx = x - +this._x.call(null, node.data),
+ dy = y - +this._y.call(null, node.data),
+ d2 = dx * dx + dy * dy;
+ if (d2 < radius) {
+ var d = Math.sqrt(radius = d2);
+ x0 = x - d, y0 = y - d;
+ x3 = x + d, y3 = y + d;
+ data = node.data;
+ }
+ }
+ }
+
+ return data;
+}
+
+function tree_remove(d) {
+ if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points
+
+ var parent,
+ node = this._root,
+ retainer,
+ previous,
+ next,
+ x0 = this._x0,
+ y0 = this._y0,
+ x1 = this._x1,
+ y1 = this._y1,
+ x,
+ y,
+ xm,
+ ym,
+ right,
+ bottom,
+ i,
+ j;
+
+ // If the tree is empty, initialize the root as a leaf.
+ if (!node) return this;
+
+ // Find the leaf node for the point.
+ // While descending, also retain the deepest parent with a non-removed sibling.
+ if (node.length) while (true) {
+ if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
+ if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
+ if (!(parent = node, node = node[i = bottom << 1 | right])) return this;
+ if (!node.length) break;
+ if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i;
+ }
+
+ // Find the point to remove.
+ while (node.data !== d) if (!(previous = node, node = node.next)) return this;
+ if (next = node.next) delete node.next;
+
+ // If there are multiple coincident points, remove just the point.
+ if (previous) return (next ? previous.next = next : delete previous.next), this;
+
+ // If this is the root point, remove it.
+ if (!parent) return this._root = next, this;
+
+ // Remove this leaf.
+ next ? parent[i] = next : delete parent[i];
+
+ // If the parent now contains exactly one leaf, collapse superfluous parents.
+ if ((node = parent[0] || parent[1] || parent[2] || parent[3])
+ && node === (parent[3] || parent[2] || parent[1] || parent[0])
+ && !node.length) {
+ if (retainer) retainer[j] = node;
+ else this._root = node;
+ }
+
+ return this;
+}
+
+function removeAll(data) {
+ for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
+ return this;
+}
+
+function tree_root() {
+ return this._root;
+}
+
+function tree_size() {
+ var size = 0;
+ this.visit(function(node) {
+ if (!node.length) do ++size; while (node = node.next)
+ });
+ return size;
+}
+
+function tree_visit(callback) {
+ var quads = [], q, node = this._root, child, x0, y0, x1, y1;
+ if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1));
+ while (q = quads.pop()) {
+ if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) {
+ var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
+ if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
+ if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
+ if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
+ if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
+ }
+ }
+ return this;
+}
+
+function tree_visitAfter(callback) {
+ var quads = [], next = [], q;
+ if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1));
+ while (q = quads.pop()) {
+ var node = q.node;
+ if (node.length) {
+ var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
+ if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
+ if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
+ if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
+ if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
+ }
+ next.push(q);
+ }
+ while (q = next.pop()) {
+ callback(q.node, q.x0, q.y0, q.x1, q.y1);
+ }
+ return this;
+}
+
+function defaultX(d) {
+ return d[0];
+}
+
+function tree_x(_) {
+ return arguments.length ? (this._x = _, this) : this._x;
+}
+
+function defaultY(d) {
+ return d[1];
+}
+
+function tree_y(_) {
+ return arguments.length ? (this._y = _, this) : this._y;
+}
+
+function quadtree(nodes, x, y) {
+ var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN);
+ return nodes == null ? tree : tree.addAll(nodes);
+}
+
+function Quadtree(x, y, x0, y0, x1, y1) {
+ this._x = x;
+ this._y = y;
+ this._x0 = x0;
+ this._y0 = y0;
+ this._x1 = x1;
+ this._y1 = y1;
+ this._root = undefined;
+}
+
+function leaf_copy(leaf) {
+ var copy = {data: leaf.data}, next = copy;
+ while (leaf = leaf.next) next = next.next = {data: leaf.data};
+ return copy;
+}
+
+var treeProto = quadtree.prototype = Quadtree.prototype;
+
+treeProto.copy = function() {
+ var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1),
+ node = this._root,
+ nodes,
+ child;
+
+ if (!node) return copy;
+
+ if (!node.length) return copy._root = leaf_copy(node), copy;
+
+ nodes = [{source: node, target: copy._root = new Array(4)}];
+ while (node = nodes.pop()) {
+ for (var i = 0; i < 4; ++i) {
+ if (child = node.source[i]) {
+ if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)});
+ else node.target[i] = leaf_copy(child);
+ }
+ }
+ }
+
+ return copy;
+};
+
+treeProto.add = tree_add;
+treeProto.addAll = addAll;
+treeProto.cover = tree_cover;
+treeProto.data = tree_data;
+treeProto.extent = tree_extent;
+treeProto.find = tree_find;
+treeProto.remove = tree_remove;
+treeProto.removeAll = removeAll;
+treeProto.root = tree_root;
+treeProto.size = tree_size;
+treeProto.visit = tree_visit;
+treeProto.visitAfter = tree_visitAfter;
+treeProto.x = tree_x;
+treeProto.y = tree_y;
+
+exports.quadtree = quadtree;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-quadtree/dist/d3-quadtree.min.js b/node_modules/d3-quadtree/dist/d3-quadtree.min.js
new file mode 100644
index 00000000..db82ed2c
--- /dev/null
+++ b/node_modules/d3-quadtree/dist/d3-quadtree.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-quadtree/ v2.0.0 Copyright 2020 Mike Bostock
+!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((t=t||self).d3=t.d3||{})}(this,function(t){"use strict";function i(t,i,n,e){if(isNaN(i)||isNaN(n))return t;var r,s,h,o,a,u,l,_,f,c=t._root,x={data:e},y=t._x0,d=t._y0,v=t._x1,p=t._y1;if(!c)return t._root=x,t;for(;c.length;)if((u=i>=(s=(y+v)/2))?y=s:v=s,(l=n>=(h=(d+p)/2))?d=h:p=h,r=c,!(c=c[_=l<<1|u]))return r[_]=x,t;if(o=+t._x.call(null,c.data),a=+t._y.call(null,c.data),i===o&&n===a)return x.next=c,r?r[_]=x:t._root=x,t;do{r=r?r[_]=new Array(4):t._root=new Array(4),(u=i>=(s=(y+v)/2))?y=s:v=s,(l=n>=(h=(d+p)/2))?d=h:p=h}while((_=l<<1|u)==(f=(a>=h)<<1|o>=s));return r[f]=c,r[_]=x,t}function n(t,i,n,e,r){this.node=t,this.x0=i,this.y0=n,this.x1=e,this.y1=r}function e(t){return t[0]}function r(t){return t[1]}function s(t,i,n){var s=new h(null==i?e:i,null==n?r:n,NaN,NaN,NaN,NaN);return null==t?s:s.addAll(t)}function h(t,i,n,e,r,s){this._x=t,this._y=i,this._x0=n,this._y0=e,this._x1=r,this._y1=s,this._root=void 0}function o(t){for(var i={data:t.data},n=i;t=t.next;)n=n.next={data:t.data};return i}var a=s.prototype=h.prototype;a.copy=function(){var t,i,n=new h(this._x,this._y,this._x0,this._y0,this._x1,this._y1),e=this._root;if(!e)return n;if(!e.length)return n._root=o(e),n;for(t=[{source:e,target:n._root=new Array(4)}];e=t.pop();)for(var r=0;r<4;++r)(i=e.source[r])&&(i.length?t.push({source:i,target:e.target[r]=new Array(4)}):e.target[r]=o(i));return n},a.add=function(t){const n=+this._x.call(null,t),e=+this._y.call(null,t);return i(this.cover(n,e),n,e,t)},a.addAll=function(t){var n,e,r,s,h=t.length,o=new Array(h),a=new Array(h),u=1/0,l=1/0,_=-1/0,f=-1/0;for(e=0;e
+
+An array of ten categorical colors represented as RGB hexadecimal strings.
+
+# d3.schemeAccent [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/categorical/Accent.js "Source")
+
+
+
+An array of eight categorical colors represented as RGB hexadecimal strings.
+
+# d3.schemeDark2 [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/categorical/Dark2.js "Source")
+
+
+
+An array of eight categorical colors represented as RGB hexadecimal strings.
+
+# d3.schemePaired [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/categorical/Paired.js "Source")
+
+
+
+An array of twelve categorical colors represented as RGB hexadecimal strings.
+
+# d3.schemePastel1 [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/categorical/Pastel1.js "Source")
+
+
+
+An array of nine categorical colors represented as RGB hexadecimal strings.
+
+# d3.schemePastel2 [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/categorical/Pastel2.js "Source")
+
+
+
+An array of eight categorical colors represented as RGB hexadecimal strings.
+
+# d3.schemeSet1 [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/categorical/Set1.js "Source")
+
+
+
+An array of nine categorical colors represented as RGB hexadecimal strings.
+
+# d3.schemeSet2 [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/categorical/Set2.js "Source")
+
+
+
+An array of eight categorical colors represented as RGB hexadecimal strings.
+
+# d3.schemeSet3 [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/categorical/Set3.js "Source")
+
+
+
+An array of twelve categorical colors represented as RGB hexadecimal strings.
+
+# d3.schemeTableau10 [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/categorical/Tableau10.js "Source")
+
+
+
+An array of ten categorical colors authored by Tableau as part of [Tableau 10](https://www.tableau.com/about/blog/2016/7/colors-upgrade-tableau-10-56782) represented as RGB hexadecimal strings.
+
+### Diverging
+
+Diverging color schemes are available as continuous interpolators (often used with [d3.scaleSequential](https://github.com/d3/d3-scale/blob/master/README.md#sequential-scales)) and as discrete schemes (often used with [d3.scaleOrdinal](https://github.com/d3/d3-scale/blob/master/README.md#ordinal-scales)). Each discrete scheme, such as [d3.schemeBrBG](#schemeBrBG), is represented as an array of arrays of hexadecimal color strings. The *k*th element of this array contains the color scheme of size *k*; for example, `d3.schemeBrBG[9]` contains an array of nine strings representing the nine colors of the brown-blue-green diverging color scheme. Diverging color schemes support a size *k* ranging from 3 to 11.
+
+# d3.interpolateBrBG(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/BrBG.js "Source")
+
# d3.schemeBrBG[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “BrBG†diverging color scheme represented as an RGB string.
+
+# d3.interpolatePRGn(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/PRGn.js "Source")
+
# d3.schemePRGn[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “PRGn†diverging color scheme represented as an RGB string.
+
+# d3.interpolatePiYG(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/PiYG.js "Source")
+
# d3.schemePiYG[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “PiYG†diverging color scheme represented as an RGB string.
+
+# d3.interpolatePuOr(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/PuOr.js "Source")
+
# d3.schemePuOr[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “PuOr†diverging color scheme represented as an RGB string.
+
+# d3.interpolateRdBu(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/RdBu.js "Source")
+
# d3.schemeRdBu[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “RdBu†diverging color scheme represented as an RGB string.
+
+# d3.interpolateRdGy(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/RdGy.js "Source")
+
# d3.schemeRdGy[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “RdGy†diverging color scheme represented as an RGB string.
+
+# d3.interpolateRdYlBu(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/RdYlBu.js "Source")
+
# d3.schemeRdYlBu[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “RdYlBu†diverging color scheme represented as an RGB string.
+
+# d3.interpolateRdYlGn(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/RdYlGn.js "Source")
+
# d3.schemeRdYlGn[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “RdYlGn†diverging color scheme represented as an RGB string.
+
+# d3.interpolateSpectral(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/Spectral.js "Source")
+
# d3.schemeSpectral[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “Spectral†diverging color scheme represented as an RGB string.
+
+### Sequential (Single Hue)
+
+Sequential, single-hue color schemes are available as continuous interpolators (often used with [d3.scaleSequential](https://github.com/d3/d3-scale/blob/master/README.md#sequential-scales)) and as discrete schemes (often used with [d3.scaleOrdinal](https://github.com/d3/d3-scale/blob/master/README.md#ordinal-scales)). Each discrete scheme, such as [d3.schemeBlues](#schemeBlues), is represented as an array of arrays of hexadecimal color strings. The *k*th element of this array contains the color scheme of size *k*; for example, `d3.schemeBlues[9]` contains an array of nine strings representing the nine colors of the blue sequential color scheme. Sequential, single-hue color schemes support a size *k* ranging from 3 to 9.
+
+# d3.interpolateBlues(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-single/Blues.js "Source")
+
# d3.schemeBlues[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “Blues†sequential color scheme represented as an RGB string.
+
+# d3.interpolateGreens(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-single/Greens.js "Source")
+
# d3.schemeGreens[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “Greens†sequential color scheme represented as an RGB string.
+
+# d3.interpolateGreys(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-single/Greys.js "Source")
+
# d3.schemeGreys[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “Greys†sequential color scheme represented as an RGB string.
+
+# d3.interpolateOranges(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-single/Oranges.js "Source")
+
# d3.schemeOranges[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “Oranges†sequential color scheme represented as an RGB string.
+
+# d3.interpolatePurples(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-single/Purples.js "Source")
+
# d3.schemePurples[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “Purples†sequential color scheme represented as an RGB string.
+
+# d3.interpolateReds(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-single/Reds.js "Source")
+
# d3.schemeReds[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “Reds†sequential color scheme represented as an RGB string.
+
+### Sequential (Multi-Hue)
+
+Sequential, multi-hue color schemes are available as continuous interpolators (often used with [d3.scaleSequential](https://github.com/d3/d3-scale/blob/master/README.md#sequential-scales)) and as discrete schemes (often used with [d3.scaleOrdinal](https://github.com/d3/d3-scale/blob/master/README.md#ordinal-scales)). Each discrete scheme, such as [d3.schemeBuGn](#schemeBuGn), is represented as an array of arrays of hexadecimal color strings. The *k*th element of this array contains the color scheme of size *k*; for example, `d3.schemeBuGn[9]` contains an array of nine strings representing the nine colors of the blue-green sequential color scheme. Sequential, multi-hue color schemes support a size *k* ranging from 3 to 9.
+
+# d3.interpolateTurbo(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/turbo.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “turbo†color scheme by [Anton Mikhailov](https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html).
+
+# d3.interpolateViridis(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/viridis.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “viridis†perceptually-uniform color scheme designed by [van der Walt, Smith and Firing](https://bids.github.io/colormap/) for matplotlib, represented as an RGB string.
+
+# d3.interpolateInferno(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/viridis.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “inferno†perceptually-uniform color scheme designed by [van der Walt and Smith](https://bids.github.io/colormap/) for matplotlib, represented as an RGB string.
+
+# d3.interpolateMagma(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/viridis.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “magma†perceptually-uniform color scheme designed by [van der Walt and Smith](https://bids.github.io/colormap/) for matplotlib, represented as an RGB string.
+
+# d3.interpolatePlasma(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/viridis.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “plasma†perceptually-uniform color scheme designed by [van der Walt and Smith](https://bids.github.io/colormap/) for matplotlib, represented as an RGB string.
+
+# d3.interpolateCividis(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/cividis.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “cividis†color vision deficiency-optimized color scheme designed by [Nuñez, Anderton, and Renslow](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0199239), represented as an RGB string.
+
+# d3.interpolateWarm(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/rainbow.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from a 180° rotation of [Niccoli’s perceptual rainbow](https://mycarta.wordpress.com/2013/02/21/perceptual-rainbow-palette-the-method/), represented as an RGB string.
+
+# d3.interpolateCool(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/rainbow.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from [Niccoli’s perceptual rainbow](https://mycarta.wordpress.com/2013/02/21/perceptual-rainbow-palette-the-method/), represented as an RGB string.
+
+# d3.interpolateCubehelixDefault(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/cubehelix.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from [Green’s default Cubehelix](http://www.mrao.cam.ac.uk/~dag/CUBEHELIX/) represented as an RGB string.
+
+# d3.interpolateBuGn(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/BuGn.js "Source")
+
# d3.schemeBuGn[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “BuGn†sequential color scheme represented as an RGB string.
+
+# d3.interpolateBuPu(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/BuPu.js "Source")
+
# d3.schemeBuPu[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “BuPu†sequential color scheme represented as an RGB string.
+
+# d3.interpolateGnBu(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/GnBu.js "Source")
+
# d3.schemeGnBu[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “GnBu†sequential color scheme represented as an RGB string.
+
+# d3.interpolateOrRd(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/OrRd.js "Source")
+
# d3.schemeOrRd[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “OrRd†sequential color scheme represented as an RGB string.
+
+# d3.interpolatePuBuGn(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/PuBuGn.js "Source")
+
# d3.schemePuBuGn[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “PuBuGn†sequential color scheme represented as an RGB string.
+
+# d3.interpolatePuBu(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/PuBu.js "Source")
+
# d3.schemePuBu[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “PuBu†sequential color scheme represented as an RGB string.
+
+# d3.interpolatePuRd(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/PuRd.js "Source")
+
# d3.schemePuRd[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “PuRd†sequential color scheme represented as an RGB string.
+
+# d3.interpolateRdPu(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/RdPu.js "Source")
+
# d3.schemeRdPu[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “RdPu†sequential color scheme represented as an RGB string.
+
+# d3.interpolateYlGnBu(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/YlGnBu.js "Source")
+
# d3.schemeYlGnBu[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “YlGnBu†sequential color scheme represented as an RGB string.
+
+# d3.interpolateYlGn(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/YlGn.js "Source")
+
# d3.schemeYlGn[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “YlGn†sequential color scheme represented as an RGB string.
+
+# d3.interpolateYlOrBr(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/YlOrBr.js "Source")
+
# d3.schemeYlOrBr[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “YlOrBr†sequential color scheme represented as an RGB string.
+
+# d3.interpolateYlOrRd(*t*) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/YlOrRd.js "Source")
+
# d3.schemeYlOrRd[*k*]
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “YlOrRd†sequential color scheme represented as an RGB string.
+
+### Cyclical
+
+# d3.interpolateRainbow(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/rainbow.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from [d3.interpolateWarm](#interpolateWarm) scale from [0.0, 0.5] followed by the [d3.interpolateCool](#interpolateCool) scale from [0.5, 1.0], thus implementing the cyclical [less-angry rainbow](http://bl.ocks.org/mbostock/310c99e53880faec2434) color scheme.
+
+# d3.interpolateSinebow(t) [<>](https://github.com/d3/d3-scale-chromatic/blob/master/src/sequential-multi/sinebow.js "Source")
+
+
+
+Given a number *t* in the range [0,1], returns the corresponding color from the “sinebow†color scheme by [Jim Bumgardner](https://krazydad.com/tutorials/makecolors.php) and [Charlie Loyd](http://basecase.org/env/on-rainbows).
diff --git a/node_modules/d3-scale-chromatic/dist/d3-scale-chromatic.js b/node_modules/d3-scale-chromatic/dist/d3-scale-chromatic.js
new file mode 100644
index 00000000..b68a1510
--- /dev/null
+++ b/node_modules/d3-scale-chromatic/dist/d3-scale-chromatic.js
@@ -0,0 +1,519 @@
+// https://d3js.org/d3-scale-chromatic/ v2.0.0 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-interpolate'), require('d3-color')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-interpolate', 'd3-color'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}, global.d3, global.d3));
+}(this, function (exports, d3Interpolate, d3Color) { 'use strict';
+
+function colors(specifier) {
+ var n = specifier.length / 6 | 0, colors = new Array(n), i = 0;
+ while (i < n) colors[i] = "#" + specifier.slice(i * 6, ++i * 6);
+ return colors;
+}
+
+var category10 = colors("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf");
+
+var Accent = colors("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666");
+
+var Dark2 = colors("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666");
+
+var Paired = colors("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928");
+
+var Pastel1 = colors("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2");
+
+var Pastel2 = colors("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc");
+
+var Set1 = colors("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999");
+
+var Set2 = colors("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3");
+
+var Set3 = colors("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f");
+
+var Tableau10 = colors("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab");
+
+var ramp = scheme => d3Interpolate.interpolateRgbBasis(scheme[scheme.length - 1]);
+
+var scheme = new Array(3).concat(
+ "d8b365f5f5f55ab4ac",
+ "a6611adfc27d80cdc1018571",
+ "a6611adfc27df5f5f580cdc1018571",
+ "8c510ad8b365f6e8c3c7eae55ab4ac01665e",
+ "8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e",
+ "8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e",
+ "8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e",
+ "5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30",
+ "5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30"
+).map(colors);
+
+var BrBG = ramp(scheme);
+
+var scheme$1 = new Array(3).concat(
+ "af8dc3f7f7f77fbf7b",
+ "7b3294c2a5cfa6dba0008837",
+ "7b3294c2a5cff7f7f7a6dba0008837",
+ "762a83af8dc3e7d4e8d9f0d37fbf7b1b7837",
+ "762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837",
+ "762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837",
+ "762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837",
+ "40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b",
+ "40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b"
+).map(colors);
+
+var PRGn = ramp(scheme$1);
+
+var scheme$2 = new Array(3).concat(
+ "e9a3c9f7f7f7a1d76a",
+ "d01c8bf1b6dab8e1864dac26",
+ "d01c8bf1b6daf7f7f7b8e1864dac26",
+ "c51b7de9a3c9fde0efe6f5d0a1d76a4d9221",
+ "c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221",
+ "c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221",
+ "c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221",
+ "8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419",
+ "8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419"
+).map(colors);
+
+var PiYG = ramp(scheme$2);
+
+var scheme$3 = new Array(3).concat(
+ "998ec3f7f7f7f1a340",
+ "5e3c99b2abd2fdb863e66101",
+ "5e3c99b2abd2f7f7f7fdb863e66101",
+ "542788998ec3d8daebfee0b6f1a340b35806",
+ "542788998ec3d8daebf7f7f7fee0b6f1a340b35806",
+ "5427888073acb2abd2d8daebfee0b6fdb863e08214b35806",
+ "5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806",
+ "2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08",
+ "2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08"
+).map(colors);
+
+var PuOr = ramp(scheme$3);
+
+var scheme$4 = new Array(3).concat(
+ "ef8a62f7f7f767a9cf",
+ "ca0020f4a58292c5de0571b0",
+ "ca0020f4a582f7f7f792c5de0571b0",
+ "b2182bef8a62fddbc7d1e5f067a9cf2166ac",
+ "b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac",
+ "b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac",
+ "b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac",
+ "67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061",
+ "67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061"
+).map(colors);
+
+var RdBu = ramp(scheme$4);
+
+var scheme$5 = new Array(3).concat(
+ "ef8a62ffffff999999",
+ "ca0020f4a582bababa404040",
+ "ca0020f4a582ffffffbababa404040",
+ "b2182bef8a62fddbc7e0e0e09999994d4d4d",
+ "b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d",
+ "b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d",
+ "b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d",
+ "67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a",
+ "67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a"
+).map(colors);
+
+var RdGy = ramp(scheme$5);
+
+var scheme$6 = new Array(3).concat(
+ "fc8d59ffffbf91bfdb",
+ "d7191cfdae61abd9e92c7bb6",
+ "d7191cfdae61ffffbfabd9e92c7bb6",
+ "d73027fc8d59fee090e0f3f891bfdb4575b4",
+ "d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4",
+ "d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4",
+ "d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4",
+ "a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695",
+ "a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695"
+).map(colors);
+
+var RdYlBu = ramp(scheme$6);
+
+var scheme$7 = new Array(3).concat(
+ "fc8d59ffffbf91cf60",
+ "d7191cfdae61a6d96a1a9641",
+ "d7191cfdae61ffffbfa6d96a1a9641",
+ "d73027fc8d59fee08bd9ef8b91cf601a9850",
+ "d73027fc8d59fee08bffffbfd9ef8b91cf601a9850",
+ "d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850",
+ "d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850",
+ "a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837",
+ "a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837"
+).map(colors);
+
+var RdYlGn = ramp(scheme$7);
+
+var scheme$8 = new Array(3).concat(
+ "fc8d59ffffbf99d594",
+ "d7191cfdae61abdda42b83ba",
+ "d7191cfdae61ffffbfabdda42b83ba",
+ "d53e4ffc8d59fee08be6f59899d5943288bd",
+ "d53e4ffc8d59fee08bffffbfe6f59899d5943288bd",
+ "d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd",
+ "d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd",
+ "9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2",
+ "9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2"
+).map(colors);
+
+var Spectral = ramp(scheme$8);
+
+var scheme$9 = new Array(3).concat(
+ "e5f5f999d8c92ca25f",
+ "edf8fbb2e2e266c2a4238b45",
+ "edf8fbb2e2e266c2a42ca25f006d2c",
+ "edf8fbccece699d8c966c2a42ca25f006d2c",
+ "edf8fbccece699d8c966c2a441ae76238b45005824",
+ "f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824",
+ "f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b"
+).map(colors);
+
+var BuGn = ramp(scheme$9);
+
+var scheme$a = new Array(3).concat(
+ "e0ecf49ebcda8856a7",
+ "edf8fbb3cde38c96c688419d",
+ "edf8fbb3cde38c96c68856a7810f7c",
+ "edf8fbbfd3e69ebcda8c96c68856a7810f7c",
+ "edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b",
+ "f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b",
+ "f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b"
+).map(colors);
+
+var BuPu = ramp(scheme$a);
+
+var scheme$b = new Array(3).concat(
+ "e0f3dba8ddb543a2ca",
+ "f0f9e8bae4bc7bccc42b8cbe",
+ "f0f9e8bae4bc7bccc443a2ca0868ac",
+ "f0f9e8ccebc5a8ddb57bccc443a2ca0868ac",
+ "f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e",
+ "f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e",
+ "f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081"
+).map(colors);
+
+var GnBu = ramp(scheme$b);
+
+var scheme$c = new Array(3).concat(
+ "fee8c8fdbb84e34a33",
+ "fef0d9fdcc8afc8d59d7301f",
+ "fef0d9fdcc8afc8d59e34a33b30000",
+ "fef0d9fdd49efdbb84fc8d59e34a33b30000",
+ "fef0d9fdd49efdbb84fc8d59ef6548d7301f990000",
+ "fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000",
+ "fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000"
+).map(colors);
+
+var OrRd = ramp(scheme$c);
+
+var scheme$d = new Array(3).concat(
+ "ece2f0a6bddb1c9099",
+ "f6eff7bdc9e167a9cf02818a",
+ "f6eff7bdc9e167a9cf1c9099016c59",
+ "f6eff7d0d1e6a6bddb67a9cf1c9099016c59",
+ "f6eff7d0d1e6a6bddb67a9cf3690c002818a016450",
+ "fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450",
+ "fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636"
+).map(colors);
+
+var PuBuGn = ramp(scheme$d);
+
+var scheme$e = new Array(3).concat(
+ "ece7f2a6bddb2b8cbe",
+ "f1eef6bdc9e174a9cf0570b0",
+ "f1eef6bdc9e174a9cf2b8cbe045a8d",
+ "f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d",
+ "f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b",
+ "fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b",
+ "fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858"
+).map(colors);
+
+var PuBu = ramp(scheme$e);
+
+var scheme$f = new Array(3).concat(
+ "e7e1efc994c7dd1c77",
+ "f1eef6d7b5d8df65b0ce1256",
+ "f1eef6d7b5d8df65b0dd1c77980043",
+ "f1eef6d4b9dac994c7df65b0dd1c77980043",
+ "f1eef6d4b9dac994c7df65b0e7298ace125691003f",
+ "f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f",
+ "f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f"
+).map(colors);
+
+var PuRd = ramp(scheme$f);
+
+var scheme$g = new Array(3).concat(
+ "fde0ddfa9fb5c51b8a",
+ "feebe2fbb4b9f768a1ae017e",
+ "feebe2fbb4b9f768a1c51b8a7a0177",
+ "feebe2fcc5c0fa9fb5f768a1c51b8a7a0177",
+ "feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177",
+ "fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177",
+ "fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a"
+).map(colors);
+
+var RdPu = ramp(scheme$g);
+
+var scheme$h = new Array(3).concat(
+ "edf8b17fcdbb2c7fb8",
+ "ffffcca1dab441b6c4225ea8",
+ "ffffcca1dab441b6c42c7fb8253494",
+ "ffffccc7e9b47fcdbb41b6c42c7fb8253494",
+ "ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84",
+ "ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84",
+ "ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58"
+).map(colors);
+
+var YlGnBu = ramp(scheme$h);
+
+var scheme$i = new Array(3).concat(
+ "f7fcb9addd8e31a354",
+ "ffffccc2e69978c679238443",
+ "ffffccc2e69978c67931a354006837",
+ "ffffccd9f0a3addd8e78c67931a354006837",
+ "ffffccd9f0a3addd8e78c67941ab5d238443005a32",
+ "ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32",
+ "ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529"
+).map(colors);
+
+var YlGn = ramp(scheme$i);
+
+var scheme$j = new Array(3).concat(
+ "fff7bcfec44fd95f0e",
+ "ffffd4fed98efe9929cc4c02",
+ "ffffd4fed98efe9929d95f0e993404",
+ "ffffd4fee391fec44ffe9929d95f0e993404",
+ "ffffd4fee391fec44ffe9929ec7014cc4c028c2d04",
+ "ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04",
+ "ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506"
+).map(colors);
+
+var YlOrBr = ramp(scheme$j);
+
+var scheme$k = new Array(3).concat(
+ "ffeda0feb24cf03b20",
+ "ffffb2fecc5cfd8d3ce31a1c",
+ "ffffb2fecc5cfd8d3cf03b20bd0026",
+ "ffffb2fed976feb24cfd8d3cf03b20bd0026",
+ "ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026",
+ "ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026",
+ "ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026"
+).map(colors);
+
+var YlOrRd = ramp(scheme$k);
+
+var scheme$l = new Array(3).concat(
+ "deebf79ecae13182bd",
+ "eff3ffbdd7e76baed62171b5",
+ "eff3ffbdd7e76baed63182bd08519c",
+ "eff3ffc6dbef9ecae16baed63182bd08519c",
+ "eff3ffc6dbef9ecae16baed64292c62171b5084594",
+ "f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594",
+ "f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b"
+).map(colors);
+
+var Blues = ramp(scheme$l);
+
+var scheme$m = new Array(3).concat(
+ "e5f5e0a1d99b31a354",
+ "edf8e9bae4b374c476238b45",
+ "edf8e9bae4b374c47631a354006d2c",
+ "edf8e9c7e9c0a1d99b74c47631a354006d2c",
+ "edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32",
+ "f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32",
+ "f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b"
+).map(colors);
+
+var Greens = ramp(scheme$m);
+
+var scheme$n = new Array(3).concat(
+ "f0f0f0bdbdbd636363",
+ "f7f7f7cccccc969696525252",
+ "f7f7f7cccccc969696636363252525",
+ "f7f7f7d9d9d9bdbdbd969696636363252525",
+ "f7f7f7d9d9d9bdbdbd969696737373525252252525",
+ "fffffff0f0f0d9d9d9bdbdbd969696737373525252252525",
+ "fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000"
+).map(colors);
+
+var Greys = ramp(scheme$n);
+
+var scheme$o = new Array(3).concat(
+ "efedf5bcbddc756bb1",
+ "f2f0f7cbc9e29e9ac86a51a3",
+ "f2f0f7cbc9e29e9ac8756bb154278f",
+ "f2f0f7dadaebbcbddc9e9ac8756bb154278f",
+ "f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486",
+ "fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486",
+ "fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d"
+).map(colors);
+
+var Purples = ramp(scheme$o);
+
+var scheme$p = new Array(3).concat(
+ "fee0d2fc9272de2d26",
+ "fee5d9fcae91fb6a4acb181d",
+ "fee5d9fcae91fb6a4ade2d26a50f15",
+ "fee5d9fcbba1fc9272fb6a4ade2d26a50f15",
+ "fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d",
+ "fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d",
+ "fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d"
+).map(colors);
+
+var Reds = ramp(scheme$p);
+
+var scheme$q = new Array(3).concat(
+ "fee6cefdae6be6550d",
+ "feeddefdbe85fd8d3cd94701",
+ "feeddefdbe85fd8d3ce6550da63603",
+ "feeddefdd0a2fdae6bfd8d3ce6550da63603",
+ "feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04",
+ "fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04",
+ "fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704"
+).map(colors);
+
+var Oranges = ramp(scheme$q);
+
+function cividis(t) {
+ t = Math.max(0, Math.min(1, t));
+ return "rgb("
+ + Math.max(0, Math.min(255, Math.round(-4.54 - t * (35.34 - t * (2381.73 - t * (6402.7 - t * (7024.72 - t * 2710.57))))))) + ", "
+ + Math.max(0, Math.min(255, Math.round(32.49 + t * (170.73 + t * (52.82 - t * (131.46 - t * (176.58 - t * 67.37))))))) + ", "
+ + Math.max(0, Math.min(255, Math.round(81.24 + t * (442.36 - t * (2482.43 - t * (6167.24 - t * (6614.94 - t * 2475.67)))))))
+ + ")";
+}
+
+var cubehelix = d3Interpolate.interpolateCubehelixLong(d3Color.cubehelix(300, 0.5, 0.0), d3Color.cubehelix(-240, 0.5, 1.0));
+
+var warm = d3Interpolate.interpolateCubehelixLong(d3Color.cubehelix(-100, 0.75, 0.35), d3Color.cubehelix(80, 1.50, 0.8));
+
+var cool = d3Interpolate.interpolateCubehelixLong(d3Color.cubehelix(260, 0.75, 0.35), d3Color.cubehelix(80, 1.50, 0.8));
+
+var c = d3Color.cubehelix();
+
+function rainbow(t) {
+ if (t < 0 || t > 1) t -= Math.floor(t);
+ var ts = Math.abs(t - 0.5);
+ c.h = 360 * t - 100;
+ c.s = 1.5 - 1.5 * ts;
+ c.l = 0.8 - 0.9 * ts;
+ return c + "";
+}
+
+var c$1 = d3Color.rgb(),
+ pi_1_3 = Math.PI / 3,
+ pi_2_3 = Math.PI * 2 / 3;
+
+function sinebow(t) {
+ var x;
+ t = (0.5 - t) * Math.PI;
+ c$1.r = 255 * (x = Math.sin(t)) * x;
+ c$1.g = 255 * (x = Math.sin(t + pi_1_3)) * x;
+ c$1.b = 255 * (x = Math.sin(t + pi_2_3)) * x;
+ return c$1 + "";
+}
+
+function turbo(t) {
+ t = Math.max(0, Math.min(1, t));
+ return "rgb("
+ + Math.max(0, Math.min(255, Math.round(34.61 + t * (1172.33 - t * (10793.56 - t * (33300.12 - t * (38394.49 - t * 14825.05))))))) + ", "
+ + Math.max(0, Math.min(255, Math.round(23.31 + t * (557.33 + t * (1225.33 - t * (3574.96 - t * (1073.77 + t * 707.56))))))) + ", "
+ + Math.max(0, Math.min(255, Math.round(27.2 + t * (3211.1 - t * (15327.97 - t * (27814 - t * (22569.18 - t * 6838.66)))))))
+ + ")";
+}
+
+function ramp$1(range) {
+ var n = range.length;
+ return function(t) {
+ return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
+ };
+}
+
+var viridis = ramp$1(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
+
+var magma = ramp$1(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
+
+var inferno = ramp$1(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
+
+var plasma = ramp$1(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));
+
+exports.interpolateBlues = Blues;
+exports.interpolateBrBG = BrBG;
+exports.interpolateBuGn = BuGn;
+exports.interpolateBuPu = BuPu;
+exports.interpolateCividis = cividis;
+exports.interpolateCool = cool;
+exports.interpolateCubehelixDefault = cubehelix;
+exports.interpolateGnBu = GnBu;
+exports.interpolateGreens = Greens;
+exports.interpolateGreys = Greys;
+exports.interpolateInferno = inferno;
+exports.interpolateMagma = magma;
+exports.interpolateOrRd = OrRd;
+exports.interpolateOranges = Oranges;
+exports.interpolatePRGn = PRGn;
+exports.interpolatePiYG = PiYG;
+exports.interpolatePlasma = plasma;
+exports.interpolatePuBu = PuBu;
+exports.interpolatePuBuGn = PuBuGn;
+exports.interpolatePuOr = PuOr;
+exports.interpolatePuRd = PuRd;
+exports.interpolatePurples = Purples;
+exports.interpolateRainbow = rainbow;
+exports.interpolateRdBu = RdBu;
+exports.interpolateRdGy = RdGy;
+exports.interpolateRdPu = RdPu;
+exports.interpolateRdYlBu = RdYlBu;
+exports.interpolateRdYlGn = RdYlGn;
+exports.interpolateReds = Reds;
+exports.interpolateSinebow = sinebow;
+exports.interpolateSpectral = Spectral;
+exports.interpolateTurbo = turbo;
+exports.interpolateViridis = viridis;
+exports.interpolateWarm = warm;
+exports.interpolateYlGn = YlGn;
+exports.interpolateYlGnBu = YlGnBu;
+exports.interpolateYlOrBr = YlOrBr;
+exports.interpolateYlOrRd = YlOrRd;
+exports.schemeAccent = Accent;
+exports.schemeBlues = scheme$l;
+exports.schemeBrBG = scheme;
+exports.schemeBuGn = scheme$9;
+exports.schemeBuPu = scheme$a;
+exports.schemeCategory10 = category10;
+exports.schemeDark2 = Dark2;
+exports.schemeGnBu = scheme$b;
+exports.schemeGreens = scheme$m;
+exports.schemeGreys = scheme$n;
+exports.schemeOrRd = scheme$c;
+exports.schemeOranges = scheme$q;
+exports.schemePRGn = scheme$1;
+exports.schemePaired = Paired;
+exports.schemePastel1 = Pastel1;
+exports.schemePastel2 = Pastel2;
+exports.schemePiYG = scheme$2;
+exports.schemePuBu = scheme$e;
+exports.schemePuBuGn = scheme$d;
+exports.schemePuOr = scheme$3;
+exports.schemePuRd = scheme$f;
+exports.schemePurples = scheme$o;
+exports.schemeRdBu = scheme$4;
+exports.schemeRdGy = scheme$5;
+exports.schemeRdPu = scheme$g;
+exports.schemeRdYlBu = scheme$6;
+exports.schemeRdYlGn = scheme$7;
+exports.schemeReds = scheme$p;
+exports.schemeSet1 = Set1;
+exports.schemeSet2 = Set2;
+exports.schemeSet3 = Set3;
+exports.schemeSpectral = scheme$8;
+exports.schemeTableau10 = Tableau10;
+exports.schemeYlGn = scheme$i;
+exports.schemeYlGnBu = scheme$h;
+exports.schemeYlOrBr = scheme$j;
+exports.schemeYlOrRd = scheme$k;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-scale-chromatic/dist/d3-scale-chromatic.min.js b/node_modules/d3-scale-chromatic/dist/d3-scale-chromatic.min.js
new file mode 100644
index 00000000..191130af
--- /dev/null
+++ b/node_modules/d3-scale-chromatic/dist/d3-scale-chromatic.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-scale-chromatic/ v2.0.0 Copyright 2020 Mike Bostock
+!function(f,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("d3-interpolate"),require("d3-color")):"function"==typeof define&&define.amd?define(["exports","d3-interpolate","d3-color"],e):e((f=f||self).d3=f.d3||{},f.d3,f.d3)}(this,function(f,e,d){"use strict";function a(f){for(var e=f.length/6|0,d=new Array(e),a=0;a
# time.ticks([interval])
+
+Returns representative dates from the scale’s [domain](#time_domain). The returned tick values are uniformly-spaced (mostly), have sensible values (such as every day at midnight), and are guaranteed to be within the extent of the domain. Ticks are often used to display reference lines, or tick marks, in conjunction with the visualized data.
+
+An optional *count* may be specified to affect how many ticks are generated. If *count* is not specified, it defaults to 10. The specified *count* is only a hint; the scale may return more or fewer values depending on the domain. For example, to create ten default ticks, say:
+
+```js
+var x = d3.scaleTime();
+
+x.ticks(10);
+// [Sat Jan 01 2000 00:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 03:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 06:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 09:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 12:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 15:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 18:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 21:00:00 GMT-0800 (PST),
+// Sun Jan 02 2000 00:00:00 GMT-0800 (PST)]
+```
+
+The following time intervals are considered for automatic ticks:
+
+* 1-, 5-, 15- and 30-second.
+* 1-, 5-, 15- and 30-minute.
+* 1-, 3-, 6- and 12-hour.
+* 1- and 2-day.
+* 1-week.
+* 1- and 3-month.
+* 1-year.
+
+In lieu of a *count*, a [time *interval*](https://github.com/d3/d3-time/blob/master/README.md#intervals) may be explicitly specified. To prune the generated ticks for a given time *interval*, use [*interval*.every](https://github.com/d3/d3-time/blob/master/README.md#interval_every). For example, to generate ticks at 15-[minute](https://github.com/d3/d3-time/blob/master/README.md#minute) intervals:
+
+```js
+var x = d3.scaleTime()
+ .domain([new Date(2000, 0, 1, 0), new Date(2000, 0, 1, 2)]);
+
+x.ticks(d3.timeMinute.every(15));
+// [Sat Jan 01 2000 00:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 00:15:00 GMT-0800 (PST),
+// Sat Jan 01 2000 00:30:00 GMT-0800 (PST),
+// Sat Jan 01 2000 00:45:00 GMT-0800 (PST),
+// Sat Jan 01 2000 01:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 01:15:00 GMT-0800 (PST),
+// Sat Jan 01 2000 01:30:00 GMT-0800 (PST),
+// Sat Jan 01 2000 01:45:00 GMT-0800 (PST),
+// Sat Jan 01 2000 02:00:00 GMT-0800 (PST)]
+```
+
+Alternatively, pass a test function to [*interval*.filter](https://github.com/d3/d3-time/blob/master/README.md#interval_filter):
+
+```js
+x.ticks(d3.timeMinute.filter(function(d) {
+ return d.getMinutes() % 15 === 0;
+}));
+```
+
+Note: in some cases, such as with day ticks, specifying a *step* can result in irregular spacing of ticks because time intervals have varying length.
+
+# time.tickFormat([count[, specifier]]) · [Source](https://github.com/d3/d3-scale/blob/master/src/time.js), [Examples](https://observablehq.com/@d3/scale-ticks)
+
# time.tickFormat([interval[, specifier]])
+
+Returns a time format function suitable for displaying [tick](#time_ticks) values. The specified *count* or *interval* is currently ignored, but is accepted for consistency with other scales such as [*continuous*.tickFormat](#continuous_tickFormat). If a format *specifier* is specified, this method is equivalent to [format](https://github.com/d3/d3-time-format/blob/master/README.md#format). If *specifier* is not specified, the default time format is returned. The default multi-scale time format chooses a human-readable representation based on the specified date as follows:
+
+* `%Y` - for year boundaries, such as `2011`.
+* `%B` - for month boundaries, such as `February`.
+* `%b %d` - for week boundaries, such as `Feb 06`.
+* `%a %d` - for day boundaries, such as `Mon 07`.
+* `%I %p` - for hour boundaries, such as `01 AM`.
+* `%I:%M` - for minute boundaries, such as `01:23`.
+* `:%S` - for second boundaries, such as `:45`.
+* `.%L` - milliseconds for all other times, such as `.012`.
+
+Although somewhat unusual, this default behavior has the benefit of providing both local and global context: for example, formatting a sequence of ticks as [11 PM, Mon 07, 01 AM] reveals information about hours, dates, and day simultaneously, rather than just the hours [11 PM, 12 AM, 01 AM]. See [d3-time-format](https://github.com/d3/d3-time-format) if you’d like to roll your own conditional time format.
+
+# time.nice([count]) · [Source](https://github.com/d3/d3-scale/blob/master/src/time.js), [Examples](https://observablehq.com/@d3/d3-scaletime)
+
# time.nice([interval])
+
+Extends the [domain](#time_domain) so that it starts and ends on nice round values. This method typically modifies the scale’s domain, and may only extend the bounds to the nearest round value. See [*continuous*.nice](#continuous_nice) for more.
+
+An optional tick *count* argument allows greater control over the step size used to extend the bounds, guaranteeing that the returned [ticks](#time_ticks) will exactly cover the domain. Alternatively, a [time *interval*](https://github.com/d3/d3-time/blob/master/README.md#intervals) may be specified to explicitly set the ticks. If an *interval* is specified, an optional *step* may also be specified to skip some ticks. For example, `time.nice(d3.timeSecond.every(10))` will extend the domain to an even ten seconds (0, 10, 20, etc.). See [*time*.ticks](#time_ticks) and [*interval*.every](https://github.com/d3/d3-time/blob/master/README.md#interval_every) for further detail.
+
+Nicing is useful if the domain is computed from data, say using [extent](https://github.com/d3/d3-array/blob/master/README.md#extent), and may be irregular. For example, for a domain of [2009-07-13T00:02, 2009-07-13T23:48], the nice domain is [2009-07-13, 2009-07-14]. If the domain has more than two values, nicing the domain only affects the first and last value.
+
+# time.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/time.js), [Examples](https://observablehq.com/@d3/d3-scaletime)
+
+See [*continuous*.copy](#continuous_copy).
+
+# d3.scaleUtc([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/utcTime.js), [Examples](https://observablehq.com/@d3/d3-scaletime)
+
+Equivalent to [scaleTime](#scaleTime), but the returned time scale operates in [Coordinated Universal Time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) rather than local time.
+
+### Sequential Scales
+
+Sequential scales, like [diverging scales](#diverging-scales), are similar to [continuous scales](#continuous-scales) in that they map a continuous, numeric input domain to a continuous output range. However, unlike continuous scales, the input domain and output range of a sequential scale always has exactly two elements, and the output range is typically specified as an interpolator rather than an array of values. These scales do not expose [invert](#continuous_invert) and [interpolate](#continuous_interpolate) methods.
+
+# d3.scaleSequential([[domain, ]interpolator]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+Constructs a new sequential scale with the specified [*domain*](#sequential_domain) and [*interpolator*](#sequential_interpolator) function or array. If *domain* is not specified, it defaults to [0, 1]. If *interpolator* is not specified, it defaults to the identity function. When the scale is [applied](#_sequential), the interpolator will be invoked with a value typically in the range [0, 1], where 0 represents the minimum value and 1 represents the maximum value. For example, to implement the ill-advised [HSL](https://github.com/d3/d3-color/blob/master/README.md#hsl) rainbow scale:
+
+```js
+var rainbow = d3.scaleSequential(function(t) {
+ return d3.hsl(t * 360, 1, 0.5) + "";
+});
+```
+
+A more aesthetically-pleasing and perceptually-effective cyclical hue encoding is to use [d3.interpolateRainbow](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#interpolateRainbow):
+
+```js
+var rainbow = d3.scaleSequential(d3.interpolateRainbow);
+```
+
+If *interpolator* is an array, it represents the scale’s two-element output range and is converted to an interpolator function using [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate).
+
+# sequential(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*](#_continuous).
+
+# sequential.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*.domain](#continuous_domain). Note that a sequential scale’s domain must be numeric and must contain exactly two values.
+
+# sequential.clamp([clamp]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*.clamp](#continuous_clamp).
+
+# sequential.interpolator([interpolator]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+If *interpolator* is specified, sets the scale’s interpolator to the specified function. If *interpolator* is not specified, returns the scale’s current interpolator.
+
+# sequential.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*.range](#continuous_range). If *range* is specified, the given two-element array is converted to an interpolator function using [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate).
+
+# sequential.rangeRound([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*.rangeRound](#continuous_rangeRound). If *range* is specified, implicitly uses [d3.interpolateRound](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRound) as the interpolator.
+
+# sequential.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*.copy](#continuous_copy).
+
+# d3.scaleSequentialLog([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+A [sequential scale](#sequential-scales) with a logarithmic transform, analogous to a [log scale](#log-scales).
+
+# d3.scaleSequentialPow([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+A [sequential scale](#sequential-scales) with an exponential transform, analogous to a [power scale](#pow-scales).
+
+# d3.scaleSequentialSqrt([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+A [sequential scale](#sequential-scales) with a square-root transform, analogous to a [d3.scaleSqrt](#scaleSqrt).
+
+# d3.scaleSequentialSymlog([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+A [sequential scale](#sequential-scales) with a symmetric logarithmic transform, analogous to a [symlog scale](#symlog-scales).
+
+# d3.scaleSequentialQuantile([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequentialQuantile.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+A [sequential scale](#sequential-scales) using a *p*-quantile transform, analogous to a [quantile scale](#quantile-scales).
+
+# sequentialQuantile.quantiles(n) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequentialQuantile.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+Returns an array of *n* + 1 quantiles. For example, if *n* = 4, returns an array of five numbers: the minimum value, the first quartile, the median, the third quartile, and the maximum.
+
+### Diverging Scales
+
+Diverging scales, like [sequential scales](#sequential-scales), are similar to [continuous scales](#continuous-scales) in that they map a continuous, numeric input domain to a continuous output range. However, unlike continuous scales, the input domain and output range of a diverging scale always has exactly three elements, and the output range is typically specified as an interpolator rather than an array of values. These scales do not expose [invert](#continuous_invert) and [interpolate](#continuous_interpolate) methods.
+
+# d3.scaleDiverging([[domain, ]interpolator]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+Constructs a new diverging scale with the specified [*domain*](#diverging_domain) and [*interpolator*](#diverging_interpolator) function or array. If *domain* is not specified, it defaults to [0, 0.5, 1]. If *interpolator* is not specified, it defaults to the identity function. When the scale is [applied](#_diverging), the interpolator will be invoked with a value typically in the range [0, 1], where 0 represents the extreme negative value, 0.5 represents the neutral value, and 1 represents the extreme positive value. For example, using [d3.interpolateSpectral](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#interpolateSpectral):
+
+```js
+var spectral = d3.scaleDiverging(d3.interpolateSpectral);
+```
+
+If *interpolator* is an array, it represents the scale’s three-element output range and is converted to an interpolator function using [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate) and [d3.piecewise](https://github.com/d3/d3-interpolate/blob/master/README.md#piecewise).
+
+# diverging(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*](#_continuous).
+
+# diverging.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.domain](#continuous_domain). Note that a diverging scale’s domain must be numeric and must contain exactly three values. The default domain is [0, 0.5, 1].
+
+# diverging.clamp([clamp]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.clamp](#continuous_clamp).
+
+# diverging.interpolator([interpolator]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+If *interpolator* is specified, sets the scale’s interpolator to the specified function. If *interpolator* is not specified, returns the scale’s current interpolator.
+
+# diverging.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.range](#continuous_range). If *range* is specified, the given three-element array is converted to an interpolator function using [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate) and [d3.piecewise](https://github.com/d3/d3-interpolate/blob/master/README.md#piecewise).
+
+# diverging.rangeRound([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.range](#continuous_rangeRound). If *range* is specified, implicitly uses [d3.interpolateRound](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRound) as the interpolator.
+
+# diverging.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.copy](#continuous_copy).
+
+# diverging.unknown() · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.unknown](#continuous_unknown).
+
+# d3.scaleDivergingLog([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+A [diverging scale](#diverging-scales) with a logarithmic transform, analogous to a [log scale](#log-scales).
+
+# d3.scaleDivergingPow([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+A [diverging scale](#diverging-scales) with an exponential transform, analogous to a [power scale](#pow-scales).
+
+# d3.scaleDivergingSqrt([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+A [diverging scale](#diverging-scales) with a square-root transform, analogous to a [d3.scaleSqrt](#scaleSqrt).
+
+# d3.scaleDivergingSymlog([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+A [diverging scale](#diverging-scales) with a symmetric logarithmic transform, analogous to a [symlog scale](#symlog-scales).
+
+### Quantize Scales
+
+Quantize scales are similar to [linear scales](#linear-scales), except they use a discrete rather than continuous range. The continuous input domain is divided into uniform segments based on the number of values in (*i.e.*, the cardinality of) the output range. Each range value *y* can be expressed as a quantized linear function of the domain value *x*: *y* = *m round(x)* + *b*. See [this choropleth](https://observablehq.com/@d3/choropleth) for an example.
+
+# d3.scaleQuantize([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Constructs a new quantize scale with the specified [*domain*](#quantize_domain) and [*range*](#quantize_range). If either *domain* or *range* is not specified, each defaults to [0, 1]. Thus, the default quantize scale is equivalent to the [Math.round](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Math/round) function.
+
+# quantize(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Given a *value* in the input [domain](#quantize_domain), returns the corresponding value in the output [range](#quantize_range). For example, to apply a color encoding:
+
+```js
+var color = d3.scaleQuantize()
+ .domain([0, 1])
+ .range(["brown", "steelblue"]);
+
+color(0.49); // "brown"
+color(0.51); // "steelblue"
+```
+
+Or dividing the domain into three equally-sized parts with different range values to compute an appropriate stroke width:
+
+```js
+var width = d3.scaleQuantize()
+ .domain([10, 100])
+ .range([1, 2, 4]);
+
+width(20); // 1
+width(50); // 2
+width(80); // 4
+```
+
+# quantize.invertExtent(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns the extent of values in the [domain](#quantize_domain) [x0, x1] for the corresponding *value* in the [range](#quantize_range): the inverse of [*quantize*](#_quantize). This method is useful for interaction, say to determine the value in the domain that corresponds to the pixel location under the mouse.
+
+```js
+var width = d3.scaleQuantize()
+ .domain([10, 100])
+ .range([1, 2, 4]);
+
+width.invertExtent(2); // [40, 70]
+```
+
+# quantize.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *domain* is specified, sets the scale’s domain to the specified two-element array of numbers. If the elements in the given array are not numbers, they will be coerced to numbers. The numbers must be in ascending order or the behavior of the scale is undefined. If *domain* is not specified, returns the scale’s current domain.
+
+# quantize.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *range* is specified, sets the scale’s range to the specified array of values. The array may contain any number of discrete values. The elements in the given array need not be numbers; any value or type will work. If *range* is not specified, returns the scale’s current range.
+
+# quantize.ticks([count]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/scale-ticks)
+
+Equivalent to [*continuous*.ticks](#continuous_ticks).
+
+# quantize.tickFormat([count[, specifier]]) · [Source](https://github.com/d3/d3-scale/blob/master/src/linear.js), [Examples](https://observablehq.com/@d3/scale-ticks)
+
+Equivalent to [*continuous*.tickFormat](#continuous_tickFormat).
+
+# quantize.nice() · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Equivalent to [*continuous*.nice](#continuous_nice).
+
+# quantize.thresholds() · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns the array of computed thresholds within the [domain](#quantize_domain).
+
+# quantize.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.
+
+### Quantile Scales
+
+Quantile scales map a sampled input domain to a discrete range. The domain is considered continuous and thus the scale will accept any reasonable input value; however, the domain is specified as a discrete set of sample values. The number of values in (the cardinality of) the output range determines the number of quantiles that will be computed from the domain. To compute the quantiles, the domain is sorted, and treated as a [population of discrete values](https://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population); see d3-array’s [quantile](https://github.com/d3/d3-array/blob/master/README.md#quantile). See [this quantile choropleth](https://observablehq.com/@d3/quantile-choropleth) for an example.
+
+# d3.scaleQuantile([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Constructs a new quantile scale with the specified [*domain*](#quantile_domain) and [*range*](#quantile_range). If either *domain* or *range* is not specified, each defaults to the empty array. The quantile scale is invalid until both a domain and range are specified.
+
+# quantile(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Given a *value* in the input [domain](#quantile_domain), returns the corresponding value in the output [range](#quantile_range).
+
+# quantile.invertExtent(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns the extent of values in the [domain](#quantile_domain) [x0, x1] for the corresponding *value* in the [range](#quantile_range): the inverse of [*quantile*](#_quantile). This method is useful for interaction, say to determine the value in the domain that corresponds to the pixel location under the mouse.
+
+# quantile.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *domain* is specified, sets the domain of the quantile scale to the specified set of discrete numeric values. The array must not be empty, and must contain at least one numeric value; NaN, null and undefined values are ignored and not considered part of the sample population. If the elements in the given array are not numbers, they will be coerced to numbers. A copy of the input array is sorted and stored internally. If *domain* is not specified, returns the scale’s current domain.
+
+# quantile.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *range* is specified, sets the discrete values in the range. The array must not be empty, and may contain any type of value. The number of values in (the cardinality, or length, of) the *range* array determines the number of quantiles that are computed. For example, to compute quartiles, *range* must be an array of four elements such as [0, 1, 2, 3]. If *range* is not specified, returns the current range.
+
+# quantile.quantiles() · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns the quantile thresholds. If the [range](#quantile_range) contains *n* discrete values, the returned array will contain *n* - 1 thresholds. Values less than the first threshold are considered in the first quantile; values greater than or equal to the first threshold but less than the second threshold are in the second quantile, and so on. Internally, the thresholds array is used with [bisect](https://github.com/d3/d3-array/blob/master/README.md#bisect) to find the output quantile associated with the given input value.
+
+# quantile.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.
+
+### Threshold Scales
+
+Threshold scales are similar to [quantize scales](#quantize-scales), except they allow you to map arbitrary subsets of the domain to discrete values in the range. The input domain is still continuous, and divided into slices based on a set of threshold values. See [this choropleth](https://observablehq.com/@d3/threshold-choropleth) for an example.
+
+# d3.scaleThreshold([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Constructs a new threshold scale with the specified [*domain*](#threshold_domain) and [*range*](#threshold_range). If *domain* is not specified, it defaults to [0.5]. If *range* is not specified, it defaults to [0, 1]. Thus, the default threshold scale is equivalent to the [Math.round](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Math/round) function for numbers; for example threshold(0.49) returns 0, and threshold(0.51) returns 1.
+
+# threshold(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Given a *value* in the input [domain](#threshold_domain), returns the corresponding value in the output [range](#threshold_range). For example:
+
+```js
+var color = d3.scaleThreshold()
+ .domain([0, 1])
+ .range(["red", "white", "green"]);
+
+color(-1); // "red"
+color(0); // "white"
+color(0.5); // "white"
+color(1); // "green"
+color(1000); // "green"
+```
+
+# threshold.invertExtent(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/choropleth)
+
+Returns the extent of values in the [domain](#threshold_domain) [x0, x1] for the corresponding *value* in the [range](#threshold_range), representing the inverse mapping from range to domain. This method is useful for interaction, say to determine the value in the domain that corresponds to the pixel location under the mouse. For example:
+
+```js
+var color = d3.scaleThreshold()
+ .domain([0, 1])
+ .range(["red", "white", "green"]);
+
+color.invertExtent("red"); // [undefined, 0]
+color.invertExtent("white"); // [0, 1]
+color.invertExtent("green"); // [1, undefined]
+```
+
+# threshold.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *domain* is specified, sets the scale’s domain to the specified array of values. The values must be in ascending order or the behavior of the scale is undefined. The values are typically numbers, but any naturally ordered values (such as strings) will work; a threshold scale can be used to encode any type that is ordered. If the number of values in the scale’s range is N+1, the number of values in the scale’s domain must be N. If there are fewer than N elements in the domain, the additional values in the range are ignored. If there are more than N elements in the domain, the scale may return undefined for some inputs. If *domain* is not specified, returns the scale’s current domain.
+
+# threshold.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *range* is specified, sets the scale’s range to the specified array of values. If the number of values in the scale’s domain is N, the number of values in the scale’s range must be N+1. If there are fewer than N+1 elements in the range, the scale may return undefined for some inputs. If there are more than N+1 elements in the range, the additional values are ignored. The elements in the given array need not be numbers; any value or type will work. If *range* is not specified, returns the scale’s current range.
+
+# threshold.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.
+
+### Ordinal Scales
+
+Unlike [continuous scales](#continuous-scales), ordinal scales have a discrete domain and range. For example, an ordinal scale might map a set of named categories to a set of colors, or determine the horizontal positions of columns in a column chart.
+
+# d3.scaleOrdinal([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+Constructs a new ordinal scale with the specified [*domain*](#ordinal_domain) and [*range*](#ordinal_range). If *domain* is not specified, it defaults to the empty array. If *range* is not specified, it defaults to the empty array; an ordinal scale always returns undefined until a non-empty range is defined.
+
+# ordinal(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+Given a *value* in the input [domain](#ordinal_domain), returns the corresponding value in the output [range](#ordinal_range). If the given *value* is not in the scale’s [domain](#ordinal_domain), returns the [unknown](#ordinal_unknown); or, if the unknown value is [implicit](#scaleImplicit) (the default), then the *value* is implicitly added to the domain and the next-available value in the range is assigned to *value*, such that this and subsequent invocations of the scale given the same input *value* return the same output value.
+
+# ordinal.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+If *domain* is specified, sets the domain to the specified array of values. The first element in *domain* will be mapped to the first element in the range, the second domain value to the second range value, and so on. Domain values are stored internally in a map from stringified value to index; the resulting index is then used to retrieve a value from the range. Thus, an ordinal scale’s values must be coercible to a string, and the stringified version of the domain value uniquely identifies the corresponding range value. If *domain* is not specified, this method returns the current domain.
+
+Setting the domain on an ordinal scale is optional if the [unknown value](#ordinal_unknown) is [implicit](#scaleImplicit) (the default). In this case, the domain will be inferred implicitly from usage by assigning each unique value passed to the scale a new value from the range. Note that an explicit domain is recommended to ensure deterministic behavior, as inferring the domain from usage will be dependent on ordering.
+
+# ordinal.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+If *range* is specified, sets the range of the ordinal scale to the specified array of values. The first element in the domain will be mapped to the first element in *range*, the second domain value to the second range value, and so on. If there are fewer elements in the range than in the domain, the scale will reuse values from the start of the range. If *range* is not specified, this method returns the current range.
+
+# ordinal.unknown([value]) · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+If *value* is specified, sets the output value of the scale for unknown input values and returns this scale. If *value* is not specified, returns the current unknown value, which defaults to [implicit](#scaleImplicit). The implicit value enables implicit domain construction; see [*ordinal*.domain](#ordinal_domain).
+
+# ordinal.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+Returns an exact copy of this ordinal scale. Changes to this scale will not affect the returned scale, and vice versa.
+
+# d3.scaleImplicit · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+A special value for [*ordinal*.unknown](#ordinal_unknown) that enables implicit domain construction: unknown values are implicitly added to the domain.
+
+#### Band Scales
+
+Band scales are like [ordinal scales](#ordinal-scales) except the output range is continuous and numeric. Discrete output values are automatically computed by the scale by dividing the continuous range into uniform bands. Band scales are typically used for bar charts with an ordinal or categorical dimension. The [unknown value](#ordinal_unknown) of a band scale is effectively undefined: they do not allow implicit domain construction.
+
+
+
+# d3.scaleBand([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Constructs a new band scale with the specified [*domain*](#band_domain) and [*range*](#band_range), no [padding](#band_padding), no [rounding](#band_round) and center [alignment](#band_align). If *domain* is not specified, it defaults to the empty domain. If *range* is not specified, it defaults to the unit range [0, 1].
+
+# band(*value*) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Given a *value* in the input [domain](#band_domain), returns the start of the corresponding band derived from the output [range](#band_range). If the given *value* is not in the scale’s domain, returns undefined.
+
+# band.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *domain* is specified, sets the domain to the specified array of values. The first element in *domain* will be mapped to the first band, the second domain value to the second band, and so on. Domain values are stored internally in a map from stringified value to index; the resulting index is then used to determine the band. Thus, a band scale’s values must be coercible to a string, and the stringified version of the domain value uniquely identifies the corresponding band. If *domain* is not specified, this method returns the current domain.
+
+# band.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *range* is specified, sets the scale’s range to the specified two-element array of numbers. If the elements in the given array are not numbers, they will be coerced to numbers. If *range* is not specified, returns the scale’s current range, which defaults to [0, 1].
+
+# band.rangeRound([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Sets the scale’s [*range*](#band_range) to the specified two-element array of numbers while also enabling [rounding](#band_round). This is a convenience method equivalent to:
+
+```js
+band
+ .range(range)
+ .round(true);
+```
+
+Rounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges†styles.
+
+# band.round([round]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *round* is specified, enables or disables rounding accordingly. If rounding is enabled, the start and stop of each band will be integers. Rounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges†styles. Note that if the width of the domain is not a multiple of the cardinality of the range, there may be leftover unused space, even without padding! Use [*band*.align](#band_align) to specify how the leftover space is distributed.
+
+# band.paddingInner([padding]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *padding* is specified, sets the inner padding to the specified number which must be less than or equal to 1. If *padding* is not specified, returns the current inner padding which defaults to 0. The inner padding specifies the proportion of the range that is reserved for blank space between bands; a value of 0 means no blank space between bands, and a value of 1 means a [bandwidth](#band_bandwidth) of zero.
+
+# band.paddingOuter([padding]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *padding* is specified, sets the outer padding to the specified number which is typically in the range [0, 1]. If *padding* is not specified, returns the current outer padding which defaults to 0. The outer padding specifies the amount of blank space, in terms of multiples of the [step](#band_step), to reserve before the first band and after the last band.
+
+# band.padding([padding]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+A convenience method for setting the [inner](#band_paddingInner) and [outer](#band_paddingOuter) padding to the same *padding* value. If *padding* is not specified, returns the inner padding.
+
+# band.align([align]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *align* is specified, sets the alignment to the specified value which must be in the range [0, 1]. If *align* is not specified, returns the current alignment which defaults to 0.5. The alignment specifies how outer padding is distributed in the range. A value of 0.5 indicates that the outer padding should be equally distributed before the first band and after the last band; *i.e.*, the bands should be centered within the range. A value of 0 or 1 may be used to shift the bands to one side, say to position them adjacent to an axis. For more, [see this explainer](https://observablehq.com/@d3/band-align).
+
+# band.bandwidth() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Returns the width of each band.
+
+# band.step() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Returns the distance between the starts of adjacent bands.
+
+# band.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Returns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.
+
+#### Point Scales
+
+Point scales are a variant of [band scales](#band-scales) with the bandwidth fixed to zero. Point scales are typically used for scatterplots with an ordinal or categorical dimension. The [unknown value](#ordinal_unknown) of a point scale is always undefined: they do not allow implicit domain construction.
+
+
+
+# d3.scalePoint([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Constructs a new point scale with the specified [*domain*](#point_domain) and [*range*](#point_range), no [padding](#point_padding), no [rounding](#point_round) and center [alignment](#point_align). If *domain* is not specified, it defaults to the empty domain. If *range* is not specified, it defaults to the unit range [0, 1].
+
+# point(*value*) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Given a *value* in the input [domain](#point_domain), returns the corresponding point derived from the output [range](#point_range). If the given *value* is not in the scale’s domain, returns undefined.
+
+# point.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+If *domain* is specified, sets the domain to the specified array of values. The first element in *domain* will be mapped to the first point, the second domain value to the second point, and so on. Domain values are stored internally in a map from stringified value to index; the resulting index is then used to determine the point. Thus, a point scale’s values must be coercible to a string, and the stringified version of the domain value uniquely identifies the corresponding point. If *domain* is not specified, this method returns the current domain.
+
+# point.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+If *range* is specified, sets the scale’s range to the specified two-element array of numbers. If the elements in the given array are not numbers, they will be coerced to numbers. If *range* is not specified, returns the scale’s current range, which defaults to [0, 1].
+
+# point.rangeRound([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Sets the scale’s [*range*](#point_range) to the specified two-element array of numbers while also enabling [rounding](#point_round). This is a convenience method equivalent to:
+
+```js
+point
+ .range(range)
+ .round(true);
+```
+
+Rounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges†styles.
+
+# point.round([round]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+If *round* is specified, enables or disables rounding accordingly. If rounding is enabled, the position of each point will be integers. Rounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges†styles. Note that if the width of the domain is not a multiple of the cardinality of the range, there may be leftover unused space, even without padding! Use [*point*.align](#point_align) to specify how the leftover space is distributed.
+
+# point.padding([padding]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+If *padding* is specified, sets the outer padding to the specified number which is typically in the range [0, 1]. If *padding* is not specified, returns the current outer padding which defaults to 0. The outer padding specifies the amount of blank space, in terms of multiples of the [step](#band_step), to reserve before the first point and after the last point. Equivalent to [*band*.paddingOuter](#band_paddingOuter).
+
+# point.align([align]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+If *align* is specified, sets the alignment to the specified value which must be in the range [0, 1]. If *align* is not specified, returns the current alignment which defaults to 0.5. The alignment specifies how any leftover unused space in the range is distributed. A value of 0.5 indicates that the leftover space should be equally distributed before the first point and after the last point; *i.e.*, the points should be centered within the range. A value of 0 or 1 may be used to shift the points to one side, say to position them adjacent to an axis.
+
+# point.bandwidth() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Returns zero.
+
+# point.step() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Returns the distance between the starts of adjacent points.
+
+# point.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Returns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.
diff --git a/node_modules/d3-scale/dist/d3-scale.js b/node_modules/d3-scale/dist/d3-scale.js
new file mode 100644
index 00000000..7a8c7e1e
--- /dev/null
+++ b/node_modules/d3-scale/dist/d3-scale.js
@@ -0,0 +1,1267 @@
+// https://d3js.org/d3-scale/ v3.2.3 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array'), require('d3-interpolate'), require('d3-format'), require('d3-time'), require('d3-time-format')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-array', 'd3-interpolate', 'd3-format', 'd3-time', 'd3-time-format'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}, global.d3, global.d3, global.d3, global.d3, global.d3));
+}(this, function (exports, d3Array, d3Interpolate, d3Format, d3Time, d3TimeFormat) { 'use strict';
+
+function initRange(domain, range) {
+ switch (arguments.length) {
+ case 0: break;
+ case 1: this.range(domain); break;
+ default: this.range(range).domain(domain); break;
+ }
+ return this;
+}
+
+function initInterpolator(domain, interpolator) {
+ switch (arguments.length) {
+ case 0: break;
+ case 1: {
+ if (typeof domain === "function") this.interpolator(domain);
+ else this.range(domain);
+ break;
+ }
+ default: {
+ this.domain(domain);
+ if (typeof interpolator === "function") this.interpolator(interpolator);
+ else this.range(interpolator);
+ break;
+ }
+ }
+ return this;
+}
+
+const implicit = Symbol("implicit");
+
+function ordinal() {
+ var index = new Map(),
+ domain = [],
+ range = [],
+ unknown = implicit;
+
+ function scale(d) {
+ var key = d + "", i = index.get(key);
+ if (!i) {
+ if (unknown !== implicit) return unknown;
+ index.set(key, i = domain.push(d));
+ }
+ return range[(i - 1) % range.length];
+ }
+
+ scale.domain = function(_) {
+ if (!arguments.length) return domain.slice();
+ domain = [], index = new Map();
+ for (const value of _) {
+ const key = value + "";
+ if (index.has(key)) continue;
+ index.set(key, domain.push(value));
+ }
+ return scale;
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (range = Array.from(_), scale) : range.slice();
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ scale.copy = function() {
+ return ordinal(domain, range).unknown(unknown);
+ };
+
+ initRange.apply(scale, arguments);
+
+ return scale;
+}
+
+function band() {
+ var scale = ordinal().unknown(undefined),
+ domain = scale.domain,
+ ordinalRange = scale.range,
+ r0 = 0,
+ r1 = 1,
+ step,
+ bandwidth,
+ round = false,
+ paddingInner = 0,
+ paddingOuter = 0,
+ align = 0.5;
+
+ delete scale.unknown;
+
+ function rescale() {
+ var n = domain().length,
+ reverse = r1 < r0,
+ start = reverse ? r1 : r0,
+ stop = reverse ? r0 : r1;
+ step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);
+ if (round) step = Math.floor(step);
+ start += (stop - start - step * (n - paddingInner)) * align;
+ bandwidth = step * (1 - paddingInner);
+ if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);
+ var values = d3Array.range(n).map(function(i) { return start + step * i; });
+ return ordinalRange(reverse ? values.reverse() : values);
+ }
+
+ scale.domain = function(_) {
+ return arguments.length ? (domain(_), rescale()) : domain();
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? ([r0, r1] = _, r0 = +r0, r1 = +r1, rescale()) : [r0, r1];
+ };
+
+ scale.rangeRound = function(_) {
+ return [r0, r1] = _, r0 = +r0, r1 = +r1, round = true, rescale();
+ };
+
+ scale.bandwidth = function() {
+ return bandwidth;
+ };
+
+ scale.step = function() {
+ return step;
+ };
+
+ scale.round = function(_) {
+ return arguments.length ? (round = !!_, rescale()) : round;
+ };
+
+ scale.padding = function(_) {
+ return arguments.length ? (paddingInner = Math.min(1, paddingOuter = +_), rescale()) : paddingInner;
+ };
+
+ scale.paddingInner = function(_) {
+ return arguments.length ? (paddingInner = Math.min(1, _), rescale()) : paddingInner;
+ };
+
+ scale.paddingOuter = function(_) {
+ return arguments.length ? (paddingOuter = +_, rescale()) : paddingOuter;
+ };
+
+ scale.align = function(_) {
+ return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;
+ };
+
+ scale.copy = function() {
+ return band(domain(), [r0, r1])
+ .round(round)
+ .paddingInner(paddingInner)
+ .paddingOuter(paddingOuter)
+ .align(align);
+ };
+
+ return initRange.apply(rescale(), arguments);
+}
+
+function pointish(scale) {
+ var copy = scale.copy;
+
+ scale.padding = scale.paddingOuter;
+ delete scale.paddingInner;
+ delete scale.paddingOuter;
+
+ scale.copy = function() {
+ return pointish(copy());
+ };
+
+ return scale;
+}
+
+function point() {
+ return pointish(band.apply(null, arguments).paddingInner(1));
+}
+
+function constants(x) {
+ return function() {
+ return x;
+ };
+}
+
+function number(x) {
+ return +x;
+}
+
+var unit = [0, 1];
+
+function identity(x) {
+ return x;
+}
+
+function normalize(a, b) {
+ return (b -= (a = +a))
+ ? function(x) { return (x - a) / b; }
+ : constants(isNaN(b) ? NaN : 0.5);
+}
+
+function clamper(a, b) {
+ var t;
+ if (a > b) t = a, a = b, b = t;
+ return function(x) { return Math.max(a, Math.min(b, x)); };
+}
+
+// normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
+// interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].
+function bimap(domain, range, interpolate) {
+ var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];
+ if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);
+ else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);
+ return function(x) { return r0(d0(x)); };
+}
+
+function polymap(domain, range, interpolate) {
+ var j = Math.min(domain.length, range.length) - 1,
+ d = new Array(j),
+ r = new Array(j),
+ i = -1;
+
+ // Reverse descending domains.
+ if (domain[j] < domain[0]) {
+ domain = domain.slice().reverse();
+ range = range.slice().reverse();
+ }
+
+ while (++i < j) {
+ d[i] = normalize(domain[i], domain[i + 1]);
+ r[i] = interpolate(range[i], range[i + 1]);
+ }
+
+ return function(x) {
+ var i = d3Array.bisect(domain, x, 1, j) - 1;
+ return r[i](d[i](x));
+ };
+}
+
+function copy(source, target) {
+ return target
+ .domain(source.domain())
+ .range(source.range())
+ .interpolate(source.interpolate())
+ .clamp(source.clamp())
+ .unknown(source.unknown());
+}
+
+function transformer() {
+ var domain = unit,
+ range = unit,
+ interpolate = d3Interpolate.interpolate,
+ transform,
+ untransform,
+ unknown,
+ clamp = identity,
+ piecewise,
+ output,
+ input;
+
+ function rescale() {
+ var n = Math.min(domain.length, range.length);
+ if (clamp !== identity) clamp = clamper(domain[0], domain[n - 1]);
+ piecewise = n > 2 ? polymap : bimap;
+ output = input = null;
+ return scale;
+ }
+
+ function scale(x) {
+ return isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));
+ }
+
+ scale.invert = function(y) {
+ return clamp(untransform((input || (input = piecewise(range, domain.map(transform), d3Interpolate.interpolateNumber)))(y)));
+ };
+
+ scale.domain = function(_) {
+ return arguments.length ? (domain = Array.from(_, number), rescale()) : domain.slice();
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
+ };
+
+ scale.rangeRound = function(_) {
+ return range = Array.from(_), interpolate = d3Interpolate.interpolateRound, rescale();
+ };
+
+ scale.clamp = function(_) {
+ return arguments.length ? (clamp = _ ? true : identity, rescale()) : clamp !== identity;
+ };
+
+ scale.interpolate = function(_) {
+ return arguments.length ? (interpolate = _, rescale()) : interpolate;
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ return function(t, u) {
+ transform = t, untransform = u;
+ return rescale();
+ };
+}
+
+function continuous() {
+ return transformer()(identity, identity);
+}
+
+function tickFormat(start, stop, count, specifier) {
+ var step = d3Array.tickStep(start, stop, count),
+ precision;
+ specifier = d3Format.formatSpecifier(specifier == null ? ",f" : specifier);
+ switch (specifier.type) {
+ case "s": {
+ var value = Math.max(Math.abs(start), Math.abs(stop));
+ if (specifier.precision == null && !isNaN(precision = d3Format.precisionPrefix(step, value))) specifier.precision = precision;
+ return d3Format.formatPrefix(specifier, value);
+ }
+ case "":
+ case "e":
+ case "g":
+ case "p":
+ case "r": {
+ if (specifier.precision == null && !isNaN(precision = d3Format.precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
+ break;
+ }
+ case "f":
+ case "%": {
+ if (specifier.precision == null && !isNaN(precision = d3Format.precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
+ break;
+ }
+ }
+ return d3Format.format(specifier);
+}
+
+function linearish(scale) {
+ var domain = scale.domain;
+
+ scale.ticks = function(count) {
+ var d = domain();
+ return d3Array.ticks(d[0], d[d.length - 1], count == null ? 10 : count);
+ };
+
+ scale.tickFormat = function(count, specifier) {
+ var d = domain();
+ return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
+ };
+
+ scale.nice = function(count) {
+ if (count == null) count = 10;
+
+ var d = domain();
+ var i0 = 0;
+ var i1 = d.length - 1;
+ var start = d[i0];
+ var stop = d[i1];
+ var prestep;
+ var step;
+ var maxIter = 10;
+
+ if (stop < start) {
+ step = start, start = stop, stop = step;
+ step = i0, i0 = i1, i1 = step;
+ }
+
+ while (maxIter-- > 0) {
+ step = d3Array.tickIncrement(start, stop, count);
+ if (step === prestep) {
+ d[i0] = start;
+ d[i1] = stop;
+ return domain(d);
+ } else if (step > 0) {
+ start = Math.floor(start / step) * step;
+ stop = Math.ceil(stop / step) * step;
+ } else if (step < 0) {
+ start = Math.ceil(start * step) / step;
+ stop = Math.floor(stop * step) / step;
+ } else {
+ break;
+ }
+ prestep = step;
+ }
+
+ return scale;
+ };
+
+ return scale;
+}
+
+function linear() {
+ var scale = continuous();
+
+ scale.copy = function() {
+ return copy(scale, linear());
+ };
+
+ initRange.apply(scale, arguments);
+
+ return linearish(scale);
+}
+
+function identity$1(domain) {
+ var unknown;
+
+ function scale(x) {
+ return isNaN(x = +x) ? unknown : x;
+ }
+
+ scale.invert = scale;
+
+ scale.domain = scale.range = function(_) {
+ return arguments.length ? (domain = Array.from(_, number), scale) : domain.slice();
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ scale.copy = function() {
+ return identity$1(domain).unknown(unknown);
+ };
+
+ domain = arguments.length ? Array.from(domain, number) : [0, 1];
+
+ return linearish(scale);
+}
+
+function nice(domain, interval) {
+ domain = domain.slice();
+
+ var i0 = 0,
+ i1 = domain.length - 1,
+ x0 = domain[i0],
+ x1 = domain[i1],
+ t;
+
+ if (x1 < x0) {
+ t = i0, i0 = i1, i1 = t;
+ t = x0, x0 = x1, x1 = t;
+ }
+
+ domain[i0] = interval.floor(x0);
+ domain[i1] = interval.ceil(x1);
+ return domain;
+}
+
+function transformLog(x) {
+ return Math.log(x);
+}
+
+function transformExp(x) {
+ return Math.exp(x);
+}
+
+function transformLogn(x) {
+ return -Math.log(-x);
+}
+
+function transformExpn(x) {
+ return -Math.exp(-x);
+}
+
+function pow10(x) {
+ return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x;
+}
+
+function powp(base) {
+ return base === 10 ? pow10
+ : base === Math.E ? Math.exp
+ : function(x) { return Math.pow(base, x); };
+}
+
+function logp(base) {
+ return base === Math.E ? Math.log
+ : base === 10 && Math.log10
+ || base === 2 && Math.log2
+ || (base = Math.log(base), function(x) { return Math.log(x) / base; });
+}
+
+function reflect(f) {
+ return function(x) {
+ return -f(-x);
+ };
+}
+
+function loggish(transform) {
+ var scale = transform(transformLog, transformExp),
+ domain = scale.domain,
+ base = 10,
+ logs,
+ pows;
+
+ function rescale() {
+ logs = logp(base), pows = powp(base);
+ if (domain()[0] < 0) {
+ logs = reflect(logs), pows = reflect(pows);
+ transform(transformLogn, transformExpn);
+ } else {
+ transform(transformLog, transformExp);
+ }
+ return scale;
+ }
+
+ scale.base = function(_) {
+ return arguments.length ? (base = +_, rescale()) : base;
+ };
+
+ scale.domain = function(_) {
+ return arguments.length ? (domain(_), rescale()) : domain();
+ };
+
+ scale.ticks = function(count) {
+ var d = domain(),
+ u = d[0],
+ v = d[d.length - 1],
+ r;
+
+ if (r = v < u) i = u, u = v, v = i;
+
+ var i = logs(u),
+ j = logs(v),
+ p,
+ k,
+ t,
+ n = count == null ? 10 : +count,
+ z = [];
+
+ if (!(base % 1) && j - i < n) {
+ i = Math.floor(i), j = Math.ceil(j);
+ if (u > 0) for (; i <= j; ++i) {
+ for (k = 1, p = pows(i); k < base; ++k) {
+ t = p * k;
+ if (t < u) continue;
+ if (t > v) break;
+ z.push(t);
+ }
+ } else for (; i <= j; ++i) {
+ for (k = base - 1, p = pows(i); k >= 1; --k) {
+ t = p * k;
+ if (t < u) continue;
+ if (t > v) break;
+ z.push(t);
+ }
+ }
+ if (z.length * 2 < n) z = d3Array.ticks(u, v, n);
+ } else {
+ z = d3Array.ticks(i, j, Math.min(j - i, n)).map(pows);
+ }
+
+ return r ? z.reverse() : z;
+ };
+
+ scale.tickFormat = function(count, specifier) {
+ if (specifier == null) specifier = base === 10 ? ".0e" : ",";
+ if (typeof specifier !== "function") specifier = d3Format.format(specifier);
+ if (count === Infinity) return specifier;
+ if (count == null) count = 10;
+ var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
+ return function(d) {
+ var i = d / pows(Math.round(logs(d)));
+ if (i * base < base - 0.5) i *= base;
+ return i <= k ? specifier(d) : "";
+ };
+ };
+
+ scale.nice = function() {
+ return domain(nice(domain(), {
+ floor: function(x) { return pows(Math.floor(logs(x))); },
+ ceil: function(x) { return pows(Math.ceil(logs(x))); }
+ }));
+ };
+
+ return scale;
+}
+
+function log() {
+ var scale = loggish(transformer()).domain([1, 10]);
+
+ scale.copy = function() {
+ return copy(scale, log()).base(scale.base());
+ };
+
+ initRange.apply(scale, arguments);
+
+ return scale;
+}
+
+function transformSymlog(c) {
+ return function(x) {
+ return Math.sign(x) * Math.log1p(Math.abs(x / c));
+ };
+}
+
+function transformSymexp(c) {
+ return function(x) {
+ return Math.sign(x) * Math.expm1(Math.abs(x)) * c;
+ };
+}
+
+function symlogish(transform) {
+ var c = 1, scale = transform(transformSymlog(c), transformSymexp(c));
+
+ scale.constant = function(_) {
+ return arguments.length ? transform(transformSymlog(c = +_), transformSymexp(c)) : c;
+ };
+
+ return linearish(scale);
+}
+
+function symlog() {
+ var scale = symlogish(transformer());
+
+ scale.copy = function() {
+ return copy(scale, symlog()).constant(scale.constant());
+ };
+
+ return initRange.apply(scale, arguments);
+}
+
+function transformPow(exponent) {
+ return function(x) {
+ return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
+ };
+}
+
+function transformSqrt(x) {
+ return x < 0 ? -Math.sqrt(-x) : Math.sqrt(x);
+}
+
+function transformSquare(x) {
+ return x < 0 ? -x * x : x * x;
+}
+
+function powish(transform) {
+ var scale = transform(identity, identity),
+ exponent = 1;
+
+ function rescale() {
+ return exponent === 1 ? transform(identity, identity)
+ : exponent === 0.5 ? transform(transformSqrt, transformSquare)
+ : transform(transformPow(exponent), transformPow(1 / exponent));
+ }
+
+ scale.exponent = function(_) {
+ return arguments.length ? (exponent = +_, rescale()) : exponent;
+ };
+
+ return linearish(scale);
+}
+
+function pow() {
+ var scale = powish(transformer());
+
+ scale.copy = function() {
+ return copy(scale, pow()).exponent(scale.exponent());
+ };
+
+ initRange.apply(scale, arguments);
+
+ return scale;
+}
+
+function sqrt() {
+ return pow.apply(null, arguments).exponent(0.5);
+}
+
+function square(x) {
+ return Math.sign(x) * x * x;
+}
+
+function unsquare(x) {
+ return Math.sign(x) * Math.sqrt(Math.abs(x));
+}
+
+function radial() {
+ var squared = continuous(),
+ range = [0, 1],
+ round = false,
+ unknown;
+
+ function scale(x) {
+ var y = unsquare(squared(x));
+ return isNaN(y) ? unknown : round ? Math.round(y) : y;
+ }
+
+ scale.invert = function(y) {
+ return squared.invert(square(y));
+ };
+
+ scale.domain = function(_) {
+ return arguments.length ? (squared.domain(_), scale) : squared.domain();
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (squared.range((range = Array.from(_, number)).map(square)), scale) : range.slice();
+ };
+
+ scale.rangeRound = function(_) {
+ return scale.range(_).round(true);
+ };
+
+ scale.round = function(_) {
+ return arguments.length ? (round = !!_, scale) : round;
+ };
+
+ scale.clamp = function(_) {
+ return arguments.length ? (squared.clamp(_), scale) : squared.clamp();
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ scale.copy = function() {
+ return radial(squared.domain(), range)
+ .round(round)
+ .clamp(squared.clamp())
+ .unknown(unknown);
+ };
+
+ initRange.apply(scale, arguments);
+
+ return linearish(scale);
+}
+
+function quantile() {
+ var domain = [],
+ range = [],
+ thresholds = [],
+ unknown;
+
+ function rescale() {
+ var i = 0, n = Math.max(1, range.length);
+ thresholds = new Array(n - 1);
+ while (++i < n) thresholds[i - 1] = d3Array.quantileSorted(domain, i / n);
+ return scale;
+ }
+
+ function scale(x) {
+ return isNaN(x = +x) ? unknown : range[d3Array.bisect(thresholds, x)];
+ }
+
+ scale.invertExtent = function(y) {
+ var i = range.indexOf(y);
+ return i < 0 ? [NaN, NaN] : [
+ i > 0 ? thresholds[i - 1] : domain[0],
+ i < thresholds.length ? thresholds[i] : domain[domain.length - 1]
+ ];
+ };
+
+ scale.domain = function(_) {
+ if (!arguments.length) return domain.slice();
+ domain = [];
+ for (let d of _) if (d != null && !isNaN(d = +d)) domain.push(d);
+ domain.sort(d3Array.ascending);
+ return rescale();
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ scale.quantiles = function() {
+ return thresholds.slice();
+ };
+
+ scale.copy = function() {
+ return quantile()
+ .domain(domain)
+ .range(range)
+ .unknown(unknown);
+ };
+
+ return initRange.apply(scale, arguments);
+}
+
+function quantize() {
+ var x0 = 0,
+ x1 = 1,
+ n = 1,
+ domain = [0.5],
+ range = [0, 1],
+ unknown;
+
+ function scale(x) {
+ return x <= x ? range[d3Array.bisect(domain, x, 0, n)] : unknown;
+ }
+
+ function rescale() {
+ var i = -1;
+ domain = new Array(n);
+ while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
+ return scale;
+ }
+
+ scale.domain = function(_) {
+ return arguments.length ? ([x0, x1] = _, x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
+ };
+
+ scale.invertExtent = function(y) {
+ var i = range.indexOf(y);
+ return i < 0 ? [NaN, NaN]
+ : i < 1 ? [x0, domain[0]]
+ : i >= n ? [domain[n - 1], x1]
+ : [domain[i - 1], domain[i]];
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : scale;
+ };
+
+ scale.thresholds = function() {
+ return domain.slice();
+ };
+
+ scale.copy = function() {
+ return quantize()
+ .domain([x0, x1])
+ .range(range)
+ .unknown(unknown);
+ };
+
+ return initRange.apply(linearish(scale), arguments);
+}
+
+function threshold() {
+ var domain = [0.5],
+ range = [0, 1],
+ unknown,
+ n = 1;
+
+ function scale(x) {
+ return x <= x ? range[d3Array.bisect(domain, x, 0, n)] : unknown;
+ }
+
+ scale.domain = function(_) {
+ return arguments.length ? (domain = Array.from(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (range = Array.from(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice();
+ };
+
+ scale.invertExtent = function(y) {
+ var i = range.indexOf(y);
+ return [domain[i - 1], domain[i]];
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ scale.copy = function() {
+ return threshold()
+ .domain(domain)
+ .range(range)
+ .unknown(unknown);
+ };
+
+ return initRange.apply(scale, arguments);
+}
+
+var durationSecond = 1000,
+ durationMinute = durationSecond * 60,
+ durationHour = durationMinute * 60,
+ durationDay = durationHour * 24,
+ durationWeek = durationDay * 7,
+ durationMonth = durationDay * 30,
+ durationYear = durationDay * 365;
+
+function date(t) {
+ return new Date(t);
+}
+
+function number$1(t) {
+ return t instanceof Date ? +t : +new Date(+t);
+}
+
+function calendar(year, month, week, day, hour, minute, second, millisecond, format) {
+ var scale = continuous(),
+ invert = scale.invert,
+ domain = scale.domain;
+
+ var formatMillisecond = format(".%L"),
+ formatSecond = format(":%S"),
+ formatMinute = format("%I:%M"),
+ formatHour = format("%I %p"),
+ formatDay = format("%a %d"),
+ formatWeek = format("%b %d"),
+ formatMonth = format("%B"),
+ formatYear = format("%Y");
+
+ var tickIntervals = [
+ [second, 1, durationSecond],
+ [second, 5, 5 * durationSecond],
+ [second, 15, 15 * durationSecond],
+ [second, 30, 30 * durationSecond],
+ [minute, 1, durationMinute],
+ [minute, 5, 5 * durationMinute],
+ [minute, 15, 15 * durationMinute],
+ [minute, 30, 30 * durationMinute],
+ [ hour, 1, durationHour ],
+ [ hour, 3, 3 * durationHour ],
+ [ hour, 6, 6 * durationHour ],
+ [ hour, 12, 12 * durationHour ],
+ [ day, 1, durationDay ],
+ [ day, 2, 2 * durationDay ],
+ [ week, 1, durationWeek ],
+ [ month, 1, durationMonth ],
+ [ month, 3, 3 * durationMonth ],
+ [ year, 1, durationYear ]
+ ];
+
+ function tickFormat(date) {
+ return (second(date) < date ? formatMillisecond
+ : minute(date) < date ? formatSecond
+ : hour(date) < date ? formatMinute
+ : day(date) < date ? formatHour
+ : month(date) < date ? (week(date) < date ? formatDay : formatWeek)
+ : year(date) < date ? formatMonth
+ : formatYear)(date);
+ }
+
+ function tickInterval(interval, start, stop) {
+ if (interval == null) interval = 10;
+
+ // If a desired tick count is specified, pick a reasonable tick interval
+ // based on the extent of the domain and a rough estimate of tick size.
+ // Otherwise, assume interval is already a time interval and use it.
+ if (typeof interval === "number") {
+ var target = Math.abs(stop - start) / interval,
+ i = d3Array.bisector(function(i) { return i[2]; }).right(tickIntervals, target),
+ step;
+ if (i === tickIntervals.length) {
+ step = d3Array.tickStep(start / durationYear, stop / durationYear, interval);
+ interval = year;
+ } else if (i) {
+ i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
+ step = i[1];
+ interval = i[0];
+ } else {
+ step = Math.max(d3Array.tickStep(start, stop, interval), 1);
+ interval = millisecond;
+ }
+ return interval.every(step);
+ }
+
+ return interval;
+ }
+
+ scale.invert = function(y) {
+ return new Date(invert(y));
+ };
+
+ scale.domain = function(_) {
+ return arguments.length ? domain(Array.from(_, number$1)) : domain().map(date);
+ };
+
+ scale.ticks = function(interval) {
+ var d = domain(),
+ t0 = d[0],
+ t1 = d[d.length - 1],
+ r = t1 < t0,
+ t;
+ if (r) t = t0, t0 = t1, t1 = t;
+ t = tickInterval(interval, t0, t1);
+ t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
+ return r ? t.reverse() : t;
+ };
+
+ scale.tickFormat = function(count, specifier) {
+ return specifier == null ? tickFormat : format(specifier);
+ };
+
+ scale.nice = function(interval) {
+ var d = domain();
+ return (interval = tickInterval(interval, d[0], d[d.length - 1]))
+ ? domain(nice(d, interval))
+ : scale;
+ };
+
+ scale.copy = function() {
+ return copy(scale, calendar(year, month, week, day, hour, minute, second, millisecond, format));
+ };
+
+ return scale;
+}
+
+function time() {
+ return initRange.apply(calendar(d3Time.timeYear, d3Time.timeMonth, d3Time.timeWeek, d3Time.timeDay, d3Time.timeHour, d3Time.timeMinute, d3Time.timeSecond, d3Time.timeMillisecond, d3TimeFormat.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]), arguments);
+}
+
+function utcTime() {
+ return initRange.apply(calendar(d3Time.utcYear, d3Time.utcMonth, d3Time.utcWeek, d3Time.utcDay, d3Time.utcHour, d3Time.utcMinute, d3Time.utcSecond, d3Time.utcMillisecond, d3TimeFormat.utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]), arguments);
+}
+
+function transformer$1() {
+ var x0 = 0,
+ x1 = 1,
+ t0,
+ t1,
+ k10,
+ transform,
+ interpolator = identity,
+ clamp = false,
+ unknown;
+
+ function scale(x) {
+ return isNaN(x = +x) ? unknown : interpolator(k10 === 0 ? 0.5 : (x = (transform(x) - t0) * k10, clamp ? Math.max(0, Math.min(1, x)) : x));
+ }
+
+ scale.domain = function(_) {
+ return arguments.length ? ([x0, x1] = _, t0 = transform(x0 = +x0), t1 = transform(x1 = +x1), k10 = t0 === t1 ? 0 : 1 / (t1 - t0), scale) : [x0, x1];
+ };
+
+ scale.clamp = function(_) {
+ return arguments.length ? (clamp = !!_, scale) : clamp;
+ };
+
+ scale.interpolator = function(_) {
+ return arguments.length ? (interpolator = _, scale) : interpolator;
+ };
+
+ function range(interpolate) {
+ return function(_) {
+ var r0, r1;
+ return arguments.length ? ([r0, r1] = _, interpolator = interpolate(r0, r1), scale) : [interpolator(0), interpolator(1)];
+ };
+ }
+
+ scale.range = range(d3Interpolate.interpolate);
+
+ scale.rangeRound = range(d3Interpolate.interpolateRound);
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ return function(t) {
+ transform = t, t0 = t(x0), t1 = t(x1), k10 = t0 === t1 ? 0 : 1 / (t1 - t0);
+ return scale;
+ };
+}
+
+function copy$1(source, target) {
+ return target
+ .domain(source.domain())
+ .interpolator(source.interpolator())
+ .clamp(source.clamp())
+ .unknown(source.unknown());
+}
+
+function sequential() {
+ var scale = linearish(transformer$1()(identity));
+
+ scale.copy = function() {
+ return copy$1(scale, sequential());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function sequentialLog() {
+ var scale = loggish(transformer$1()).domain([1, 10]);
+
+ scale.copy = function() {
+ return copy$1(scale, sequentialLog()).base(scale.base());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function sequentialSymlog() {
+ var scale = symlogish(transformer$1());
+
+ scale.copy = function() {
+ return copy$1(scale, sequentialSymlog()).constant(scale.constant());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function sequentialPow() {
+ var scale = powish(transformer$1());
+
+ scale.copy = function() {
+ return copy$1(scale, sequentialPow()).exponent(scale.exponent());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function sequentialSqrt() {
+ return sequentialPow.apply(null, arguments).exponent(0.5);
+}
+
+function sequentialQuantile() {
+ var domain = [],
+ interpolator = identity;
+
+ function scale(x) {
+ if (!isNaN(x = +x)) return interpolator((d3Array.bisect(domain, x, 1) - 1) / (domain.length - 1));
+ }
+
+ scale.domain = function(_) {
+ if (!arguments.length) return domain.slice();
+ domain = [];
+ for (let d of _) if (d != null && !isNaN(d = +d)) domain.push(d);
+ domain.sort(d3Array.ascending);
+ return scale;
+ };
+
+ scale.interpolator = function(_) {
+ return arguments.length ? (interpolator = _, scale) : interpolator;
+ };
+
+ scale.range = function() {
+ return domain.map((d, i) => interpolator(i / (domain.length - 1)));
+ };
+
+ scale.quantiles = function(n) {
+ return Array.from({length: n + 1}, (_, i) => d3Array.quantile(domain, i / n));
+ };
+
+ scale.copy = function() {
+ return sequentialQuantile(interpolator).domain(domain);
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function transformer$2() {
+ var x0 = 0,
+ x1 = 0.5,
+ x2 = 1,
+ s = 1,
+ t0,
+ t1,
+ t2,
+ k10,
+ k21,
+ interpolator = identity,
+ transform,
+ clamp = false,
+ unknown;
+
+ function scale(x) {
+ return isNaN(x = +x) ? unknown : (x = 0.5 + ((x = +transform(x)) - t1) * (s * x < s * t1 ? k10 : k21), interpolator(clamp ? Math.max(0, Math.min(1, x)) : x));
+ }
+
+ scale.domain = function(_) {
+ return arguments.length ? ([x0, x1, x2] = _, t0 = transform(x0 = +x0), t1 = transform(x1 = +x1), t2 = transform(x2 = +x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), s = t1 < t0 ? -1 : 1, scale) : [x0, x1, x2];
+ };
+
+ scale.clamp = function(_) {
+ return arguments.length ? (clamp = !!_, scale) : clamp;
+ };
+
+ scale.interpolator = function(_) {
+ return arguments.length ? (interpolator = _, scale) : interpolator;
+ };
+
+ function range(interpolate) {
+ return function(_) {
+ var r0, r1, r2;
+ return arguments.length ? ([r0, r1, r2] = _, interpolator = d3Interpolate.piecewise(interpolate, [r0, r1, r2]), scale) : [interpolator(0), interpolator(0.5), interpolator(1)];
+ };
+ }
+
+ scale.range = range(d3Interpolate.interpolate);
+
+ scale.rangeRound = range(d3Interpolate.interpolateRound);
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ return function(t) {
+ transform = t, t0 = t(x0), t1 = t(x1), t2 = t(x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), s = t1 < t0 ? -1 : 1;
+ return scale;
+ };
+}
+
+function diverging() {
+ var scale = linearish(transformer$2()(identity));
+
+ scale.copy = function() {
+ return copy$1(scale, diverging());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function divergingLog() {
+ var scale = loggish(transformer$2()).domain([0.1, 1, 10]);
+
+ scale.copy = function() {
+ return copy$1(scale, divergingLog()).base(scale.base());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function divergingSymlog() {
+ var scale = symlogish(transformer$2());
+
+ scale.copy = function() {
+ return copy$1(scale, divergingSymlog()).constant(scale.constant());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function divergingPow() {
+ var scale = powish(transformer$2());
+
+ scale.copy = function() {
+ return copy$1(scale, divergingPow()).exponent(scale.exponent());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function divergingSqrt() {
+ return divergingPow.apply(null, arguments).exponent(0.5);
+}
+
+exports.scaleBand = band;
+exports.scaleDiverging = diverging;
+exports.scaleDivergingLog = divergingLog;
+exports.scaleDivergingPow = divergingPow;
+exports.scaleDivergingSqrt = divergingSqrt;
+exports.scaleDivergingSymlog = divergingSymlog;
+exports.scaleIdentity = identity$1;
+exports.scaleImplicit = implicit;
+exports.scaleLinear = linear;
+exports.scaleLog = log;
+exports.scaleOrdinal = ordinal;
+exports.scalePoint = point;
+exports.scalePow = pow;
+exports.scaleQuantile = quantile;
+exports.scaleQuantize = quantize;
+exports.scaleRadial = radial;
+exports.scaleSequential = sequential;
+exports.scaleSequentialLog = sequentialLog;
+exports.scaleSequentialPow = sequentialPow;
+exports.scaleSequentialQuantile = sequentialQuantile;
+exports.scaleSequentialSqrt = sequentialSqrt;
+exports.scaleSequentialSymlog = sequentialSymlog;
+exports.scaleSqrt = sqrt;
+exports.scaleSymlog = symlog;
+exports.scaleThreshold = threshold;
+exports.scaleTime = time;
+exports.scaleUtc = utcTime;
+exports.tickFormat = tickFormat;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-scale/dist/d3-scale.min.js b/node_modules/d3-scale/dist/d3-scale.min.js
new file mode 100644
index 00000000..81799bfa
--- /dev/null
+++ b/node_modules/d3-scale/dist/d3-scale.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-scale/ v3.2.3 Copyright 2020 Mike Bostock
+!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-array"),require("d3-interpolate"),require("d3-format"),require("d3-time"),require("d3-time-format")):"function"==typeof define&&define.amd?define(["exports","d3-array","d3-interpolate","d3-format","d3-time","d3-time-format"],t):t((n=n||self).d3=n.d3||{},n.d3,n.d3,n.d3,n.d3,n.d3)}(this,function(n,t,r,e,u,i){"use strict";function o(n,t){switch(arguments.length){case 0:break;case 1:this.range(n);break;default:this.range(t).domain(n)}return this}function a(n,t){switch(arguments.length){case 0:break;case 1:"function"==typeof n?this.interpolator(n):this.range(n);break;default:this.domain(n),"function"==typeof t?this.interpolator(t):this.range(t)}return this}const c=Symbol("implicit");function f(){var n=new Map,t=[],r=[],e=c;function u(u){var i=u+"",o=n.get(i);if(!o){if(e!==c)return e;n.set(i,o=t.push(u))}return r[(o-1)%r.length]}return u.domain=function(r){if(!arguments.length)return t.slice();t=[],n=new Map;for(const e of r){const r=e+"";n.has(r)||n.set(r,t.push(e))}return u},u.range=function(n){return arguments.length?(r=Array.from(n),u):r.slice()},u.unknown=function(n){return arguments.length?(e=n,u):e},u.copy=function(){return f(t,r).unknown(e)},o.apply(u,arguments),u}function l(){var n,r,e=f().unknown(void 0),u=e.domain,i=e.range,a=0,c=1,p=!1,s=0,h=0,g=.5;function m(){var e=u().length,o=ct&&(r=n,n=t,t=r),l=function(r){return Math.max(n,Math.min(t,r))}),u=e>2?d:m,i=o=null,y}function y(t){return isNaN(t=+t)?e:(i||(i=u(a.map(n),c,f)))(n(l(t)))}return y.invert=function(e){return l(t((o||(o=u(c,a.map(n),r.interpolateNumber)))(e)))},y.domain=function(n){return arguments.length?(a=Array.from(n,p),g()):a.slice()},y.range=function(n){return arguments.length?(c=Array.from(n),g()):c.slice()},y.rangeRound=function(n){return c=Array.from(n),f=r.interpolateRound,g()},y.clamp=function(n){return arguments.length?(l=!!n||h,g()):l!==h},y.interpolate=function(n){return arguments.length?(f=n,g()):f},y.unknown=function(n){return arguments.length?(e=n,y):e},function(r,e){return n=r,t=e,g()}}function M(){return v()(h,h)}function k(n,r,u,i){var o,a=t.tickStep(n,r,u);switch((i=e.formatSpecifier(null==i?",f":i)).type){case"s":var c=Math.max(Math.abs(n),Math.abs(r));return null!=i.precision||isNaN(o=e.precisionPrefix(a,c))||(i.precision=o),e.formatPrefix(i,c);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=e.precisionRound(a,Math.max(Math.abs(n),Math.abs(r))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=e.precisionFixed(a))||(i.precision=o-2*("%"===i.type))}return e.format(i)}function w(n){var r=n.domain;return n.ticks=function(n){var e=r();return t.ticks(e[0],e[e.length-1],null==n?10:n)},n.tickFormat=function(n,t){var e=r();return k(e[0],e[e.length-1],null==n?10:n,t)},n.nice=function(e){null==e&&(e=10);var u,i,o=r(),a=0,c=o.length-1,f=o[a],l=o[c],p=10;for(l
+
+```
+
+You can expose the custom data attributes by setting each element’s data as the built-in [dataset](http://www.w3.org/TR/html5/dom.html#dom-dataset) property:
+
+```js
+selection.datum(function() { return this.dataset; })
+```
+
+### Handling Events
+
+For interaction, selections allow listening for and dispatching of events.
+
+# selection.on(typenames[, listener[, options]]) · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/on.js)
+
+Adds or removes a *listener* to each selected element for the specified event *typenames*. The *typenames* is a string event type, such as `click`, `mouseover`, or `submit`; any [DOM event type](https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events) supported by your browser may be used. The type may be optionally followed by a period (`.`) and a name; the optional name allows multiple callbacks to be registered to receive events of the same type, such as `click.foo` and `click.bar`. To specify multiple typenames, separate typenames with spaces, such as `input change` or `click.foo click.bar`.
+
+When a specified event is dispatched on a selected element, the specified *listener* will be evaluated for the element, being passed the current event (*event*) and the current datum (*d*), with *this* as the current DOM element (*event*.currentTarget). Listeners always see the latest datum for their element. Note: while you can use [*event*.pageX](https://developer.mozilla.org/en/DOM/event.pageX) and [*event*.pageY](https://developer.mozilla.org/en/DOM/event.pageY) directly, it is often convenient to transform the event position to the local coordinate system of the element that received the event using [d3.pointer](#pointer).
+
+If an event listener was previously registered for the same *typename* on a selected element, the old listener is removed before the new listener is added. To remove a listener, pass null as the *listener*. To remove all listeners for a given name, pass null as the *listener* and `.foo` as the *typename*, where `foo` is the name; to remove all listeners with no name, specify `.` as the *typename*.
+
+An optional *options* object may specify characteristics about the event listener, such as whether it is capturing or passive; see [*element*.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener).
+
+If a *listener* is not specified, returns the currently-assigned listener for the specified event *typename* on the first (non-null) selected element, if any. If multiple typenames are specified, the first matching listener is returned.
+
+# selection.dispatch(type[, parameters]) · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/dispatch.js)
+
+Dispatches a [custom event](http://www.w3.org/TR/dom/#interface-customevent) of the specified *type* to each selected element, in order. An optional *parameters* map may be specified to set additional properties of the event. It may contain the following fields:
+
+* [`bubbles`](https://www.w3.org/TR/dom/#dom-event-bubbles) - if true, the event is dispatched to ancestors in reverse tree order.
+* [`cancelable`](https://www.w3.org/TR/dom/#dom-event-cancelable) - if true, *event*.preventDefault is allowed.
+* [`detail`](https://www.w3.org/TR/dom/#dom-customevent-detail) - any custom data associated with the event.
+
+If *parameters* is a function, it is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element (*nodes*[*i*]). It must return the parameters map for the current element.
+
+# d3.pointer(event[, target]) · [Source](https://github.com/d3/d3-selection/blob/master/src/pointer.js)
+
+Returns a two-element array of numbers [*x*, *y*] representing the coordinates of the specified *event* relative to the specified *target*. *event* can be a [UIEvent](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent) (MouseEvent or TouchEvent), a [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent), a custom event holding a UIEvent as *event*.sourceEvent, or a [touch](https://www.w3.org/TR/touch-events/#touch-interface).
+
+If *target* is not specified, it defaults to the source event’s currentTarget property, if available.
+
+If the *target* is an SVG element, the event’s coordinates are transformed using the [inverse](https://www.w3.org/TR/geometry-1/#dom-dommatrixreadonly-inverse) of the [screen coordinate transformation matrix](https://www.w3.org/TR/SVG/types.html#__svg__SVGGraphicsElement__getScreenCTM).
+
+If the *target* is an HTML element, the event’s coordinates are translated relative to the top-left corner of the *target*’s [bounding client rectangle](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). (As such, the coordinate system can only be translated relative to the client coordinates. See also [GeometryUtils](https://www.w3.org/TR/cssom-view-1/#the-geometryutils-interface).)
+
+Otherwise, [*event*.pageX, *event*.pageY] is returned.
+
+In the case of touch events, the coordinates of the first touch are returned. To handle multitouch interactions, see [pointers](#pointers) instead.
+
+# d3.pointers(event[, target]) · [Source](https://github.com/d3/d3-selection/blob/master/src/pointers.js)
+
+Returns an array [[*x0*, *y0*], [*x1*, *y1*]…] of coordinates of the specified *event*’s pointer locations relative to the specified *target*. For mouse, stylus or single touch events, [*x0*, *y0*] is equivalent to d3.pointer(event, target). In the case of multi-touch events, the returned array contains a pair of coordinates for each of the touches.
+
+If *target* is not specified, it defaults to the source event’s currentTarget property, if available.
+
+### Control Flow
+
+For advanced usage, selections provide methods for custom control flow.
+
+# selection.each(function) · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/each.js)
+
+Invokes the specified *function* for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element (*nodes*[*i*]). This method can be used to invoke arbitrary code for each selected element, and is useful for creating a context to access parent and child data simultaneously, such as:
+
+```js
+parent.each(function(p, j) {
+ d3.select(this)
+ .selectAll(".child")
+ .text(d => `child ${d.name} of ${p.name}`);
+});
+```
+
+See [Sized Donut Multiples](http://bl.ocks.org/mbostock/4c5fad723c87d2fd8273) for an example.
+
+# selection.call(function[, arguments…]) · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/call.js)
+
+Invokes the specified *function* exactly once, passing in this selection along with any optional *arguments*. Returns this selection. This is equivalent to invoking the function by hand but facilitates method chaining. For example, to set several styles in a reusable function:
+
+```js
+function name(selection, first, last) {
+ selection
+ .attr("first-name", first)
+ .attr("last-name", last);
+}
+```
+
+Now say:
+
+```js
+d3.selectAll("div").call(name, "John", "Snow");
+```
+
+This is roughly equivalent to:
+
+```js
+name(d3.selectAll("div"), "John", "Snow");
+```
+
+The only difference is that *selection*.call always returns the *selection* and not the return value of the called *function*, `name`.
+
+# selection.empty() · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/empty.js)
+
+Returns true if this selection contains no (non-null) elements.
+
+# selection.nodes() · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/nodes.js)
+
+Returns an array of all (non-null) elements in this selection. Equivalent to:
+
+```js
+const elements = Array.from(selection);
+````
+
+See also [*selection*[Symbol.iterator]](#selection_iterator).
+
+# selection.node() · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/node.js)
+
+Returns the first (non-null) element in this selection. If the selection is empty, returns null.
+
+# selection.size() · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/size.js)
+
+Returns the total number of (non-null) elements in this selection.
+
+# selection[Symbol.iterator]() · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/iterator.js)
+
+Returns an iterator over the selected (non-null) elements. For example, to iterate over the selected elements:
+
+```js
+for (const element of selection) {
+ console.log(element);
+}
+```
+
+To flatten the selection to an array:
+
+```js
+const elements = [...selection];
+````
+
+### Local Variables
+
+D3 locals allow you to define local state independent of data. For instance, when rendering [small multiples](http://bl.ocks.org/mbostock/e1192fe405703d8321a5187350910e08) of time-series data, you might want the same *x*-scale for all charts but distinct *y*-scales to compare the relative performance of each metric. D3 locals are scoped by DOM elements: on set, the value is stored on the given element; on get, the value is retrieved from given element or the nearest ancestor that defines it.
+
+# d3.local() · [Source](https://github.com/d3/d3-selection/blob/master/src/local.js)
+
+Declares a new local variable. For example:
+
+```js
+const foo = d3.local();
+```
+
+Like `var`, each local is a distinct symbolic reference; unlike `var`, the value of each local is also scoped by the DOM.
+
+# local.set(node, value) · [Source](https://github.com/d3/d3-selection/blob/master/src/local.js)
+
+Sets the value of this local on the specified *node* to the *value*, and returns the specified *value*. This is often performed using [*selection*.each](#selection_each):
+
+```js
+selection.each(function(d) { foo.set(this, d.value); });
+```
+
+If you are just setting a single variable, consider using [*selection*.property](#selection_property):
+
+```js
+selection.property(foo, d => d.value);
+```
+
+# local.get(node) · [Source](https://github.com/d3/d3-selection/blob/master/src/local.js)
+
+Returns the value of this local on the specified *node*. If the *node* does not define this local, returns the value from the nearest ancestor that defines it. Returns undefined if no ancestor defines this local.
+
+# local.remove(node) · [Source](https://github.com/d3/d3-selection/blob/master/src/local.js)
+
+Deletes this local’s value from the specified *node*. Returns true if the *node* defined this local prior to removal, and false otherwise. If ancestors also define this local, those definitions are unaffected, and thus [*local*.get](#local_get) will still return the inherited value.
+
+# local.toString() · [Source](https://github.com/d3/d3-selection/blob/master/src/local.js)
+
+Returns the automatically-generated identifier for this local. This is the name of the property that is used to store the local’s value on elements, and thus you can also set or get the local’s value using *element*[*local*] or by using [*selection*.property](#selection_property).
+
+### Namespaces
+
+XML namespaces are fun! Right? Fortunately you can mostly ignore them.
+
+# d3.namespace(name) · [Source](https://github.com/d3/d3-selection/blob/master/src/namespace.js)
+
+Qualifies the specified *name*, which may or may not have a namespace prefix. If the name contains a colon (`:`), the substring before the colon is interpreted as the namespace prefix, which must be registered in [d3.namespaces](#namespaces). Returns an object `space` and `local` attributes describing the full namespace URL and the local name. For example:
+
+```js
+d3.namespace("svg:text"); // {space: "http://www.w3.org/2000/svg", local: "text"}
+```
+
+If the name does not contain a colon, this function merely returns the input name.
+
+# d3.namespaces · [Source](https://github.com/d3/d3-selection/blob/master/src/namespaces.js)
+
+The map of registered namespace prefixes. The initial value is:
+
+```js
+{
+ 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/"
+}
+```
+
+Additional prefixes may be assigned as needed to create elements or attributes in other namespaces.
diff --git a/node_modules/d3-selection/dist/d3-selection.js b/node_modules/d3-selection/dist/d3-selection.js
new file mode 100644
index 00000000..582cfaba
--- /dev/null
+++ b/node_modules/d3-selection/dist/d3-selection.js
@@ -0,0 +1,999 @@
+// https://d3js.org/d3-selection/ v2.0.0 Copyright 2020 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+typeof define === 'function' && define.amd ? define(['exports'], factory) :
+(global = global || self, factory(global.d3 = global.d3 || {}));
+}(this, function (exports) { 'use strict';
+
+var xhtml = "http://www.w3.org/1999/xhtml";
+
+var namespaces = {
+ svg: "http://www.w3.org/2000/svg",
+ xhtml: xhtml,
+ xlink: "http://www.w3.org/1999/xlink",
+ xml: "http://www.w3.org/XML/1998/namespace",
+ xmlns: "http://www.w3.org/2000/xmlns/"
+};
+
+function namespace(name) {
+ var prefix = name += "", i = prefix.indexOf(":");
+ if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
+ return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name; // eslint-disable-line no-prototype-builtins
+}
+
+function creatorInherit(name) {
+ return function() {
+ var document = this.ownerDocument,
+ uri = this.namespaceURI;
+ return uri === xhtml && document.documentElement.namespaceURI === xhtml
+ ? document.createElement(name)
+ : document.createElementNS(uri, name);
+ };
+}
+
+function creatorFixed(fullname) {
+ return function() {
+ return this.ownerDocument.createElementNS(fullname.space, fullname.local);
+ };
+}
+
+function creator(name) {
+ var fullname = namespace(name);
+ return (fullname.local
+ ? creatorFixed
+ : creatorInherit)(fullname);
+}
+
+function none() {}
+
+function selector(selector) {
+ return selector == null ? none : function() {
+ return this.querySelector(selector);
+ };
+}
+
+function selection_select(select) {
+ if (typeof select !== "function") select = selector(select);
+
+ for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
+ for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
+ if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
+ if ("__data__" in node) subnode.__data__ = node.__data__;
+ subgroup[i] = subnode;
+ }
+ }
+ }
+
+ return new Selection(subgroups, this._parents);
+}
+
+function array(x) {
+ return typeof x === "object" && "length" in x
+ ? x // Array, TypedArray, NodeList, array-like
+ : Array.from(x); // Map, Set, iterable, string, or anything else
+}
+
+function empty() {
+ return [];
+}
+
+function selectorAll(selector) {
+ return selector == null ? empty : function() {
+ return this.querySelectorAll(selector);
+ };
+}
+
+function arrayAll(select) {
+ return function() {
+ var group = select.apply(this, arguments);
+ return group == null ? [] : array(group);
+ };
+}
+
+function selection_selectAll(select) {
+ if (typeof select === "function") select = arrayAll(select);
+ else select = selectorAll(select);
+
+ for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
+ for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
+ if (node = group[i]) {
+ subgroups.push(select.call(node, node.__data__, i, group));
+ parents.push(node);
+ }
+ }
+ }
+
+ return new Selection(subgroups, parents);
+}
+
+function matcher(selector) {
+ return function() {
+ return this.matches(selector);
+ };
+}
+
+function childMatcher(selector) {
+ return function(node) {
+ return node.matches(selector);
+ };
+}
+
+var find = Array.prototype.find;
+
+function childFind(match) {
+ return function() {
+ return find.call(this.children, match);
+ };
+}
+
+function childFirst() {
+ return this.firstElementChild;
+}
+
+function selection_selectChild(match) {
+ return this.select(match == null ? childFirst
+ : childFind(typeof match === "function" ? match : childMatcher(match)));
+}
+
+var filter = Array.prototype.filter;
+
+function children() {
+ return this.children;
+}
+
+function childrenFilter(match) {
+ return function() {
+ return filter.call(this.children, match);
+ };
+}
+
+function selection_selectChildren(match) {
+ return this.selectAll(match == null ? children
+ : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
+}
+
+function selection_filter(match) {
+ if (typeof match !== "function") match = matcher(match);
+
+ for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
+ for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
+ if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
+ subgroup.push(node);
+ }
+ }
+ }
+
+ return new Selection(subgroups, this._parents);
+}
+
+function sparse(update) {
+ return new Array(update.length);
+}
+
+function selection_enter() {
+ return new Selection(this._enter || this._groups.map(sparse), this._parents);
+}
+
+function EnterNode(parent, datum) {
+ this.ownerDocument = parent.ownerDocument;
+ this.namespaceURI = parent.namespaceURI;
+ this._next = null;
+ this._parent = parent;
+ this.__data__ = datum;
+}
+
+EnterNode.prototype = {
+ constructor: EnterNode,
+ appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
+ insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
+ querySelector: function(selector) { return this._parent.querySelector(selector); },
+ querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
+};
+
+function constant(x) {
+ return function() {
+ return x;
+ };
+}
+
+function bindIndex(parent, group, enter, update, exit, data) {
+ var i = 0,
+ node,
+ groupLength = group.length,
+ dataLength = data.length;
+
+ // Put any non-null nodes that fit into update.
+ // Put any null nodes into enter.
+ // Put any remaining data into enter.
+ for (; i < dataLength; ++i) {
+ if (node = group[i]) {
+ node.__data__ = data[i];
+ update[i] = node;
+ } else {
+ enter[i] = new EnterNode(parent, data[i]);
+ }
+ }
+
+ // Put any non-null nodes that don’t fit into exit.
+ for (; i < groupLength; ++i) {
+ if (node = group[i]) {
+ exit[i] = node;
+ }
+ }
+}
+
+function bindKey(parent, group, enter, update, exit, data, key) {
+ var i,
+ node,
+ nodeByKeyValue = new Map,
+ groupLength = group.length,
+ dataLength = data.length,
+ keyValues = new Array(groupLength),
+ keyValue;
+
+ // Compute the key for each node.
+ // If multiple nodes have the same key, the duplicates are added to exit.
+ for (i = 0; i < groupLength; ++i) {
+ if (node = group[i]) {
+ keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
+ if (nodeByKeyValue.has(keyValue)) {
+ exit[i] = node;
+ } else {
+ nodeByKeyValue.set(keyValue, node);
+ }
+ }
+ }
+
+ // Compute the key for each datum.
+ // If there a node associated with this key, join and add it to update.
+ // If there is not (or the key is a duplicate), add it to enter.
+ for (i = 0; i < dataLength; ++i) {
+ keyValue = key.call(parent, data[i], i, data) + "";
+ if (node = nodeByKeyValue.get(keyValue)) {
+ update[i] = node;
+ node.__data__ = data[i];
+ nodeByKeyValue.delete(keyValue);
+ } else {
+ enter[i] = new EnterNode(parent, data[i]);
+ }
+ }
+
+ // Add any remaining nodes that were not bound to data to exit.
+ for (i = 0; i < groupLength; ++i) {
+ if ((node = group[i]) && (nodeByKeyValue.get(keyValues[i]) === node)) {
+ exit[i] = node;
+ }
+ }
+}
+
+function datum(node) {
+ return node.__data__;
+}
+
+function selection_data(value, key) {
+ if (!arguments.length) return Array.from(this, datum);
+
+ var bind = key ? bindKey : bindIndex,
+ parents = this._parents,
+ groups = this._groups;
+
+ if (typeof value !== "function") value = constant(value);
+
+ for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
+ var parent = parents[j],
+ group = groups[j],
+ groupLength = group.length,
+ data = array(value.call(parent, parent && parent.__data__, j, parents)),
+ dataLength = data.length,
+ enterGroup = enter[j] = new Array(dataLength),
+ updateGroup = update[j] = new Array(dataLength),
+ exitGroup = exit[j] = new Array(groupLength);
+
+ bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
+
+ // Now connect the enter nodes to their following update node, such that
+ // appendChild can insert the materialized enter node before this node,
+ // rather than at the end of the parent node.
+ for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
+ if (previous = enterGroup[i0]) {
+ if (i0 >= i1) i1 = i0 + 1;
+ while (!(next = updateGroup[i1]) && ++i1 < dataLength);
+ previous._next = next || null;
+ }
+ }
+ }
+
+ update = new Selection(update, parents);
+ update._enter = enter;
+ update._exit = exit;
+ return update;
+}
+
+function selection_exit() {
+ return new Selection(this._exit || this._groups.map(sparse), this._parents);
+}
+
+function selection_join(onenter, onupdate, onexit) {
+ var enter = this.enter(), update = this, exit = this.exit();
+ enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + "");
+ if (onupdate != null) update = onupdate(update);
+ if (onexit == null) exit.remove(); else onexit(exit);
+ return enter && update ? enter.merge(update).order() : update;
+}
+
+function selection_merge(selection) {
+ if (!(selection instanceof Selection)) throw new Error("invalid merge");
+
+ for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
+ for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
+ if (node = group0[i] || group1[i]) {
+ merge[i] = node;
+ }
+ }
+ }
+
+ for (; j < m0; ++j) {
+ merges[j] = groups0[j];
+ }
+
+ return new Selection(merges, this._parents);
+}
+
+function selection_order() {
+
+ for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
+ for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
+ if (node = group[i]) {
+ if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
+ next = node;
+ }
+ }
+ }
+
+ return this;
+}
+
+function selection_sort(compare) {
+ if (!compare) compare = ascending;
+
+ function compareNode(a, b) {
+ return a && b ? compare(a.__data__, b.__data__) : !a - !b;
+ }
+
+ for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
+ for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
+ if (node = group[i]) {
+ sortgroup[i] = node;
+ }
+ }
+ sortgroup.sort(compareNode);
+ }
+
+ return new Selection(sortgroups, this._parents).order();
+}
+
+function ascending(a, b) {
+ return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+}
+
+function selection_call() {
+ var callback = arguments[0];
+ arguments[0] = this;
+ callback.apply(null, arguments);
+ return this;
+}
+
+function selection_nodes() {
+ return Array.from(this);
+}
+
+function selection_node() {
+
+ for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
+ for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
+ var node = group[i];
+ if (node) return node;
+ }
+ }
+
+ return null;
+}
+
+function selection_size() {
+ let size = 0;
+ for (const node of this) ++size; // eslint-disable-line no-unused-vars
+ return size;
+}
+
+function selection_empty() {
+ return !this.node();
+}
+
+function selection_each(callback) {
+
+ for (var groups = this._groups, 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.call(node, node.__data__, i, group);
+ }
+ }
+
+ return this;
+}
+
+function attrRemove(name) {
+ return function() {
+ this.removeAttribute(name);
+ };
+}
+
+function attrRemoveNS(fullname) {
+ return function() {
+ this.removeAttributeNS(fullname.space, fullname.local);
+ };
+}
+
+function attrConstant(name, value) {
+ return function() {
+ this.setAttribute(name, value);
+ };
+}
+
+function attrConstantNS(fullname, value) {
+ return function() {
+ this.setAttributeNS(fullname.space, fullname.local, value);
+ };
+}
+
+function attrFunction(name, value) {
+ return function() {
+ var v = value.apply(this, arguments);
+ if (v == null) this.removeAttribute(name);
+ else this.setAttribute(name, v);
+ };
+}
+
+function attrFunctionNS(fullname, value) {
+ return function() {
+ var v = value.apply(this, arguments);
+ if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
+ else this.setAttributeNS(fullname.space, fullname.local, v);
+ };
+}
+
+function selection_attr(name, value) {
+ var fullname = namespace(name);
+
+ if (arguments.length < 2) {
+ var node = this.node();
+ return fullname.local
+ ? node.getAttributeNS(fullname.space, fullname.local)
+ : node.getAttribute(fullname);
+ }
+
+ return this.each((value == null
+ ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
+ ? (fullname.local ? attrFunctionNS : attrFunction)
+ : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
+}
+
+function defaultView(node) {
+ return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
+ || (node.document && node) // node is a Window
+ || node.defaultView; // node is a Document
+}
+
+function styleRemove(name) {
+ return function() {
+ this.style.removeProperty(name);
+ };
+}
+
+function styleConstant(name, value, priority) {
+ return function() {
+ this.style.setProperty(name, value, priority);
+ };
+}
+
+function styleFunction(name, value, priority) {
+ return function() {
+ var v = value.apply(this, arguments);
+ if (v == null) this.style.removeProperty(name);
+ else this.style.setProperty(name, v, priority);
+ };
+}
+
+function selection_style(name, value, priority) {
+ return arguments.length > 1
+ ? this.each((value == null
+ ? styleRemove : typeof value === "function"
+ ? styleFunction
+ : styleConstant)(name, value, priority == null ? "" : priority))
+ : styleValue(this.node(), name);
+}
+
+function styleValue(node, name) {
+ return node.style.getPropertyValue(name)
+ || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
+}
+
+function propertyRemove(name) {
+ return function() {
+ delete this[name];
+ };
+}
+
+function propertyConstant(name, value) {
+ return function() {
+ this[name] = value;
+ };
+}
+
+function propertyFunction(name, value) {
+ return function() {
+ var v = value.apply(this, arguments);
+ if (v == null) delete this[name];
+ else this[name] = v;
+ };
+}
+
+function selection_property(name, value) {
+ return arguments.length > 1
+ ? this.each((value == null
+ ? propertyRemove : typeof value === "function"
+ ? propertyFunction
+ : propertyConstant)(name, value))
+ : this.node()[name];
+}
+
+function classArray(string) {
+ return string.trim().split(/^|\s+/);
+}
+
+function classList(node) {
+ return node.classList || new ClassList(node);
+}
+
+function ClassList(node) {
+ this._node = node;
+ this._names = classArray(node.getAttribute("class") || "");
+}
+
+ClassList.prototype = {
+ add: function(name) {
+ var i = this._names.indexOf(name);
+ if (i < 0) {
+ this._names.push(name);
+ this._node.setAttribute("class", this._names.join(" "));
+ }
+ },
+ remove: function(name) {
+ var i = this._names.indexOf(name);
+ if (i >= 0) {
+ this._names.splice(i, 1);
+ this._node.setAttribute("class", this._names.join(" "));
+ }
+ },
+ contains: function(name) {
+ return this._names.indexOf(name) >= 0;
+ }
+};
+
+function classedAdd(node, names) {
+ var list = classList(node), i = -1, n = names.length;
+ while (++i < n) list.add(names[i]);
+}
+
+function classedRemove(node, names) {
+ var list = classList(node), i = -1, n = names.length;
+ while (++i < n) list.remove(names[i]);
+}
+
+function classedTrue(names) {
+ return function() {
+ classedAdd(this, names);
+ };
+}
+
+function classedFalse(names) {
+ return function() {
+ classedRemove(this, names);
+ };
+}
+
+function classedFunction(names, value) {
+ return function() {
+ (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
+ };
+}
+
+function selection_classed(name, value) {
+ var names = classArray(name + "");
+
+ if (arguments.length < 2) {
+ var list = classList(this.node()), i = -1, n = names.length;
+ while (++i < n) if (!list.contains(names[i])) return false;
+ return true;
+ }
+
+ return this.each((typeof value === "function"
+ ? classedFunction : value
+ ? classedTrue
+ : classedFalse)(names, value));
+}
+
+function textRemove() {
+ this.textContent = "";
+}
+
+function textConstant(value) {
+ return function() {
+ this.textContent = value;
+ };
+}
+
+function textFunction(value) {
+ return function() {
+ var v = value.apply(this, arguments);
+ this.textContent = v == null ? "" : v;
+ };
+}
+
+function selection_text(value) {
+ return arguments.length
+ ? this.each(value == null
+ ? textRemove : (typeof value === "function"
+ ? textFunction
+ : textConstant)(value))
+ : this.node().textContent;
+}
+
+function htmlRemove() {
+ this.innerHTML = "";
+}
+
+function htmlConstant(value) {
+ return function() {
+ this.innerHTML = value;
+ };
+}
+
+function htmlFunction(value) {
+ return function() {
+ var v = value.apply(this, arguments);
+ this.innerHTML = v == null ? "" : v;
+ };
+}
+
+function selection_html(value) {
+ return arguments.length
+ ? this.each(value == null
+ ? htmlRemove : (typeof value === "function"
+ ? htmlFunction
+ : htmlConstant)(value))
+ : this.node().innerHTML;
+}
+
+function raise() {
+ if (this.nextSibling) this.parentNode.appendChild(this);
+}
+
+function selection_raise() {
+ return this.each(raise);
+}
+
+function lower() {
+ if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
+}
+
+function selection_lower() {
+ return this.each(lower);
+}
+
+function selection_append(name) {
+ var create = typeof name === "function" ? name : creator(name);
+ return this.select(function() {
+ return this.appendChild(create.apply(this, arguments));
+ });
+}
+
+function constantNull() {
+ return null;
+}
+
+function selection_insert(name, before) {
+ var create = typeof name === "function" ? name : creator(name),
+ select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
+ return this.select(function() {
+ return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
+ });
+}
+
+function remove() {
+ var parent = this.parentNode;
+ if (parent) parent.removeChild(this);
+}
+
+function selection_remove() {
+ return this.each(remove);
+}
+
+function selection_cloneShallow() {
+ var clone = this.cloneNode(false), parent = this.parentNode;
+ return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
+}
+
+function selection_cloneDeep() {
+ var clone = this.cloneNode(true), parent = this.parentNode;
+ return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
+}
+
+function selection_clone(deep) {
+ return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
+}
+
+function selection_datum(value) {
+ return arguments.length
+ ? this.property("__data__", value)
+ : this.node().__data__;
+}
+
+function contextListener(listener) {
+ return function(event) {
+ listener.call(this, event, this.__data__);
+ };
+}
+
+function parseTypenames(typenames) {
+ return typenames.trim().split(/^|\s+/).map(function(t) {
+ var name = "", i = t.indexOf(".");
+ if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
+ return {type: t, name: name};
+ });
+}
+
+function onRemove(typename) {
+ return function() {
+ var on = this.__on;
+ if (!on) return;
+ for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
+ if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
+ this.removeEventListener(o.type, o.listener, o.options);
+ } else {
+ on[++i] = o;
+ }
+ }
+ if (++i) on.length = i;
+ else delete this.__on;
+ };
+}
+
+function onAdd(typename, value, options) {
+ return function() {
+ var on = this.__on, o, listener = contextListener(value);
+ if (on) for (var j = 0, m = on.length; j < m; ++j) {
+ if ((o = on[j]).type === typename.type && o.name === typename.name) {
+ this.removeEventListener(o.type, o.listener, o.options);
+ this.addEventListener(o.type, o.listener = listener, o.options = options);
+ o.value = value;
+ return;
+ }
+ }
+ this.addEventListener(typename.type, listener, options);
+ o = {type: typename.type, name: typename.name, value: value, listener: listener, options: options};
+ if (!on) this.__on = [o];
+ else on.push(o);
+ };
+}
+
+function selection_on(typename, value, options) {
+ var typenames = parseTypenames(typename + ""), i, n = typenames.length, t;
+
+ if (arguments.length < 2) {
+ var on = this.node().__on;
+ if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
+ for (i = 0, o = on[j]; i < n; ++i) {
+ if ((t = typenames[i]).type === o.type && t.name === o.name) {
+ return o.value;
+ }
+ }
+ }
+ return;
+ }
+
+ on = value ? onAdd : onRemove;
+ for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options));
+ return this;
+}
+
+function dispatchEvent(node, type, params) {
+ var window = defaultView(node),
+ event = window.CustomEvent;
+
+ if (typeof event === "function") {
+ event = new event(type, params);
+ } else {
+ event = window.document.createEvent("Event");
+ if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
+ else event.initEvent(type, false, false);
+ }
+
+ node.dispatchEvent(event);
+}
+
+function dispatchConstant(type, params) {
+ return function() {
+ return dispatchEvent(this, type, params);
+ };
+}
+
+function dispatchFunction(type, params) {
+ return function() {
+ return dispatchEvent(this, type, params.apply(this, arguments));
+ };
+}
+
+function selection_dispatch(type, params) {
+ return this.each((typeof params === "function"
+ ? dispatchFunction
+ : dispatchConstant)(type, params));
+}
+
+function* selection_iterator() {
+ for (var groups = this._groups, 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]) yield node;
+ }
+ }
+}
+
+var root = [null];
+
+function Selection(groups, parents) {
+ this._groups = groups;
+ this._parents = parents;
+}
+
+function selection() {
+ return new Selection([[document.documentElement]], root);
+}
+
+function selection_selection() {
+ return this;
+}
+
+Selection.prototype = selection.prototype = {
+ constructor: Selection,
+ select: selection_select,
+ selectAll: selection_selectAll,
+ selectChild: selection_selectChild,
+ selectChildren: selection_selectChildren,
+ filter: selection_filter,
+ data: selection_data,
+ enter: selection_enter,
+ exit: selection_exit,
+ join: selection_join,
+ merge: selection_merge,
+ selection: selection_selection,
+ order: selection_order,
+ sort: selection_sort,
+ call: selection_call,
+ nodes: selection_nodes,
+ node: selection_node,
+ size: selection_size,
+ empty: selection_empty,
+ each: selection_each,
+ attr: selection_attr,
+ style: selection_style,
+ property: selection_property,
+ classed: selection_classed,
+ text: selection_text,
+ html: selection_html,
+ raise: selection_raise,
+ lower: selection_lower,
+ append: selection_append,
+ insert: selection_insert,
+ remove: selection_remove,
+ clone: selection_clone,
+ datum: selection_datum,
+ on: selection_on,
+ dispatch: selection_dispatch,
+ [Symbol.iterator]: selection_iterator
+};
+
+function select(selector) {
+ return typeof selector === "string"
+ ? new Selection([[document.querySelector(selector)]], [document.documentElement])
+ : new Selection([[selector]], root);
+}
+
+function create(name) {
+ return select(creator(name).call(document.documentElement));
+}
+
+var nextId = 0;
+
+function local() {
+ return new Local;
+}
+
+function Local() {
+ this._ = "@" + (++nextId).toString(36);
+}
+
+Local.prototype = local.prototype = {
+ constructor: Local,
+ get: function(node) {
+ var id = this._;
+ while (!(id in node)) if (!(node = node.parentNode)) return;
+ return node[id];
+ },
+ set: function(node, value) {
+ return node[this._] = value;
+ },
+ remove: function(node) {
+ return this._ in node && delete node[this._];
+ },
+ toString: function() {
+ return this._;
+ }
+};
+
+function sourceEvent(event) {
+ let sourceEvent;
+ while (sourceEvent = event.sourceEvent) event = sourceEvent;
+ return event;
+}
+
+function pointer(event, node) {
+ event = sourceEvent(event);
+ if (node === undefined) node = event.currentTarget;
+ if (node) {
+ var svg = node.ownerSVGElement || node;
+ if (svg.createSVGPoint) {
+ var point = svg.createSVGPoint();
+ point.x = event.clientX, point.y = event.clientY;
+ point = point.matrixTransform(node.getScreenCTM().inverse());
+ return [point.x, point.y];
+ }
+ if (node.getBoundingClientRect) {
+ var rect = node.getBoundingClientRect();
+ return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
+ }
+ }
+ return [event.pageX, event.pageY];
+}
+
+function pointers(events, node) {
+ if (events.target) { // i.e., instanceof Event, not TouchList or iterable
+ events = sourceEvent(events);
+ if (node === undefined) node = events.currentTarget;
+ events = events.touches || [events];
+ }
+ return Array.from(events, event => pointer(event, node));
+}
+
+function selectAll(selector) {
+ return typeof selector === "string"
+ ? new Selection([document.querySelectorAll(selector)], [document.documentElement])
+ : new Selection([selector == null ? [] : array(selector)], root);
+}
+
+exports.create = create;
+exports.creator = creator;
+exports.local = local;
+exports.matcher = matcher;
+exports.namespace = namespace;
+exports.namespaces = namespaces;
+exports.pointer = pointer;
+exports.pointers = pointers;
+exports.select = select;
+exports.selectAll = selectAll;
+exports.selection = selection;
+exports.selector = selector;
+exports.selectorAll = selectorAll;
+exports.style = styleValue;
+exports.window = defaultView;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-selection/dist/d3-selection.min.js b/node_modules/d3-selection/dist/d3-selection.min.js
new file mode 100644
index 00000000..46a30ba4
--- /dev/null
+++ b/node_modules/d3-selection/dist/d3-selection.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-selection/ v2.0.0 Copyright 2020 Mike Bostock
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t=t||self).d3=t.d3||{})}(this,function(t){"use strict";var n="http://www.w3.org/1999/xhtml",e={svg:"http://www.w3.org/2000/svg",xhtml:n,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function r(t){var n=t+="",r=n.indexOf(":");return r>=0&&"xmlns"!==(n=t.slice(0,r))&&(t=t.slice(r+1)),e.hasOwnProperty(n)?{space:e[n],local:t}:t}function i(t){var e=r(t);return(e.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var e=this.ownerDocument,r=this.namespaceURI;return r===n&&e.documentElement.namespaceURI===n?e.createElement(t):e.createElementNS(r,t)}})(e)}function o(){}function u(t){return null==t?o:function(){return this.querySelector(t)}}function c(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function s(){return[]}function l(t){return null==t?s:function(){return this.querySelectorAll(t)}}function a(t){return function(){return this.matches(t)}}function f(t){return function(n){return n.matches(t)}}var h=Array.prototype.find;function p(){return this.firstElementChild}var _=Array.prototype.filter;function d(){return this.children}function y(t){return new Array(t.length)}function v(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function m(t,n,e,r,i,o){for(var u,c=0,s=n.length,l=o.length;c
](http://bl.ocks.org/mbostock/8878e7fd82034f1d63cf)[
](http://bl.ocks.org/mbostock/2394b23da1994fc202e1)
+
+The arc generator produces a [circular](https://en.wikipedia.org/wiki/Circular_sector) or [annular](https://en.wikipedia.org/wiki/Annulus_\(mathematics\)) sector, as in a pie or donut chart. If the difference between the [start](#arc_startAngle) and [end](#arc_endAngle) angles (the *angular span*) is greater than [τ](https://en.wikipedia.org/wiki/Turn_\(geometry\)#Tau_proposal), the arc generator will produce a complete circle or annulus. If it is less than τ, arcs may have [rounded corners](#arc_cornerRadius) and [angular padding](#arc_padAngle). Arcs are always centered at ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to move the arc to a different position.
+
+See also the [pie generator](#pies), which computes the necessary angles to represent an array of data as a pie or donut chart; these angles can then be passed to an arc generator.
+
+# d3.arc() · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+Constructs a new arc generator with the default settings.
+
+# arc(arguments…) · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+Generates an arc for the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the arc generator’s accessor functions along with the `this` object. For example, with the default settings, an object with radii and angles is expected:
+
+```js
+const arc = d3.arc();
+
+arc({
+ innerRadius: 0,
+ outerRadius: 100,
+ startAngle: 0,
+ endAngle: Math.PI / 2
+}); // "M0,-100A100,100,0,0,1,100,0L0,0Z"
+```
+
+If the radii and angles are instead defined as constants, you can generate an arc without any arguments:
+
+```js
+const arc = d3.arc()
+ .innerRadius(0)
+ .outerRadius(100)
+ .startAngle(0)
+ .endAngle(Math.PI / 2);
+
+arc(); // "M0,-100A100,100,0,0,1,100,0L0,0Z"
+```
+
+If the arc generator has a [context](#arc_context), then the arc is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.
+
+# arc.centroid(arguments…) · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+Computes the midpoint [*x*, *y*] of the center line of the arc that would be [generated](#_arc) by the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the arc generator’s accessor functions along with the `this` object. To be consistent with the generated arc, the accessors must be deterministic, *i.e.*, return the same value given the same arguments. The midpoint is defined as ([startAngle](#arc_startAngle) + [endAngle](#arc_endAngle)) / 2 and ([innerRadius](#arc_innerRadius) + [outerRadius](#arc_outerRadius)) / 2. For example:
+
+[
](http://bl.ocks.org/mbostock/9b5a2fd1ce1a146f27e4)[
](http://bl.ocks.org/mbostock/c274877f647361f3df7d)
+
+Note that this is **not the geometric center** of the arc, which may be outside the arc; this method is merely a convenience for positioning labels.
+
+# arc.innerRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+If *radius* is specified, sets the inner radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current inner radius accessor, which defaults to:
+
+```js
+function innerRadius(d) {
+ return d.innerRadius;
+}
+```
+
+Specifying the inner radius as a function is useful for constructing a stacked polar bar chart, often in conjunction with a [sqrt scale](https://github.com/d3/d3-scale#sqrt). More commonly, a constant inner radius is used for a donut or pie chart. If the outer radius is smaller than the inner radius, the inner and outer radii are swapped. A negative value is treated as zero.
+
+# arc.outerRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+If *radius* is specified, sets the outer radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current outer radius accessor, which defaults to:
+
+```js
+function outerRadius(d) {
+ return d.outerRadius;
+}
+```
+
+Specifying the outer radius as a function is useful for constructing a coxcomb or polar bar chart, often in conjunction with a [sqrt scale](https://github.com/d3/d3-scale#sqrt). More commonly, a constant outer radius is used for a pie or donut chart. If the outer radius is smaller than the inner radius, the inner and outer radii are swapped. A negative value is treated as zero.
+
+# arc.cornerRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+If *radius* is specified, sets the corner radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current corner radius accessor, which defaults to:
+
+```js
+function cornerRadius() {
+ return 0;
+}
+```
+
+If the corner radius is greater than zero, the corners of the arc are rounded using circles of the given radius. For a circular sector, the two outer corners are rounded; for an annular sector, all four corners are rounded. The corner circles are shown in this diagram:
+
+[
](http://bl.ocks.org/mbostock/e5e3680f3079cf5c3437)[
](http://bl.ocks.org/mbostock/f41f50e06a6c04828b6e)
+
+The corner radius may not be larger than ([outerRadius](#arc_outerRadius) - [innerRadius](#arc_innerRadius)) / 2. In addition, for arcs whose angular span is less than π, the corner radius may be reduced as two adjacent rounded corners intersect. This is occurs more often with the inner corners. See the [arc corners animation](http://bl.ocks.org/mbostock/b7671cb38efdfa5da3af) for illustration.
+
+# arc.startAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+If *angle* is specified, sets the start angle to the specified function or number and returns this arc generator. If *angle* is not specified, returns the current start angle accessor, which defaults to:
+
+```js
+function startAngle(d) {
+ return d.startAngle;
+}
+```
+
+The *angle* is specified in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise. If |endAngle - startAngle| ≥ τ, a complete circle or annulus is generated rather than a sector.
+
+# arc.endAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+If *angle* is specified, sets the end angle to the specified function or number and returns this arc generator. If *angle* is not specified, returns the current end angle accessor, which defaults to:
+
+```js
+function endAngle(d) {
+ return d.endAngle;
+}
+```
+
+The *angle* is specified in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise. If |endAngle - startAngle| ≥ τ, a complete circle or annulus is generated rather than a sector.
+
+# arc.padAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+If *angle* is specified, sets the pad angle to the specified function or number and returns this arc generator. If *angle* is not specified, returns the current pad angle accessor, which defaults to:
+
+```js
+function padAngle() {
+ return d && d.padAngle;
+}
+```
+
+The pad angle is converted to a fixed linear distance separating adjacent arcs, defined as [padRadius](#arc_padRadius) * padAngle. This distance is subtracted equally from the [start](#arc_startAngle) and [end](#arc_endAngle) of the arc. If the arc forms a complete circle or annulus, as when |endAngle - startAngle| ≥ τ, the pad angle is ignored.
+
+If the [inner radius](#arc_innerRadius) or angular span is small relative to the pad angle, it may not be possible to maintain parallel edges between adjacent arcs. In this case, the inner edge of the arc may collapse to a point, similar to a circular sector. For this reason, padding is typically only applied to annular sectors (*i.e.*, when innerRadius is positive), as shown in this diagram:
+
+[
](http://bl.ocks.org/mbostock/f37b07b92633781a46f7)[
](http://bl.ocks.org/mbostock/99f0a6533f7c949cf8b8)
+
+The recommended minimum inner radius when using padding is outerRadius \* padAngle / sin(θ), where θ is the angular span of the smallest arc before padding. For example, if the outer radius is 200 pixels and the pad angle is 0.02 radians, a reasonable θ is 0.04 radians, and a reasonable inner radius is 100 pixels. See the [arc padding animation](http://bl.ocks.org/mbostock/053fcc2295a445afab07) for illustration.
+
+Often, the pad angle is not set directly on the arc generator, but is instead computed by the [pie generator](#pies) so as to ensure that the area of padded arcs is proportional to their value; see [*pie*.padAngle](#pie_padAngle). See the [pie padding animation](http://bl.ocks.org/mbostock/3e961b4c97a1b543fff2) for illustration. If you apply a constant pad angle to the arc generator directly, it tends to subtract disproportionately from smaller arcs, introducing distortion.
+
+# arc.padRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+If *radius* is specified, sets the pad radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current pad radius accessor, which defaults to null, indicating that the pad radius should be automatically computed as sqrt([innerRadius](#arc_innerRadius) * innerRadius + [outerRadius](#arc_outerRadius) * outerRadius). The pad radius determines the fixed linear distance separating adjacent arcs, defined as padRadius * [padAngle](#arc_padAngle).
+
+# arc.context([context]) · [Source](https://github.com/d3/d3-shape/blob/master/src/arc.js)
+
+If *context* is specified, sets the context and returns this arc generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated arc](#_arc) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated arc is returned.
+
+### Pies
+
+The pie generator does not produce a shape directly, but instead computes the necessary angles to represent a tabular dataset as a pie or donut chart; these angles can then be passed to an [arc generator](#arcs).
+
+# d3.pie() · [Source](https://github.com/d3/d3-shape/blob/master/src/pie.js)
+
+Constructs a new pie generator with the default settings.
+
+# pie(data[, arguments…]) · [Source](https://github.com/d3/d3-shape/blob/master/src/pie.js)
+
+Generates a pie for the given array of *data*, returning an array of objects representing each datum’s arc angles. Any additional *arguments* are arbitrary; they are simply propagated to the pie generator’s accessor functions along with the `this` object. The length of the returned array is the same as *data*, and each element *i* in the returned array corresponds to the element *i* in the input data. Each object in the returned array has the following properties:
+
+* `data` - the input datum; the corresponding element in the input data array.
+* `value` - the numeric [value](#pie_value) of the arc.
+* `index` - the zero-based [sorted index](#pie_sort) of the arc.
+* `startAngle` - the [start angle](#pie_startAngle) of the arc.
+* `endAngle` - the [end angle](#pie_endAngle) of the arc.
+* `padAngle` - the [pad angle](#pie_padAngle) of the arc.
+
+This representation is designed to work with the arc generator’s default [startAngle](#arc_startAngle), [endAngle](#arc_endAngle) and [padAngle](#arc_padAngle) accessors. The angular units are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify angles in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.
+
+Given a small dataset of numbers, here is how to compute the arc angles to render this data as a pie chart:
+
+```js
+const data = [1, 1, 2, 3, 5, 8, 13, 21];
+const arcs = d3.pie()(data);
+```
+
+The first pair of parens, `pie()`, [constructs](#pie) a default pie generator. The second, `pie()(data)`, [invokes](#_pie) this generator on the dataset, returning an array of objects:
+
+```json
+[
+ {"data": 1, "value": 1, "index": 6, "startAngle": 6.050474740247008, "endAngle": 6.166830023713296, "padAngle": 0},
+ {"data": 1, "value": 1, "index": 7, "startAngle": 6.166830023713296, "endAngle": 6.283185307179584, "padAngle": 0},
+ {"data": 2, "value": 2, "index": 5, "startAngle": 5.817764173314431, "endAngle": 6.050474740247008, "padAngle": 0},
+ {"data": 3, "value": 3, "index": 4, "startAngle": 5.468698322915565, "endAngle": 5.817764173314431, "padAngle": 0},
+ {"data": 5, "value": 5, "index": 3, "startAngle": 4.886921905584122, "endAngle": 5.468698322915565, "padAngle": 0},
+ {"data": 8, "value": 8, "index": 2, "startAngle": 3.956079637853813, "endAngle": 4.886921905584122, "padAngle": 0},
+ {"data": 13, "value": 13, "index": 1, "startAngle": 2.443460952792061, "endAngle": 3.956079637853813, "padAngle": 0},
+ {"data": 21, "value": 21, "index": 0, "startAngle": 0.000000000000000, "endAngle": 2.443460952792061, "padAngle": 0}
+]
+```
+
+Note that the returned array is in the same order as the data, even though this pie chart is [sorted](#pie_sortValues) by descending value, starting with the arc for the last datum (value 21) at 12 o’clock.
+
+# pie.value([value]) · [Source](https://github.com/d3/d3-shape/blob/master/src/pie.js)
+
+If *value* is specified, sets the value accessor to the specified function or number and returns this pie generator. If *value* is not specified, returns the current value accessor, which defaults to:
+
+```js
+function value(d) {
+ return d;
+}
+```
+
+When a pie is [generated](#_pie), the value accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default value accessor assumes that the input data are numbers, or that they are coercible to numbers using [valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf). If your data are not simply numbers, then you should specify an accessor that returns the corresponding numeric value for a given datum. For example:
+
+```js
+const data = [
+ {"number": 4, "name": "Locke"},
+ {"number": 8, "name": "Reyes"},
+ {"number": 15, "name": "Ford"},
+ {"number": 16, "name": "Jarrah"},
+ {"number": 23, "name": "Shephard"},
+ {"number": 42, "name": "Kwon"}
+];
+
+const arcs = d3.pie()
+ .value(d => d.number)
+ (data);
+```
+
+This is similar to [mapping](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) your data to values before invoking the pie generator:
+
+```js
+const arcs = d3.pie()(data.map(d => d.number));
+```
+
+The benefit of an accessor is that the input data remains associated with the returned objects, thereby making it easier to access other fields of the data, for example to set the color or to add text labels.
+
+# pie.sort([compare]) · [Source](https://github.com/d3/d3-shape/blob/master/src/pie.js)
+
+If *compare* is specified, sets the data comparator to the specified function and returns this pie generator. If *compare* is not specified, returns the current data comparator, which defaults to null. If both the data comparator and the value comparator are null, then arcs are positioned in the original input order. Otherwise, the data is sorted according to the data comparator, and the resulting order is used. Setting the data comparator implicitly sets the [value comparator](#pie_sortValues) to null.
+
+The *compare* function takes two arguments *a* and *b*, each elements from the input data array. If the arc for *a* should be before the arc for *b*, then the comparator must return a number less than zero; if the arc for *a* should be after the arc for *b*, then the comparator must return a number greater than zero; returning zero means that the relative order of *a* and *b* is unspecified. For example, to sort arcs by their associated name:
+
+```js
+pie.sort((a, b) => a.name.localeCompare(b.name));
+```
+
+Sorting does not affect the order of the [generated arc array](#_pie) which is always in the same order as the input data array; it merely affects the computed angles of each arc. The first arc starts at the [start angle](#pie_startAngle) and the last arc ends at the [end angle](#pie_endAngle).
+
+# pie.sortValues([compare]) · [Source](https://github.com/d3/d3-shape/blob/master/src/pie.js)
+
+If *compare* is specified, sets the value comparator to the specified function and returns this pie generator. If *compare* is not specified, returns the current value comparator, which defaults to descending value. The default value comparator is implemented as:
+
+```js
+function compare(a, b) {
+ return b - a;
+}
+```
+
+If both the data comparator and the value comparator are null, then arcs are positioned in the original input order. Otherwise, the data is sorted according to the data comparator, and the resulting order is used. Setting the value comparator implicitly sets the [data comparator](#pie_sort) to null.
+
+The value comparator is similar to the [data comparator](#pie_sort), except the two arguments *a* and *b* are values derived from the input data array using the [value accessor](#pie_value), not the data elements. If the arc for *a* should be before the arc for *b*, then the comparator must return a number less than zero; if the arc for *a* should be after the arc for *b*, then the comparator must return a number greater than zero; returning zero means that the relative order of *a* and *b* is unspecified. For example, to sort arcs by ascending value:
+
+```js
+pie.sortValues((a, b) => a - b);
+```
+
+Sorting does not affect the order of the [generated arc array](#_pie) which is always in the same order as the input data array; it merely affects the computed angles of each arc. The first arc starts at the [start angle](#pie_startAngle) and the last arc ends at the [end angle](#pie_endAngle).
+
+# pie.startAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/pie.js)
+
+If *angle* is specified, sets the overall start angle of the pie to the specified function or number and returns this pie generator. If *angle* is not specified, returns the current start angle accessor, which defaults to:
+
+```js
+function startAngle() {
+ return 0;
+}
+```
+
+The start angle here means the *overall* start angle of the pie, *i.e.*, the start angle of the first arc. The start angle accessor is invoked once, being passed the same arguments and `this` context as the [pie generator](#_pie). The units of *angle* are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify an angle in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.
+
+# pie.endAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/pie.js)
+
+If *angle* is specified, sets the overall end angle of the pie to the specified function or number and returns this pie generator. If *angle* is not specified, returns the current end angle accessor, which defaults to:
+
+```js
+function endAngle() {
+ return 2 * Math.PI;
+}
+```
+
+The end angle here means the *overall* end angle of the pie, *i.e.*, the end angle of the last arc. The end angle accessor is invoked once, being passed the same arguments and `this` context as the [pie generator](#_pie). The units of *angle* are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify an angle in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.
+
+The value of the end angle is constrained to [startAngle](#pie_startAngle) ± τ, such that |endAngle - startAngle| ≤ τ.
+
+# pie.padAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/pie.js)
+
+If *angle* is specified, sets the pad angle to the specified function or number and returns this pie generator. If *angle* is not specified, returns the current pad angle accessor, which defaults to:
+
+```js
+function padAngle() {
+ return 0;
+}
+```
+
+The pad angle here means the angular separation between each adjacent arc. The total amount of padding reserved is the specified *angle* times the number of elements in the input data array, and at most |endAngle - startAngle|; the remaining space is then divided proportionally by [value](#pie_value) such that the relative area of each arc is preserved. See the [pie padding animation](http://bl.ocks.org/mbostock/3e961b4c97a1b543fff2) for illustration. The pad angle accessor is invoked once, being passed the same arguments and `this` context as the [pie generator](#_pie). The units of *angle* are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify an angle in radians.
+
+### Lines
+
+[
](https://observablehq.com/@d3/line-chart)
+
+The line generator produces a [spline](https://en.wikipedia.org/wiki/Spline_\(mathematics\)) or [polyline](https://en.wikipedia.org/wiki/Polygonal_chain), as in a line chart. Lines also appear in many other visualization types, such as the links in [hierarchical edge bundling](https://observablehq.com/@d3/hierarchical-edge-bundling).
+
+# d3.line([x][, y]) · [Source](https://github.com/d3/d3-shape/blob/master/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+Constructs a new line generator with the default settings. If *x* or *y* are specified, sets the corresponding accessors to the specified function or number and returns this line generator.
+
+# line(data) · [Source](https://github.com/d3/d3-shape/blob/master/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+Generates a line for the given array of *data*. Depending on this line generator’s associated [curve](#line_curve), the given input *data* may need to be sorted by *x*-value before being passed to the line generator. If the line generator has a [context](#line_context), then the line is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.
+
+# line.x([x]) · [Source](https://github.com/d3/d3-shape/blob/master/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+If *x* is specified, sets the x accessor to the specified function or number and returns this line generator. If *x* is not specified, returns the current x accessor, which defaults to:
+
+```js
+function x(d) {
+ return d[0];
+}
+```
+
+When a line is [generated](#_line), the x accessor will be invoked for each [defined](#line_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default x accessor assumes that the input data are two-element arrays of numbers. If your data are in a different format, or if you wish to transform the data before rendering, then you should specify a custom accessor. For example, if `x` is a [time scale](https://github.com/d3/d3-scale#time-scales) and `y` is a [linear scale](https://github.com/d3/d3-scale#linear-scales):
+
+```js
+const data = [
+ {date: new Date(2007, 3, 24), value: 93.24},
+ {date: new Date(2007, 3, 25), value: 95.35},
+ {date: new Date(2007, 3, 26), value: 98.84},
+ {date: new Date(2007, 3, 27), value: 99.92},
+ {date: new Date(2007, 3, 30), value: 99.80},
+ {date: new Date(2007, 4, 1), value: 99.47},
+ …
+];
+
+const line = d3.line()
+ .x(d => x(d.date))
+ .y(d => y(d.value));
+```
+
+# line.y([y]) · [Source](https://github.com/d3/d3-shape/blob/master/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+If *y* is specified, sets the y accessor to the specified function or number and returns this line generator. If *y* is not specified, returns the current y accessor, which defaults to:
+
+```js
+function y(d) {
+ return d[1];
+}
+```
+
+When a line is [generated](#_line), the y accessor will be invoked for each [defined](#line_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default y accessor assumes that the input data are two-element arrays of numbers. See [*line*.x](#line_x) for more information.
+
+# line.defined([defined]) · [Source](https://github.com/d3/d3-shape/blob/master/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+If *defined* is specified, sets the defined accessor to the specified function or boolean and returns this line generator. If *defined* is not specified, returns the current defined accessor, which defaults to:
+
+```js
+function defined() {
+ return true;
+}
+```
+
+The default accessor thus assumes that the input data is always defined. When a line is [generated](#_line), the defined accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. If the given element is defined (*i.e.*, if the defined accessor returns a truthy value for this element), the [x](#line_x) and [y](#line_y) accessors will subsequently be evaluated and the point will be added to the current line segment. Otherwise, the element will be skipped, the current line segment will be ended, and a new line segment will be generated for the next defined point. As a result, the generated line may have several discrete segments. For example:
+
+[
](http://bl.ocks.org/mbostock/0533f44f2cfabecc5e3a)
+
+Note that if a line segment consists of only a single point, it may appear invisible unless rendered with rounded or square [line caps](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap). In addition, some curves such as [curveCardinalOpen](#curveCardinalOpen) only render a visible segment if it contains multiple points.
+
+# line.curve([curve]) · [Source](https://github.com/d3/d3-shape/blob/master/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+If *curve* is specified, sets the [curve factory](#curves) and returns this line generator. If *curve* is not specified, returns the current curve factory, which defaults to [curveLinear](#curveLinear).
+
+# line.context([context]) · [Source](https://github.com/d3/d3-shape/blob/master/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+If *context* is specified, sets the context and returns this line generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated line](#_line) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated line is returned.
+
+# d3.lineRadial() · [Source](https://github.com/d3/d3-shape/blob/master/src/lineRadial.js), [Examples](https://observablehq.com/@d3/d3-lineradial)
+
+
+
+Constructs a new radial line generator with the default settings. A radial line generator is equivalent to the standard Cartesian [line generator](#line), except the [x](#line_x) and [y](#line_y) accessors are replaced with [angle](#lineRadial_angle) and [radius](#lineRadial_radius) accessors. Radial lines are always positioned relative to ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to change the origin.
+
+# lineRadial(data) · [Source](https://github.com/d3/d3-shape/blob/master/src/lineRadial.js#L4), [Examples](https://observablehq.com/@d3/d3-lineradial)
+
+Equivalent to [*line*](#_line).
+
+# lineRadial.angle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/lineRadial.js#L7), [Examples](https://observablehq.com/@d3/d3-lineradial)
+
+Equivalent to [*line*.x](#line_x), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock).
+
+# lineRadial.radius([radius]) · [Source](https://github.com/d3/d3-shape/blob/master/src/lineRadial.js#L8), [Examples](https://observablehq.com/@d3/d3-lineradial)
+
+Equivalent to [*line*.y](#line_y), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
+
+# lineRadial.defined([defined])
+
+Equivalent to [*line*.defined](#line_defined).
+
+# lineRadial.curve([curve]) · [Source](https://github.com/d3/d3-shape/blob/master/src/lineRadial.js), [Examples](https://observablehq.com/@d3/d3-lineradial)
+
+Equivalent to [*line*.curve](#line_curve). Note that [curveMonotoneX](#curveMonotoneX) or [curveMonotoneY](#curveMonotoneY) are not recommended for radial lines because they assume that the data is monotonic in *x* or *y*, which is typically untrue of radial lines.
+
+# lineRadial.context([context])
+
+Equivalent to [*line*.context](#line_context).
+
+### Areas
+
+[
](https://observablehq.com/@d3/area-chart)[
](https://observablehq.com/@d3/stacked-area-chart)[
](https://observablehq.com/@d3/difference-chart)
+
+The area generator produces an area, as in an area chart. An area is defined by two bounding [lines](#lines), either splines or polylines. Typically, the two lines share the same [*x*-values](#area_x) ([x0](#area_x0) = [x1](#area_x1)), differing only in *y*-value ([y0](#area_y0) and [y1](#area_y1)); most commonly, y0 is defined as a constant representing [zero](http://www.vox.com/2015/11/19/9758062/y-axis-zero-chart). The first line (the topline) is defined by x1 and y1 and is rendered first; the second line (the baseline) is defined by x0 and y0 and is rendered second, with the points in reverse order. With a [curveLinear](#curveLinear) [curve](#area_curve), this produces a clockwise polygon.
+
+# d3.area([x][, y0][, y1]) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+Constructs a new area generator with the default settings. If *x*, *y0* or *y1* are specified, sets the corresponding accessors to the specified function or number and returns this area generator.
+
+# area(data) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+Generates an area for the given array of *data*. Depending on this area generator’s associated [curve](#area_curve), the given input *data* may need to be sorted by *x*-value before being passed to the area generator. If the area generator has a [context](#line_context), then the area is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.
+
+# area.x([x]) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+If *x* is specified, sets [x0](#area_x0) to *x* and [x1](#area_x1) to null and returns this area generator. If *x* is not specified, returns the current x0 accessor.
+
+# area.x0([x]) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+If *x* is specified, sets the x0 accessor to the specified function or number and returns this area generator. If *x* is not specified, returns the current x0 accessor, which defaults to:
+
+```js
+function x(d) {
+ return d[0];
+}
+```
+
+When an area is [generated](#_area), the x0 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default x0 accessor assumes that the input data are two-element arrays of numbers. If your data are in a different format, or if you wish to transform the data before rendering, then you should specify a custom accessor. For example, if `x` is a [time scale](https://github.com/d3/d3-scale#time-scales) and `y` is a [linear scale](https://github.com/d3/d3-scale#linear-scales):
+
+```js
+const data = [
+ {date: new Date(2007, 3, 24), value: 93.24},
+ {date: new Date(2007, 3, 25), value: 95.35},
+ {date: new Date(2007, 3, 26), value: 98.84},
+ {date: new Date(2007, 3, 27), value: 99.92},
+ {date: new Date(2007, 3, 30), value: 99.80},
+ {date: new Date(2007, 4, 1), value: 99.47},
+ …
+];
+
+const area = d3.area()
+ .x(d => x(d.date))
+ .y1(d => y(d.value))
+ .y0(y(0));
+```
+
+# area.x1([x]) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+If *x* is specified, sets the x1 accessor to the specified function or number and returns this area generator. If *x* is not specified, returns the current x1 accessor, which defaults to null, indicating that the previously-computed [x0](#area_x0) value should be reused for the x1 value.
+
+When an area is [generated](#_area), the x1 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. See [*area*.x0](#area_x0) for more information.
+
+# area.y([y]) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+If *y* is specified, sets [y0](#area_y0) to *y* and [y1](#area_y1) to null and returns this area generator. If *y* is not specified, returns the current y0 accessor.
+
+# area.y0([y]) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+If *y* is specified, sets the y0 accessor to the specified function or number and returns this area generator. If *y* is not specified, returns the current y0 accessor, which defaults to:
+
+```js
+function y() {
+ return 0;
+}
+```
+
+When an area is [generated](#_area), the y0 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. See [*area*.x0](#area_x0) for more information.
+
+# area.y1([y]) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+If *y* is specified, sets the y1 accessor to the specified function or number and returns this area generator. If *y* is not specified, returns the current y1 accessor, which defaults to:
+
+```js
+function y(d) {
+ return d[1];
+}
+```
+
+A null accessor is also allowed, indicating that the previously-computed [y0](#area_y0) value should be reused for the y1 value. When an area is [generated](#_area), the y1 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. See [*area*.x0](#area_x0) for more information.
+
+# area.defined([defined]) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+If *defined* is specified, sets the defined accessor to the specified function or boolean and returns this area generator. If *defined* is not specified, returns the current defined accessor, which defaults to:
+
+```js
+function defined() {
+ return true;
+}
+```
+
+The default accessor thus assumes that the input data is always defined. When an area is [generated](#_area), the defined accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. If the given element is defined (*i.e.*, if the defined accessor returns a truthy value for this element), the [x0](#area_x0), [x1](#area_x1), [y0](#area_y0) and [y1](#area_y1) accessors will subsequently be evaluated and the point will be added to the current area segment. Otherwise, the element will be skipped, the current area segment will be ended, and a new area segment will be generated for the next defined point. As a result, the generated area may have several discrete segments. For example:
+
+[
](http://bl.ocks.org/mbostock/3035090)
+
+Note that if an area segment consists of only a single point, it may appear invisible unless rendered with rounded or square [line caps](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap). In addition, some curves such as [curveCardinalOpen](#curveCardinalOpen) only render a visible segment if it contains multiple points.
+
+# area.curve([curve]) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+If *curve* is specified, sets the [curve factory](#curves) and returns this area generator. If *curve* is not specified, returns the current curve factory, which defaults to [curveLinear](#curveLinear).
+
+# area.context([context]) · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+If *context* is specified, sets the context and returns this area generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated area](#_area) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated area is returned.
+
+# area.lineX0() · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
# area.lineY0() · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+Returns a new [line generator](#lines) that has this area generator’s current [defined accessor](#area_defined), [curve](#area_curve) and [context](#area_context). The line’s [*x*-accessor](#line_x) is this area’s [*x0*-accessor](#area_x0), and the line’s [*y*-accessor](#line_y) is this area’s [*y0*-accessor](#area_y0).
+
+# area.lineX1() · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+Returns a new [line generator](#lines) that has this area generator’s current [defined accessor](#area_defined), [curve](#area_curve) and [context](#area_context). The line’s [*x*-accessor](#line_x) is this area’s [*x1*-accessor](#area_x1), and the line’s [*y*-accessor](#line_y) is this area’s [*y0*-accessor](#area_y0).
+
+# area.lineY1() · [Source](https://github.com/d3/d3-shape/blob/master/src/area.js)
+
+Returns a new [line generator](#lines) that has this area generator’s current [defined accessor](#area_defined), [curve](#area_curve) and [context](#area_context). The line’s [*x*-accessor](#line_x) is this area’s [*x0*-accessor](#area_x0), and the line’s [*y*-accessor](#line_y) is this area’s [*y1*-accessor](#area_y1).
+
+# d3.areaRadial() · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+
+
+Constructs a new radial area generator with the default settings. A radial area generator is equivalent to the standard Cartesian [area generator](#area), except the [x](#area_x) and [y](#area_y) accessors are replaced with [angle](#areaRadial_angle) and [radius](#areaRadial_radius) accessors. Radial areas are always positioned relative to ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to change the origin.
+
+# areaRadial(data)
+
+Equivalent to [*area*](#_area).
+
+# areaRadial.angle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+Equivalent to [*area*.x](#area_x), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock).
+
+# areaRadial.startAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+Equivalent to [*area*.x0](#area_x0), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock). Note: typically [angle](#areaRadial_angle) is used instead of setting separate start and end angles.
+
+# areaRadial.endAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+Equivalent to [*area*.x1](#area_x1), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock). Note: typically [angle](#areaRadial_angle) is used instead of setting separate start and end angles.
+
+# areaRadial.radius([radius]) · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+Equivalent to [*area*.y](#area_y), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
+
+# areaRadial.innerRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+Equivalent to [*area*.y0](#area_y0), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
+
+# areaRadial.outerRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+Equivalent to [*area*.y1](#area_y1), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
+
+# areaRadial.defined([defined])
+
+Equivalent to [*area*.defined](#area_defined).
+
+# areaRadial.curve([curve]) · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+Equivalent to [*area*.curve](#area_curve). Note that [curveMonotoneX](#curveMonotoneX) or [curveMonotoneY](#curveMonotoneY) are not recommended for radial areas because they assume that the data is monotonic in *x* or *y*, which is typically untrue of radial areas.
+
+# areaRadial.context([context])
+
+Equivalent to [*line*.context](#line_context).
+
+# areaRadial.lineStartAngle() · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
# areaRadial.lineInnerRadius() · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+Returns a new [radial line generator](#lineRadial) that has this radial area generator’s current [defined accessor](#areaRadial_defined), [curve](#areaRadial_curve) and [context](#areaRadial_context). The line’s [angle accessor](#lineRadial_angle) is this area’s [start angle accessor](#areaRadial_startAngle), and the line’s [radius accessor](#lineRadial_radius) is this area’s [inner radius accessor](#areaRadial_innerRadius).
+
+# areaRadial.lineEndAngle() · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+Returns a new [radial line generator](#lineRadial) that has this radial area generator’s current [defined accessor](#areaRadial_defined), [curve](#areaRadial_curve) and [context](#areaRadial_context). The line’s [angle accessor](#lineRadial_angle) is this area’s [end angle accessor](#areaRadial_endAngle), and the line’s [radius accessor](#lineRadial_radius) is this area’s [inner radius accessor](#areaRadial_innerRadius).
+
+# areaRadial.lineOuterRadius() · [Source](https://github.com/d3/d3-shape/blob/master/src/areaRadial.js)
+
+Returns a new [radial line generator](#lineRadial) that has this radial area generator’s current [defined accessor](#areaRadial_defined), [curve](#areaRadial_curve) and [context](#areaRadial_context). The line’s [angle accessor](#lineRadial_angle) is this area’s [start angle accessor](#areaRadial_startAngle), and the line’s [radius accessor](#lineRadial_radius) is this area’s [outer radius accessor](#areaRadial_outerRadius).
+
+### Curves
+
+While [lines](#lines) are defined as a sequence of two-dimensional [*x*, *y*] points, and [areas](#areas) are similarly defined by a topline and a baseline, there remains the task of transforming this discrete representation into a continuous shape: *i.e.*, how to interpolate between the points. A variety of curves are provided for this purpose.
+
+Curves are typically not constructed or used directly, instead being passed to [*line*.curve](#line_curve) and [*area*.curve](#area_curve). For example:
+
+```js
+const line = d3.line(d => d.date, d => d.value)
+ .curve(d3.curveCatmullRom.alpha(0.5));
+```
+
+# d3.curveBasis(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/basis.js)
+
+
+
+Produces a cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points. The first and last points are triplicated such that the spline starts at the first point and ends at the last point, and is tangent to the line between the first and second points, and to the line between the penultimate and last points.
+
+# d3.curveBasisClosed(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/basisClosed.js)
+
+
+
+Produces a closed cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points. When a line segment ends, the first three control points are repeated, producing a closed loop with C2 continuity.
+
+# d3.curveBasisOpen(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/basisOpen.js)
+
+
+
+Produces a cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points. Unlike [basis](#basis), the first and last points are not repeated, and thus the curve typically does not intersect these points.
+
+# d3.curveBumpX(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/bump.js)
+
+
+
+Produces a Bézier curve between each pair of points, with horizontal tangents at each point.
+
+# d3.curveBumpY(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/bump.js)
+
+
+
+Produces a Bézier curve between each pair of points, with vertical tangents at each point.
+
+# d3.curveBundle(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/bundle.js)
+
+
+
+Produces a straightened cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points, with the spline straightened according to the curve’s [*beta*](#curveBundle_beta), which defaults to 0.85. This curve is typically used in [hierarchical edge bundling](https://observablehq.com/@d3/hierarchical-edge-bundling) to disambiguate connections, as proposed by [Danny Holten](https://www.win.tue.nl/vis1/home/dholten/) in [Hierarchical Edge Bundles: Visualization of Adjacency Relations in Hierarchical Data](https://www.win.tue.nl/vis1/home/dholten/papers/bundles_infovis.pdf). This curve does not implement [*curve*.areaStart](#curve_areaStart) and [*curve*.areaEnd](#curve_areaEnd); it is intended to work with [d3.line](#lines), not [d3.area](#areas).
+
+# bundle.beta(beta) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/bundle.js)
+
+Returns a bundle curve with the specified *beta* in the range [0, 1], representing the bundle strength. If *beta* equals zero, a straight line between the first and last point is produced; if *beta* equals one, a standard [basis](#basis) spline is produced. For example:
+
+```js
+const line = d3.line().curve(d3.curveBundle.beta(0.5));
+```
+
+# d3.curveCardinal(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/cardinal.js)
+
+
+
+Produces a cubic [cardinal spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline) using the specified control points, with one-sided differences used for the first and last piece. The default [tension](#curveCardinal_tension) is 0.
+
+# d3.curveCardinalClosed(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/cardinalClosed.js)
+
+
+
+Produces a closed cubic [cardinal spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline) using the specified control points. When a line segment ends, the first three control points are repeated, producing a closed loop. The default [tension](#curveCardinal_tension) is 0.
+
+# d3.curveCardinalOpen(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/cardinalOpen.js)
+
+
+
+Produces a cubic [cardinal spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline) using the specified control points. Unlike [curveCardinal](#curveCardinal), one-sided differences are not used for the first and last piece, and thus the curve starts at the second point and ends at the penultimate point. The default [tension](#curveCardinal_tension) is 0.
+
+# cardinal.tension(tension) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/cardinalOpen.js)
+
+Returns a cardinal curve with the specified *tension* in the range [0, 1]. The *tension* determines the length of the tangents: a *tension* of one yields all zero tangents, equivalent to [curveLinear](#curveLinear); a *tension* of zero produces a uniform [Catmull–Rom](#curveCatmullRom) spline. For example:
+
+```js
+const line = d3.line().curve(d3.curveCardinal.tension(0.5));
+```
+
+# d3.curveCatmullRom(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/catmullRom.js)
+
+
+
+Produces a cubic Catmull–Rom spline using the specified control points and the parameter [*alpha*](#curveCatmullRom_alpha), which defaults to 0.5, as proposed by Yuksel et al. in [On the Parameterization of Catmull–Rom Curves](http://www.cemyuksel.com/research/catmullrom_param/), with one-sided differences used for the first and last piece.
+
+# d3.curveCatmullRomClosed(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/catmullRomClosed.js)
+
+
+
+Produces a closed cubic Catmull–Rom spline using the specified control points and the parameter [*alpha*](#curveCatmullRom_alpha), which defaults to 0.5, as proposed by Yuksel et al. When a line segment ends, the first three control points are repeated, producing a closed loop.
+
+# d3.curveCatmullRomOpen(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/catmullRomOpen.js)
+
+
+
+Produces a cubic Catmull–Rom spline using the specified control points and the parameter [*alpha*](#curveCatmullRom_alpha), which defaults to 0.5, as proposed by Yuksel et al. Unlike [curveCatmullRom](#curveCatmullRom), one-sided differences are not used for the first and last piece, and thus the curve starts at the second point and ends at the penultimate point.
+
+# catmullRom.alpha(alpha) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/catmullRom.js)
+
+Returns a cubic Catmull–Rom curve with the specified *alpha* in the range [0, 1]. If *alpha* is zero, produces a uniform spline, equivalent to [curveCardinal](#curveCardinal) with a tension of zero; if *alpha* is one, produces a chordal spline; if *alpha* is 0.5, produces a [centripetal spline](https://en.wikipedia.org/wiki/Centripetal_Catmull–Rom_spline). Centripetal splines are recommended to avoid self-intersections and overshoot. For example:
+
+```js
+const line = d3.line().curve(d3.curveCatmullRom.alpha(0.5));
+```
+
+# d3.curveLinear(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/linear.js)
+
+
+
+Produces a polyline through the specified points.
+
+# d3.curveLinearClosed(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/linearClosed.js)
+
+
+
+Produces a closed polyline through the specified points by repeating the first point when the line segment ends.
+
+# d3.curveMonotoneX(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/monotone.js)
+
+
+
+Produces a cubic spline that [preserves monotonicity](https://en.wikipedia.org/wiki/Monotone_cubic_interpolation) in *y*, assuming monotonicity in *x*, as proposed by Steffen in [A simple method for monotonic interpolation in one dimension](http://adsabs.harvard.edu/full/1990A%26A...239..443S): “a smooth curve with continuous first-order derivatives that passes through any given set of data points without spurious oscillations. Local extrema can occur only at grid points where they are given by the data, but not in between two adjacent grid points.â€
+
+# d3.curveMonotoneY(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/monotone.js)
+
+
+
+Produces a cubic spline that [preserves monotonicity](https://en.wikipedia.org/wiki/Monotone_cubic_interpolation) in *x*, assuming monotonicity in *y*, as proposed by Steffen in [A simple method for monotonic interpolation in one dimension](http://adsabs.harvard.edu/full/1990A%26A...239..443S): “a smooth curve with continuous first-order derivatives that passes through any given set of data points without spurious oscillations. Local extrema can occur only at grid points where they are given by the data, but not in between two adjacent grid points.â€
+
+# d3.curveNatural(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/natural.js)
+
+
+
+Produces a [natural](https://en.wikipedia.org/wiki/Spline_interpolation) [cubic spline](http://mathworld.wolfram.com/CubicSpline.html) with the second derivative of the spline set to zero at the endpoints.
+
+# d3.curveStep(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/step.js)
+
+
+
+Produces a piecewise constant function (a [step function](https://en.wikipedia.org/wiki/Step_function)) consisting of alternating horizontal and vertical lines. The *y*-value changes at the midpoint of each pair of adjacent *x*-values.
+
+# d3.curveStepAfter(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/step.js)
+
+
+
+Produces a piecewise constant function (a [step function](https://en.wikipedia.org/wiki/Step_function)) consisting of alternating horizontal and vertical lines. The *y*-value changes after the *x*-value.
+
+# d3.curveStepBefore(context) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/step.js)
+
+
+
+Produces a piecewise constant function (a [step function](https://en.wikipedia.org/wiki/Step_function)) consisting of alternating horizontal and vertical lines. The *y*-value changes before the *x*-value.
+
+### Custom Curves
+
+Curves are typically not used directly, instead being passed to [*line*.curve](#line_curve) and [*area*.curve](#area_curve). However, you can define your own curve implementation should none of the built-in curves satisfy your needs using the following interface. You can also use this low-level interface with a built-in curve type as an alternative to the line and area generators.
+
+# curve.areaStart() · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/step.js#L7)
+
+Indicates the start of a new area segment. Each area segment consists of exactly two [line segments](#curve_lineStart): the topline, followed by the baseline, with the baseline points in reverse order.
+
+# curve.areaEnd() · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/step.js)
+
+Indicates the end of the current area segment.
+
+# curve.lineStart() · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/step.js)
+
+Indicates the start of a new line segment. Zero or more [points](#curve_point) will follow.
+
+# curve.lineEnd() · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/step.js)
+
+Indicates the end of the current line segment.
+
+# curve.point(x, y) · [Source](https://github.com/d3/d3-shape/blob/master/src/curve/step.js)
+
+Indicates a new point in the current line segment with the given *x*- and *y*-values.
+
+### Links
+
+[
](https://observablehq.com/@d3/tidy-tree)
+
+The **link** shape generates a smooth cubic Bézier curve from a source point to a target point. The tangents of the curve at the start and end are either [vertical](#linkVertical), [horizontal](#linkHorizontal) or [radial](#linkRadial).
+
+# d3.linkVertical() · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+Returns a new [link generator](#_link) with vertical tangents. For example, to visualize [links](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_links) in a [tree diagram](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree) rooted on the top edge of the display, you might say:
+
+```js
+const link = d3.linkVertical()
+ .x(d => d.x)
+ .y(d => d.y);
+```
+
+# d3.linkHorizontal() · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+Returns a new [link generator](#_link) with horizontal tangents. For example, to visualize [links](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_links) in a [tree diagram](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree) rooted on the left edge of the display, you might say:
+
+```js
+const link = d3.linkHorizontal()
+ .x(d => d.y)
+ .y(d => d.x);
+```
+
+# link(arguments…) · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+Generates a link for the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the link generator’s accessor functions along with the `this` object. For example, with the default settings, an object expected:
+
+```js
+link({
+ source: [100, 100],
+ target: [300, 300]
+});
+```
+
+# link.source([source]) · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+If *source* is specified, sets the source accessor to the specified function and returns this link generator. If *source* is not specified, returns the current source accessor, which defaults to:
+
+```js
+function source(d) {
+ return d.source;
+}
+```
+
+# link.target([target]) · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+If *target* is specified, sets the target accessor to the specified function and returns this link generator. If *target* is not specified, returns the current target accessor, which defaults to:
+
+```js
+function target(d) {
+ return d.target;
+}
+```
+
+# link.x([x]) · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+If *x* is specified, sets the *x*-accessor to the specified function or number and returns this link generator. If *x* is not specified, returns the current *x*-accessor, which defaults to:
+
+```js
+function x(d) {
+ return d[0];
+}
+```
+
+# link.y([y]) · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+If *y* is specified, sets the *y*-accessor to the specified function or number and returns this link generator. If *y* is not specified, returns the current *y*-accessor, which defaults to:
+
+```js
+function y(d) {
+ return d[1];
+}
+```
+
+# link.context([context]) · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+If *context* is specified, sets the context and returns this link generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated link](#_link) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated link is returned. See also [d3-path](https://github.com/d3/d3-path).
+
+# d3.linkRadial() · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+Returns a new [link generator](#_link) with radial tangents. For example, to visualize [links](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_links) in a [tree diagram](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree) rooted in the center of the display, you might say:
+
+```js
+const link = d3.linkRadial()
+ .angle(d => d.x)
+ .radius(d => d.y);
+```
+
+# linkRadial.angle([angle]) · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+Equivalent to [*link*.x](#link_x), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock).
+
+# linkRadial.radius([radius]) · [Source](https://github.com/d3/d3-shape/blob/master/src/link/index.js)
+
+Equivalent to [*link*.y](#link_y), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
+
+### Symbols
+
+





+
+Symbols provide a categorical shape encoding as is commonly used in scatterplots. Symbols are always centered at ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to move the symbol to a different position.
+
+# d3.symbol([type][, size]) · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+Constructs a new symbol generator of the specified [type](#symbol_type) and [size](#symbol_size). If not specified, *type* defaults to a circle, and *size* defaults to 64.
+
+# symbol(arguments…) · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+Generates a symbol for the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the symbol generator’s accessor functions along with the `this` object. For example, with the default settings, no arguments are needed to produce a circle with area 64 square pixels. If the symbol generator has a [context](#symbol_context), then the symbol is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.
+
+# symbol.type([type]) · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+If *type* is specified, sets the symbol type to the specified function or symbol type and returns this symbol generator. If *type* is a function, the symbol generator’s arguments and *this* are passed through. (See [*selection*.attr](https://github.com/d3/d3-selection/blob/master/README.md#selection_attr) if you are using d3-selection.) If *type* is not specified, returns the current symbol type accessor, which defaults to:
+
+```js
+function type() {
+ return circle;
+}
+```
+
+See [symbols](#symbols) for the set of built-in symbol types. To implement a custom symbol type, pass an object that implements [*symbolType*.draw](#symbolType_draw).
+
+# symbol.size([size]) · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+If *size* is specified, sets the size to the specified function or number and returns this symbol generator. If *size* is a function, the symbol generator’s arguments and *this* are passed through. (See [*selection*.attr](https://github.com/d3/d3-selection/blob/master/README.md#selection_attr) if you are using d3-selection.) If *size* is not specified, returns the current size accessor, which defaults to:
+
+```js
+function size() {
+ return 64;
+}
+```
+
+Specifying the size as a function is useful for constructing a scatterplot with a size encoding. If you wish to scale the symbol to fit a given bounding box, rather than by area, try [SVG’s getBBox](https://observablehq.com/d/1fac2626b9e1b65f).
+
+# symbol.context([context]) · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol.js)
+
+If *context* is specified, sets the context and returns this symbol generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated symbol](#_symbol) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated symbol is returned.
+
+# d3.symbols · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+An array containing the set of all built-in symbol types: [circle](#symbolCircle), [cross](#symbolCross), [diamond](#symbolDiamond), [square](#symbolSquare), [star](#symbolStar), [triangle](#symbolTriangle), and [wye](#symbolWye). Useful for constructing the range of an [ordinal scale](https://github.com/d3/d3-scale#ordinal-scales) should you wish to use a shape encoding for categorical data.
+
+# d3.symbolCircle · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol/circle.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+The circle symbol type.
+
+# d3.symbolCross · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol/cross.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+The Greek cross symbol type, with arms of equal length.
+
+# d3.symbolDiamond · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol/diamond.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+The rhombus symbol type.
+
+# d3.symbolSquare · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol/square.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+The square symbol type.
+
+# d3.symbolStar · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol/star.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+The pentagonal star (pentagram) symbol type.
+
+# d3.symbolTriangle · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol/triangle.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+The up-pointing triangle symbol type.
+
+# d3.symbolWye · [Source](https://github.com/d3/d3-shape/blob/master/src/symbol/wye.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+The Y-shape symbol type.
+
+# d3.pointRadial(angle, radius) · [Source](https://github.com/d3/d3-shape/blob/master/src/pointRadial.js), [Examples](https://observablehq.com/@d3/radial-area-chart)
+
+Returns the point [x, y] for the given *angle* in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise, and the given *radius*.
+
+### Custom Symbol Types
+
+Symbol types are typically not used directly, instead being passed to [*symbol*.type](#symbol_type). However, you can define your own symbol type implementation should none of the built-in types satisfy your needs using the following interface. You can also use this low-level interface with a built-in symbol type as an alternative to the symbol generator.
+
+# symbolType.draw(context, size)
+
+Renders this symbol type to the specified *context* with the specified *size* in square pixels. The *context* implements the [CanvasPathMethods](http://www.w3.org/TR/2dcontext/#canvaspathmethods) interface. (Note that this is a subset of the CanvasRenderingContext2D interface!)
+
+### Stacks
+
+[
](https://observablehq.com/@d3/stacked-bar-chart)[
](https://observablehq.com/@mbostock/streamgraph-transitions)
+
+Some shape types can be stacked, placing one shape adjacent to another. For example, a bar chart of monthly sales might be broken down into a multi-series bar chart by product category, stacking bars vertically. This is equivalent to subdividing a bar chart by an ordinal dimension (such as product category) and applying a color encoding.
+
+Stacked charts can show overall value and per-category value simultaneously; however, it is typically harder to compare across categories, as only the bottom layer of the stack is aligned. So, chose the [stack order](#stack_order) carefully, and consider a [streamgraph](#stackOffsetWiggle). (See also [grouped charts](https://observablehq.com/@d3/grouped-bar-chart).)
+
+Like the [pie generator](#pies), the stack generator does not produce a shape directly. Instead it computes positions which you can then pass to an [area generator](#areas) or use directly, say to position bars.
+
+# d3.stack() · [Source](https://github.com/d3/d3-shape/blob/master/src/stack.js)
+
+Constructs a new stack generator with the default settings.
+
+# stack(data[, arguments…]) · [Source](https://github.com/d3/d3-shape/blob/master/src/stack.js)
+
+Generates a stack for the given array of *data*, returning an array representing each series. Any additional *arguments* are arbitrary; they are simply propagated to accessors along with the `this` object.
+
+The series are determined by the [keys accessor](#stack_keys); each series *i* in the returned array corresponds to the *i*th key. Each series is an array of points, where each point *j* corresponds to the *j*th element in the input *data*. Lastly, each point is represented as an array [*y0*, *y1*] where *y0* is the lower value (baseline) and *y1* is the upper value (topline); the difference between *y0* and *y1* corresponds to the computed [value](#stack_value) for this point. The key for each series is available as *series*.key, and the [index](#stack_order) as *series*.index. The input data element for each point is available as *point*.data.
+
+For example, consider the following table representing monthly sales of fruits:
+
+Month | Apples | Bananas | Cherries | Dates
+--------|--------|---------|----------|-------
+ 1/2015 | 3840 | 1920 | 960 | 400
+ 2/2015 | 1600 | 1440 | 960 | 400
+ 3/2015 | 640 | 960 | 640 | 400
+ 4/2015 | 320 | 480 | 640 | 400
+
+This might be represented in JavaScript as an array of objects:
+
+```js
+const data = [
+ {month: new Date(2015, 0, 1), apples: 3840, bananas: 1920, cherries: 960, dates: 400},
+ {month: new Date(2015, 1, 1), apples: 1600, bananas: 1440, cherries: 960, dates: 400},
+ {month: new Date(2015, 2, 1), apples: 640, bananas: 960, cherries: 640, dates: 400},
+ {month: new Date(2015, 3, 1), apples: 320, bananas: 480, cherries: 640, dates: 400}
+];
+```
+
+To produce a stack for this data:
+
+```js
+const stack = d3.stack()
+ .keys(["apples", "bananas", "cherries", "dates"])
+ .order(d3.stackOrderNone)
+ .offset(d3.stackOffsetNone);
+
+const series = stack(data);
+```
+
+The resulting array has one element per *series*. Each series has one point per month, and each point has a lower and upper value defining the baseline and topline:
+
+```js
+[
+ [[ 0, 3840], [ 0, 1600], [ 0, 640], [ 0, 320]], // apples
+ [[3840, 5760], [1600, 3040], [ 640, 1600], [ 320, 800]], // bananas
+ [[5760, 6720], [3040, 4000], [1600, 2240], [ 800, 1440]], // cherries
+ [[6720, 7120], [4000, 4400], [2240, 2640], [1440, 1840]], // dates
+]
+```
+
+Each series in then typically passed to an [area generator](#areas) to render an area chart, or used to construct rectangles for a bar chart.
+
+# stack.keys([keys]) · [Source](https://github.com/d3/d3-shape/blob/master/src/stack.js)
+
+If *keys* is specified, sets the keys accessor to the specified function or array and returns this stack generator. If *keys* is not specified, returns the current keys accessor, which defaults to the empty array. A series (layer) is [generated](#_stack) for each key. Keys are typically strings, but they may be arbitrary values. The series’ key is passed to the [value accessor](#stack_value), along with each data point, to compute the point’s value.
+
+# stack.value([value]) · [Source](https://github.com/d3/d3-shape/blob/master/src/stack.js)
+
+If *value* is specified, sets the value accessor to the specified function or number and returns this stack generator. If *value* is not specified, returns the current value accessor, which defaults to:
+
+```js
+function value(d, key) {
+ return d[key];
+}
+```
+
+Thus, by default the stack generator assumes that the input data is an array of objects, with each object exposing named properties with numeric values; see [*stack*](#_stack) for an example.
+
+# stack.order([order]) · [Source](https://github.com/d3/d3-shape/blob/master/src/stack.js)
+
+If *order* is specified, sets the order accessor to the specified function or array and returns this stack generator. If *order* is not specified, returns the current order accessor, which defaults to [stackOrderNone](#stackOrderNone); this uses the order given by the [key accessor](#stack_key). See [stack orders](#stack-orders) for the built-in orders.
+
+If *order* is a function, it is passed the generated series array and must return an array of numeric indexes representing the stack order. For example, the default order is defined as:
+
+```js
+function orderNone(series) {
+ let n = series.length;
+ const o = new Array(n);
+ while (--n >= 0) o[n] = n;
+ return o;
+}
+```
+
+The stack order is computed prior to the [offset](#stack_offset); thus, the lower value for all points is zero at the time the order is computed. The index attribute for each series is also not set until after the order is computed.
+
+# stack.offset([offset]) · [Source](https://github.com/d3/d3-shape/blob/master/src/stack.js)
+
+If *offset* is specified, sets the offset accessor to the specified function and returns this stack generator. If *offset* is not specified, returns the current offset acccesor, which defaults to [stackOffsetNone](#stackOffsetNone); this uses a zero baseline. See [stack offsets](#stack-offsets) for the built-in offsets.
+
+The offset function is passed the generated series array and the order index array; it is then responsible for updating the lower and upper values in the series array. For example, the default offset is defined as:
+
+```js
+function offsetNone(series, order) {
+ if (!((n = series.length) > 1)) return;
+ for (let i = 1, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
+ s0 = s1, s1 = series[order[i]];
+ for (let j = 0; j < m; ++j) {
+ s1[j][1] += s1[j][0] = s0[j][1];
+ }
+ }
+}
+```
+
+### Stack Orders
+
+Stack orders are typically not used directly, but are instead passed to [*stack*.order](#stack_order).
+
+# d3.stackOrderAppearance(series) · [Source](https://github.com/d3/d3-shape/blob/master/src/order/appearance.js)
+
+Returns a series order such that the earliest series (according to the maximum value) is at the bottom.
+
+# d3.stackOrderAscending(series) · [Source](https://github.com/d3/d3-shape/blob/master/src/order/ascending.js)
+
+Returns a series order such that the smallest series (according to the sum of values) is at the bottom.
+
+# d3.stackOrderDescending(series) · [Source](https://github.com/d3/d3-shape/blob/master/src/order/descending.js)
+
+Returns a series order such that the largest series (according to the sum of values) is at the bottom.
+
+# d3.stackOrderInsideOut(series) · [Source](https://github.com/d3/d3-shape/blob/master/src/order/insideOut.js)
+
+Returns a series order such that the earliest series (according to the maximum value) are on the inside and the later series are on the outside. This order is recommended for streamgraphs in conjunction with the [wiggle offset](#stackOffsetWiggle). See [Stacked Graphs—Geometry & Aesthetics](http://leebyron.com/streamgraph/) by Byron & Wattenberg for more information.
+
+# d3.stackOrderNone(series) · [Source](https://github.com/d3/d3-shape/blob/master/src/order/none.js)
+
+Returns the given series order [0, 1, … *n* - 1] where *n* is the number of elements in *series*. Thus, the stack order is given by the [key accessor](#stack_keys).
+
+# d3.stackOrderReverse(series) · [Source](https://github.com/d3/d3-shape/blob/master/src/order/reverse.js)
+
+Returns the reverse of the given series order [*n* - 1, *n* - 2, … 0] where *n* is the number of elements in *series*. Thus, the stack order is given by the reverse of the [key accessor](#stack_keys).
+
+### Stack Offsets
+
+Stack offsets are typically not used directly, but are instead passed to [*stack*.offset](#stack_offset).
+
+# d3.stackOffsetExpand(series, order) · [Source](https://github.com/d3/d3-shape/blob/master/src/offset/expand.js)
+
+Applies a zero baseline and normalizes the values for each point such that the topline is always one.
+
+# d3.stackOffsetDiverging(series, order) · [Source](https://github.com/d3/d3-shape/blob/master/src/offset/diverging.js)
+
+Positive values are stacked above zero, negative values are [stacked below zero](https://bl.ocks.org/mbostock/b5935342c6d21928111928401e2c8608), and zero values are stacked at zero.
+
+# d3.stackOffsetNone(series, order) · [Source](https://github.com/d3/d3-shape/blob/master/src/offset/none.js)
+
+Applies a zero baseline.
+
+# d3.stackOffsetSilhouette(series, order) · [Source](https://github.com/d3/d3-shape/blob/master/src/offset/silhouette.js)
+
+Shifts the baseline down such that the center of the streamgraph is always at zero.
+
+# d3.stackOffsetWiggle(series, order) · [Source](https://github.com/d3/d3-shape/blob/master/src/offset/wiggle.js)
+
+Shifts the baseline so as to minimize the weighted wiggle of layers. This offset is recommended for streamgraphs in conjunction with the [inside-out order](#stackOrderInsideOut). See [Stacked Graphs—Geometry & Aesthetics](http://leebyron.com/streamgraph/) by Bryon & Wattenberg for more information.
diff --git a/node_modules/d3-shape/dist/d3-shape.js b/node_modules/d3-shape/dist/d3-shape.js
new file mode 100644
index 00000000..cb6f4157
--- /dev/null
+++ b/node_modules/d3-shape/dist/d3-shape.js
@@ -0,0 +1,2006 @@
+// https://d3js.org/d3-shape/ v2.1.0 Copyright 2021 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-path')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-path'], factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}, global.d3));
+}(this, (function (exports, d3Path) { 'use strict';
+
+function constant(x) {
+ return function constant() {
+ return x;
+ };
+}
+
+var abs = Math.abs;
+var atan2 = Math.atan2;
+var cos = Math.cos;
+var max = Math.max;
+var min = Math.min;
+var sin = Math.sin;
+var sqrt = Math.sqrt;
+
+var epsilon = 1e-12;
+var pi = Math.PI;
+var halfPi = pi / 2;
+var tau = 2 * pi;
+
+function acos(x) {
+ return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
+}
+
+function asin(x) {
+ return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x);
+}
+
+function arcInnerRadius(d) {
+ return d.innerRadius;
+}
+
+function arcOuterRadius(d) {
+ return d.outerRadius;
+}
+
+function arcStartAngle(d) {
+ return d.startAngle;
+}
+
+function arcEndAngle(d) {
+ return d.endAngle;
+}
+
+function arcPadAngle(d) {
+ return d && d.padAngle; // Note: optional!
+}
+
+function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
+ var x10 = x1 - x0, y10 = y1 - y0,
+ x32 = x3 - x2, y32 = y3 - y2,
+ t = y32 * x10 - x32 * y10;
+ if (t * t < epsilon) return;
+ t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
+ return [x0 + t * x10, y0 + t * y10];
+}
+
+// Compute perpendicular offset line of length rc.
+// http://mathworld.wolfram.com/Circle-LineIntersection.html
+function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
+ var x01 = x0 - x1,
+ y01 = y0 - y1,
+ lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01),
+ ox = lo * y01,
+ oy = -lo * x01,
+ x11 = x0 + ox,
+ y11 = y0 + oy,
+ x10 = x1 + ox,
+ y10 = y1 + oy,
+ x00 = (x11 + x10) / 2,
+ y00 = (y11 + y10) / 2,
+ dx = x10 - x11,
+ dy = y10 - y11,
+ d2 = dx * dx + dy * dy,
+ r = r1 - rc,
+ D = x11 * y10 - x10 * y11,
+ d = (dy < 0 ? -1 : 1) * sqrt(max(0, r * r * d2 - D * D)),
+ cx0 = (D * dy - dx * d) / d2,
+ cy0 = (-D * dx - dy * d) / d2,
+ cx1 = (D * dy + dx * d) / d2,
+ cy1 = (-D * dx + dy * d) / d2,
+ dx0 = cx0 - x00,
+ dy0 = cy0 - y00,
+ dx1 = cx1 - x00,
+ dy1 = cy1 - y00;
+
+ // Pick the closer of the two intersection points.
+ // TODO Is there a faster way to determine which intersection to use?
+ if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
+
+ return {
+ cx: cx0,
+ cy: cy0,
+ x01: -ox,
+ y01: -oy,
+ x11: cx0 * (r1 / r - 1),
+ y11: cy0 * (r1 / r - 1)
+ };
+}
+
+function arc() {
+ var innerRadius = arcInnerRadius,
+ outerRadius = arcOuterRadius,
+ cornerRadius = constant(0),
+ padRadius = null,
+ startAngle = arcStartAngle,
+ endAngle = arcEndAngle,
+ padAngle = arcPadAngle,
+ context = null;
+
+ function arc() {
+ var buffer,
+ r,
+ r0 = +innerRadius.apply(this, arguments),
+ r1 = +outerRadius.apply(this, arguments),
+ a0 = startAngle.apply(this, arguments) - halfPi,
+ a1 = endAngle.apply(this, arguments) - halfPi,
+ da = abs(a1 - a0),
+ cw = a1 > a0;
+
+ if (!context) context = buffer = d3Path.path();
+
+ // Ensure that the outer radius is always larger than the inner radius.
+ if (r1 < r0) r = r1, r1 = r0, r0 = r;
+
+ // Is it a point?
+ if (!(r1 > epsilon)) context.moveTo(0, 0);
+
+ // Or is it a circle or annulus?
+ else if (da > tau - epsilon) {
+ context.moveTo(r1 * cos(a0), r1 * sin(a0));
+ context.arc(0, 0, r1, a0, a1, !cw);
+ if (r0 > epsilon) {
+ context.moveTo(r0 * cos(a1), r0 * sin(a1));
+ context.arc(0, 0, r0, a1, a0, cw);
+ }
+ }
+
+ // Or is it a circular or annular sector?
+ else {
+ var a01 = a0,
+ a11 = a1,
+ a00 = a0,
+ a10 = a1,
+ da0 = da,
+ da1 = da,
+ ap = padAngle.apply(this, arguments) / 2,
+ rp = (ap > epsilon) && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)),
+ rc = min(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
+ rc0 = rc,
+ rc1 = rc,
+ t0,
+ t1;
+
+ // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
+ if (rp > epsilon) {
+ var p0 = asin(rp / r0 * sin(ap)),
+ p1 = asin(rp / r1 * sin(ap));
+ if ((da0 -= p0 * 2) > epsilon) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
+ else da0 = 0, a00 = a10 = (a0 + a1) / 2;
+ if ((da1 -= p1 * 2) > epsilon) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
+ else da1 = 0, a01 = a11 = (a0 + a1) / 2;
+ }
+
+ var x01 = r1 * cos(a01),
+ y01 = r1 * sin(a01),
+ x10 = r0 * cos(a10),
+ y10 = r0 * sin(a10);
+
+ // Apply rounded corners?
+ if (rc > epsilon) {
+ var x11 = r1 * cos(a11),
+ y11 = r1 * sin(a11),
+ x00 = r0 * cos(a00),
+ y00 = r0 * sin(a00),
+ oc;
+
+ // Restrict the corner radius according to the sector angle.
+ if (da < pi && (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10))) {
+ var ax = x01 - oc[0],
+ ay = y01 - oc[1],
+ bx = x11 - oc[0],
+ by = y11 - oc[1],
+ kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),
+ lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
+ rc0 = min(rc, (r0 - lc) / (kc - 1));
+ rc1 = min(rc, (r1 - lc) / (kc + 1));
+ }
+ }
+
+ // Is the sector collapsed to a line?
+ if (!(da1 > epsilon)) context.moveTo(x01, y01);
+
+ // Does the sector’s outer ring have rounded corners?
+ else if (rc1 > epsilon) {
+ t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
+ t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
+
+ context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
+
+ // Have the corners merged?
+ if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
+
+ // Otherwise, draw the two corners and the ring.
+ else {
+ context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
+ context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
+ context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
+ }
+ }
+
+ // Or is the outer ring just a circular arc?
+ else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
+
+ // Is there no inner ring, and it’s a circular sector?
+ // Or perhaps it’s an annular sector collapsed due to padding?
+ if (!(r0 > epsilon) || !(da0 > epsilon)) context.lineTo(x10, y10);
+
+ // Does the sector’s inner ring (or point) have rounded corners?
+ else if (rc0 > epsilon) {
+ t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
+ t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
+
+ context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
+
+ // Have the corners merged?
+ if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
+
+ // Otherwise, draw the two corners and the ring.
+ else {
+ context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
+ context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);
+ context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
+ }
+ }
+
+ // Or is the inner ring just a circular arc?
+ else context.arc(0, 0, r0, a10, a00, cw);
+ }
+
+ context.closePath();
+
+ if (buffer) return context = null, buffer + "" || null;
+ }
+
+ arc.centroid = function() {
+ var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
+ a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2;
+ return [cos(a) * r, sin(a) * r];
+ };
+
+ arc.innerRadius = function(_) {
+ return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant(+_), arc) : innerRadius;
+ };
+
+ arc.outerRadius = function(_) {
+ return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant(+_), arc) : outerRadius;
+ };
+
+ arc.cornerRadius = function(_) {
+ return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant(+_), arc) : cornerRadius;
+ };
+
+ arc.padRadius = function(_) {
+ return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant(+_), arc) : padRadius;
+ };
+
+ arc.startAngle = function(_) {
+ return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant(+_), arc) : startAngle;
+ };
+
+ arc.endAngle = function(_) {
+ return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant(+_), arc) : endAngle;
+ };
+
+ arc.padAngle = function(_) {
+ return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant(+_), arc) : padAngle;
+ };
+
+ arc.context = function(_) {
+ return arguments.length ? ((context = _ == null ? null : _), arc) : context;
+ };
+
+ return arc;
+}
+
+var slice = Array.prototype.slice;
+
+function array(x) {
+ return typeof x === "object" && "length" in x
+ ? x // Array, TypedArray, NodeList, array-like
+ : Array.from(x); // Map, Set, iterable, string, or anything else
+}
+
+function Linear(context) {
+ this._context = context;
+}
+
+Linear.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; // proceed
+ default: this._context.lineTo(x, y); break;
+ }
+ }
+};
+
+function curveLinear(context) {
+ return new Linear(context);
+}
+
+function x(p) {
+ return p[0];
+}
+
+function y(p) {
+ return p[1];
+}
+
+function line(x$1, y$1) {
+ var defined = constant(true),
+ context = null,
+ curve = curveLinear,
+ output = null;
+
+ x$1 = typeof x$1 === "function" ? x$1 : (x$1 === undefined) ? x : constant(x$1);
+ y$1 = typeof y$1 === "function" ? y$1 : (y$1 === undefined) ? y : constant(y$1);
+
+ function line(data) {
+ var i,
+ n = (data = array(data)).length,
+ d,
+ defined0 = false,
+ buffer;
+
+ if (context == null) output = curve(buffer = d3Path.path());
+
+ for (i = 0; i <= n; ++i) {
+ if (!(i < n && defined(d = data[i], i, data)) === defined0) {
+ if (defined0 = !defined0) output.lineStart();
+ else output.lineEnd();
+ }
+ if (defined0) output.point(+x$1(d, i, data), +y$1(d, i, data));
+ }
+
+ if (buffer) return output = null, buffer + "" || null;
+ }
+
+ line.x = function(_) {
+ return arguments.length ? (x$1 = typeof _ === "function" ? _ : constant(+_), line) : x$1;
+ };
+
+ line.y = function(_) {
+ return arguments.length ? (y$1 = typeof _ === "function" ? _ : constant(+_), line) : y$1;
+ };
+
+ line.defined = function(_) {
+ return arguments.length ? (defined = typeof _ === "function" ? _ : constant(!!_), line) : defined;
+ };
+
+ line.curve = function(_) {
+ return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
+ };
+
+ line.context = function(_) {
+ return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
+ };
+
+ return line;
+}
+
+function area(x0, y0, y1) {
+ var x1 = null,
+ defined = constant(true),
+ context = null,
+ curve = curveLinear,
+ output = null;
+
+ x0 = typeof x0 === "function" ? x0 : (x0 === undefined) ? x : constant(+x0);
+ y0 = typeof y0 === "function" ? y0 : (y0 === undefined) ? constant(0) : constant(+y0);
+ y1 = typeof y1 === "function" ? y1 : (y1 === undefined) ? y : constant(+y1);
+
+ function area(data) {
+ var i,
+ j,
+ k,
+ n = (data = array(data)).length,
+ d,
+ defined0 = false,
+ buffer,
+ x0z = new Array(n),
+ y0z = new Array(n);
+
+ if (context == null) output = curve(buffer = d3Path.path());
+
+ for (i = 0; i <= n; ++i) {
+ if (!(i < n && defined(d = data[i], i, data)) === defined0) {
+ if (defined0 = !defined0) {
+ j = i;
+ output.areaStart();
+ output.lineStart();
+ } else {
+ output.lineEnd();
+ output.lineStart();
+ for (k = i - 1; k >= j; --k) {
+ output.point(x0z[k], y0z[k]);
+ }
+ output.lineEnd();
+ output.areaEnd();
+ }
+ }
+ if (defined0) {
+ x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
+ output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
+ }
+ }
+
+ if (buffer) return output = null, buffer + "" || null;
+ }
+
+ function arealine() {
+ return line().defined(defined).curve(curve).context(context);
+ }
+
+ area.x = function(_) {
+ return arguments.length ? (x0 = typeof _ === "function" ? _ : constant(+_), x1 = null, area) : x0;
+ };
+
+ area.x0 = function(_) {
+ return arguments.length ? (x0 = typeof _ === "function" ? _ : constant(+_), area) : x0;
+ };
+
+ area.x1 = function(_) {
+ return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant(+_), area) : x1;
+ };
+
+ area.y = function(_) {
+ return arguments.length ? (y0 = typeof _ === "function" ? _ : constant(+_), y1 = null, area) : y0;
+ };
+
+ area.y0 = function(_) {
+ return arguments.length ? (y0 = typeof _ === "function" ? _ : constant(+_), area) : y0;
+ };
+
+ area.y1 = function(_) {
+ return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant(+_), area) : y1;
+ };
+
+ area.lineX0 =
+ area.lineY0 = function() {
+ return arealine().x(x0).y(y0);
+ };
+
+ area.lineY1 = function() {
+ return arealine().x(x0).y(y1);
+ };
+
+ area.lineX1 = function() {
+ return arealine().x(x1).y(y0);
+ };
+
+ area.defined = function(_) {
+ return arguments.length ? (defined = typeof _ === "function" ? _ : constant(!!_), area) : defined;
+ };
+
+ area.curve = function(_) {
+ return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;
+ };
+
+ area.context = function(_) {
+ return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
+ };
+
+ return area;
+}
+
+function descending$1(a, b) {
+ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+}
+
+function identity(d) {
+ return d;
+}
+
+function pie() {
+ var value = identity,
+ sortValues = descending$1,
+ sort = null,
+ startAngle = constant(0),
+ endAngle = constant(tau),
+ padAngle = constant(0);
+
+ function pie(data) {
+ var i,
+ n = (data = array(data)).length,
+ j,
+ k,
+ sum = 0,
+ index = new Array(n),
+ arcs = new Array(n),
+ a0 = +startAngle.apply(this, arguments),
+ da = Math.min(tau, Math.max(-tau, endAngle.apply(this, arguments) - a0)),
+ a1,
+ p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
+ pa = p * (da < 0 ? -1 : 1),
+ v;
+
+ for (i = 0; i < n; ++i) {
+ if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
+ sum += v;
+ }
+ }
+
+ // Optionally sort the arcs by previously-computed values or by data.
+ if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
+ else if (sort != null) index.sort(function(i, j) { return sort(data[i], data[j]); });
+
+ // Compute the arcs! They are stored in the original data's order.
+ for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
+ j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
+ data: data[j],
+ index: i,
+ value: v,
+ startAngle: a0,
+ endAngle: a1,
+ padAngle: p
+ };
+ }
+
+ return arcs;
+ }
+
+ pie.value = function(_) {
+ return arguments.length ? (value = typeof _ === "function" ? _ : constant(+_), pie) : value;
+ };
+
+ pie.sortValues = function(_) {
+ return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
+ };
+
+ pie.sort = function(_) {
+ return arguments.length ? (sort = _, sortValues = null, pie) : sort;
+ };
+
+ pie.startAngle = function(_) {
+ return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant(+_), pie) : startAngle;
+ };
+
+ pie.endAngle = function(_) {
+ return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant(+_), pie) : endAngle;
+ };
+
+ pie.padAngle = function(_) {
+ return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant(+_), pie) : padAngle;
+ };
+
+ return pie;
+}
+
+var curveRadialLinear = curveRadial$1(curveLinear);
+
+function Radial(curve) {
+ this._curve = curve;
+}
+
+Radial.prototype = {
+ areaStart: function() {
+ this._curve.areaStart();
+ },
+ areaEnd: function() {
+ this._curve.areaEnd();
+ },
+ lineStart: function() {
+ this._curve.lineStart();
+ },
+ lineEnd: function() {
+ this._curve.lineEnd();
+ },
+ point: function(a, r) {
+ this._curve.point(r * Math.sin(a), r * -Math.cos(a));
+ }
+};
+
+function curveRadial$1(curve) {
+
+ function radial(context) {
+ return new Radial(curve(context));
+ }
+
+ radial._curve = curve;
+
+ return radial;
+}
+
+function lineRadial(l) {
+ var c = l.curve;
+
+ l.angle = l.x, delete l.x;
+ l.radius = l.y, delete l.y;
+
+ l.curve = function(_) {
+ return arguments.length ? c(curveRadial$1(_)) : c()._curve;
+ };
+
+ return l;
+}
+
+function lineRadial$1() {
+ return lineRadial(line().curve(curveRadialLinear));
+}
+
+function areaRadial() {
+ var a = area().curve(curveRadialLinear),
+ c = a.curve,
+ x0 = a.lineX0,
+ x1 = a.lineX1,
+ y0 = a.lineY0,
+ y1 = a.lineY1;
+
+ a.angle = a.x, delete a.x;
+ a.startAngle = a.x0, delete a.x0;
+ a.endAngle = a.x1, delete a.x1;
+ a.radius = a.y, delete a.y;
+ a.innerRadius = a.y0, delete a.y0;
+ a.outerRadius = a.y1, delete a.y1;
+ a.lineStartAngle = function() { return lineRadial(x0()); }, delete a.lineX0;
+ a.lineEndAngle = function() { return lineRadial(x1()); }, delete a.lineX1;
+ a.lineInnerRadius = function() { return lineRadial(y0()); }, delete a.lineY0;
+ a.lineOuterRadius = function() { return lineRadial(y1()); }, delete a.lineY1;
+
+ a.curve = function(_) {
+ return arguments.length ? c(curveRadial$1(_)) : c()._curve;
+ };
+
+ return a;
+}
+
+function pointRadial(x, y) {
+ return [(y = +y) * Math.cos(x -= Math.PI / 2), y * Math.sin(x)];
+}
+
+function linkSource(d) {
+ return d.source;
+}
+
+function linkTarget(d) {
+ return d.target;
+}
+
+function link(curve) {
+ var source = linkSource,
+ target = linkTarget,
+ x$1 = x,
+ y$1 = y,
+ context = null;
+
+ function link() {
+ var buffer, argv = slice.call(arguments), s = source.apply(this, argv), t = target.apply(this, argv);
+ if (!context) context = buffer = d3Path.path();
+ curve(context, +x$1.apply(this, (argv[0] = s, argv)), +y$1.apply(this, argv), +x$1.apply(this, (argv[0] = t, argv)), +y$1.apply(this, argv));
+ if (buffer) return context = null, buffer + "" || null;
+ }
+
+ link.source = function(_) {
+ return arguments.length ? (source = _, link) : source;
+ };
+
+ link.target = function(_) {
+ return arguments.length ? (target = _, link) : target;
+ };
+
+ link.x = function(_) {
+ return arguments.length ? (x$1 = typeof _ === "function" ? _ : constant(+_), link) : x$1;
+ };
+
+ link.y = function(_) {
+ return arguments.length ? (y$1 = typeof _ === "function" ? _ : constant(+_), link) : y$1;
+ };
+
+ link.context = function(_) {
+ return arguments.length ? ((context = _ == null ? null : _), link) : context;
+ };
+
+ return link;
+}
+
+function curveHorizontal(context, x0, y0, x1, y1) {
+ context.moveTo(x0, y0);
+ context.bezierCurveTo(x0 = (x0 + x1) / 2, y0, x0, y1, x1, y1);
+}
+
+function curveVertical(context, x0, y0, x1, y1) {
+ context.moveTo(x0, y0);
+ context.bezierCurveTo(x0, y0 = (y0 + y1) / 2, x1, y0, x1, y1);
+}
+
+function curveRadial(context, x0, y0, x1, y1) {
+ var p0 = pointRadial(x0, y0),
+ p1 = pointRadial(x0, y0 = (y0 + y1) / 2),
+ p2 = pointRadial(x1, y0),
+ p3 = pointRadial(x1, y1);
+ context.moveTo(p0[0], p0[1]);
+ context.bezierCurveTo(p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);
+}
+
+function linkHorizontal() {
+ return link(curveHorizontal);
+}
+
+function linkVertical() {
+ return link(curveVertical);
+}
+
+function linkRadial() {
+ var l = link(curveRadial);
+ l.angle = l.x, delete l.x;
+ l.radius = l.y, delete l.y;
+ return l;
+}
+
+var circle = {
+ draw: function(context, size) {
+ var r = Math.sqrt(size / pi);
+ context.moveTo(r, 0);
+ context.arc(0, 0, r, 0, tau);
+ }
+};
+
+var cross = {
+ draw: function(context, size) {
+ var r = Math.sqrt(size / 5) / 2;
+ context.moveTo(-3 * r, -r);
+ context.lineTo(-r, -r);
+ context.lineTo(-r, -3 * r);
+ context.lineTo(r, -3 * r);
+ context.lineTo(r, -r);
+ context.lineTo(3 * r, -r);
+ context.lineTo(3 * r, r);
+ context.lineTo(r, r);
+ context.lineTo(r, 3 * r);
+ context.lineTo(-r, 3 * r);
+ context.lineTo(-r, r);
+ context.lineTo(-3 * r, r);
+ context.closePath();
+ }
+};
+
+var tan30 = Math.sqrt(1 / 3),
+ tan30_2 = tan30 * 2;
+
+var diamond = {
+ draw: function(context, size) {
+ var y = Math.sqrt(size / tan30_2),
+ x = y * tan30;
+ context.moveTo(0, -y);
+ context.lineTo(x, 0);
+ context.lineTo(0, y);
+ context.lineTo(-x, 0);
+ context.closePath();
+ }
+};
+
+var ka = 0.89081309152928522810,
+ kr = Math.sin(pi / 10) / Math.sin(7 * pi / 10),
+ kx = Math.sin(tau / 10) * kr,
+ ky = -Math.cos(tau / 10) * kr;
+
+var star = {
+ draw: function(context, size) {
+ var r = Math.sqrt(size * ka),
+ x = kx * r,
+ y = ky * r;
+ context.moveTo(0, -r);
+ context.lineTo(x, y);
+ for (var i = 1; i < 5; ++i) {
+ var a = tau * i / 5,
+ c = Math.cos(a),
+ s = Math.sin(a);
+ context.lineTo(s * r, -c * r);
+ context.lineTo(c * x - s * y, s * x + c * y);
+ }
+ context.closePath();
+ }
+};
+
+var square = {
+ draw: function(context, size) {
+ var w = Math.sqrt(size),
+ x = -w / 2;
+ context.rect(x, x, w, w);
+ }
+};
+
+var sqrt3 = Math.sqrt(3);
+
+var triangle = {
+ draw: function(context, size) {
+ var y = -Math.sqrt(size / (sqrt3 * 3));
+ context.moveTo(0, y * 2);
+ context.lineTo(-sqrt3 * y, -y);
+ context.lineTo(sqrt3 * y, -y);
+ context.closePath();
+ }
+};
+
+var c = -0.5,
+ s = Math.sqrt(3) / 2,
+ k = 1 / Math.sqrt(12),
+ a = (k / 2 + 1) * 3;
+
+var wye = {
+ draw: function(context, size) {
+ var r = Math.sqrt(size / a),
+ x0 = r / 2,
+ y0 = r * k,
+ x1 = x0,
+ y1 = r * k + r,
+ x2 = -x1,
+ y2 = y1;
+ context.moveTo(x0, y0);
+ context.lineTo(x1, y1);
+ context.lineTo(x2, y2);
+ context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
+ context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
+ context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
+ context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
+ context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
+ context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
+ context.closePath();
+ }
+};
+
+var symbols = [
+ circle,
+ cross,
+ diamond,
+ square,
+ star,
+ triangle,
+ wye
+];
+
+function symbol(type, size) {
+ var context = null;
+ type = typeof type === "function" ? type : constant(type || circle);
+ size = typeof size === "function" ? size : constant(size === undefined ? 64 : +size);
+
+ function symbol() {
+ var buffer;
+ if (!context) context = buffer = d3Path.path();
+ type.apply(this, arguments).draw(context, +size.apply(this, arguments));
+ if (buffer) return context = null, buffer + "" || null;
+ }
+
+ symbol.type = function(_) {
+ return arguments.length ? (type = typeof _ === "function" ? _ : constant(_), symbol) : type;
+ };
+
+ symbol.size = function(_) {
+ return arguments.length ? (size = typeof _ === "function" ? _ : constant(+_), symbol) : size;
+ };
+
+ symbol.context = function(_) {
+ return arguments.length ? (context = _ == null ? null : _, symbol) : context;
+ };
+
+ return symbol;
+}
+
+function noop() {}
+
+function point$3(that, x, y) {
+ that._context.bezierCurveTo(
+ (2 * that._x0 + that._x1) / 3,
+ (2 * that._y0 + that._y1) / 3,
+ (that._x0 + 2 * that._x1) / 3,
+ (that._y0 + 2 * that._y1) / 3,
+ (that._x0 + 4 * that._x1 + x) / 6,
+ (that._y0 + 4 * that._y1 + y) / 6
+ );
+}
+
+function Basis(context) {
+ this._context = context;
+}
+
+Basis.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 =
+ this._y0 = this._y1 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 3: point$3(this, this._x1, this._y1); // proceed
+ case 2: this._context.lineTo(this._x1, this._y1); break;
+ }
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed
+ default: point$3(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = x;
+ this._y0 = this._y1, this._y1 = y;
+ }
+};
+
+function basis(context) {
+ return new Basis(context);
+}
+
+function BasisClosed(context) {
+ this._context = context;
+}
+
+BasisClosed.prototype = {
+ areaStart: noop,
+ areaEnd: noop,
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
+ this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 1: {
+ this._context.moveTo(this._x2, this._y2);
+ this._context.closePath();
+ break;
+ }
+ case 2: {
+ this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);
+ this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);
+ this._context.closePath();
+ break;
+ }
+ case 3: {
+ this.point(this._x2, this._y2);
+ this.point(this._x3, this._y3);
+ this.point(this._x4, this._y4);
+ break;
+ }
+ }
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
+ case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
+ case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;
+ default: point$3(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = x;
+ this._y0 = this._y1, this._y1 = y;
+ }
+};
+
+function basisClosed(context) {
+ return new BasisClosed(context);
+}
+
+function BasisOpen(context) {
+ this._context = context;
+}
+
+BasisOpen.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 =
+ this._y0 = this._y1 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;
+ case 3: this._point = 4; // proceed
+ default: point$3(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = x;
+ this._y0 = this._y1, this._y1 = y;
+ }
+};
+
+function basisOpen(context) {
+ return new BasisOpen(context);
+}
+
+class Bump {
+ constructor(context, x) {
+ this._context = context;
+ this._x = x;
+ }
+ areaStart() {
+ this._line = 0;
+ }
+ areaEnd() {
+ this._line = NaN;
+ }
+ lineStart() {
+ this._point = 0;
+ }
+ lineEnd() {
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ }
+ point(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: {
+ this._point = 1;
+ if (this._line) this._context.lineTo(x, y);
+ else this._context.moveTo(x, y);
+ break;
+ }
+ case 1: this._point = 2; // proceed
+ default: {
+ if (this._x) this._context.bezierCurveTo(this._x0 = (this._x0 + x) / 2, this._y0, this._x0, y, x, y);
+ else this._context.bezierCurveTo(this._x0, this._y0 = (this._y0 + y) / 2, x, this._y0, x, y);
+ break;
+ }
+ }
+ this._x0 = x, this._y0 = y;
+ }
+}
+
+function bumpX(context) {
+ return new Bump(context, true);
+}
+
+function bumpY(context) {
+ return new Bump(context, false);
+}
+
+function Bundle(context, beta) {
+ this._basis = new Basis(context);
+ this._beta = beta;
+}
+
+Bundle.prototype = {
+ lineStart: function() {
+ this._x = [];
+ this._y = [];
+ this._basis.lineStart();
+ },
+ lineEnd: function() {
+ var x = this._x,
+ y = this._y,
+ j = x.length - 1;
+
+ if (j > 0) {
+ var x0 = x[0],
+ y0 = y[0],
+ dx = x[j] - x0,
+ dy = y[j] - y0,
+ i = -1,
+ t;
+
+ while (++i <= j) {
+ t = i / j;
+ this._basis.point(
+ this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
+ this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
+ );
+ }
+ }
+
+ this._x = this._y = null;
+ this._basis.lineEnd();
+ },
+ point: function(x, y) {
+ this._x.push(+x);
+ this._y.push(+y);
+ }
+};
+
+var bundle = (function custom(beta) {
+
+ function bundle(context) {
+ return beta === 1 ? new Basis(context) : new Bundle(context, beta);
+ }
+
+ bundle.beta = function(beta) {
+ return custom(+beta);
+ };
+
+ return bundle;
+})(0.85);
+
+function point$2(that, x, y) {
+ that._context.bezierCurveTo(
+ that._x1 + that._k * (that._x2 - that._x0),
+ that._y1 + that._k * (that._y2 - that._y0),
+ that._x2 + that._k * (that._x1 - x),
+ that._y2 + that._k * (that._y1 - y),
+ that._x2,
+ that._y2
+ );
+}
+
+function Cardinal(context, tension) {
+ this._context = context;
+ this._k = (1 - tension) / 6;
+}
+
+Cardinal.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 =
+ this._y0 = this._y1 = this._y2 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 2: this._context.lineTo(this._x2, this._y2); break;
+ case 3: point$2(this, this._x1, this._y1); break;
+ }
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
+ case 2: this._point = 3; // proceed
+ default: point$2(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var cardinal = (function custom(tension) {
+
+ function cardinal(context) {
+ return new Cardinal(context, tension);
+ }
+
+ cardinal.tension = function(tension) {
+ return custom(+tension);
+ };
+
+ return cardinal;
+})(0);
+
+function CardinalClosed(context, tension) {
+ this._context = context;
+ this._k = (1 - tension) / 6;
+}
+
+CardinalClosed.prototype = {
+ areaStart: noop,
+ areaEnd: noop,
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
+ this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 1: {
+ this._context.moveTo(this._x3, this._y3);
+ this._context.closePath();
+ break;
+ }
+ case 2: {
+ this._context.lineTo(this._x3, this._y3);
+ this._context.closePath();
+ break;
+ }
+ case 3: {
+ this.point(this._x3, this._y3);
+ this.point(this._x4, this._y4);
+ this.point(this._x5, this._y5);
+ break;
+ }
+ }
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
+ case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
+ case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
+ default: point$2(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var cardinalClosed = (function custom(tension) {
+
+ function cardinal(context) {
+ return new CardinalClosed(context, tension);
+ }
+
+ cardinal.tension = function(tension) {
+ return custom(+tension);
+ };
+
+ return cardinal;
+})(0);
+
+function CardinalOpen(context, tension) {
+ this._context = context;
+ this._k = (1 - tension) / 6;
+}
+
+CardinalOpen.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 =
+ this._y0 = this._y1 = this._y2 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
+ case 3: this._point = 4; // proceed
+ default: point$2(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var cardinalOpen = (function custom(tension) {
+
+ function cardinal(context) {
+ return new CardinalOpen(context, tension);
+ }
+
+ cardinal.tension = function(tension) {
+ return custom(+tension);
+ };
+
+ return cardinal;
+})(0);
+
+function point$1(that, x, y) {
+ var x1 = that._x1,
+ y1 = that._y1,
+ x2 = that._x2,
+ y2 = that._y2;
+
+ if (that._l01_a > epsilon) {
+ var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
+ n = 3 * that._l01_a * (that._l01_a + that._l12_a);
+ x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
+ y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
+ }
+
+ if (that._l23_a > epsilon) {
+ var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
+ m = 3 * that._l23_a * (that._l23_a + that._l12_a);
+ x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
+ y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;
+ }
+
+ that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);
+}
+
+function CatmullRom(context, alpha) {
+ this._context = context;
+ this._alpha = alpha;
+}
+
+CatmullRom.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 =
+ this._y0 = this._y1 = this._y2 = NaN;
+ this._l01_a = this._l12_a = this._l23_a =
+ this._l01_2a = this._l12_2a = this._l23_2a =
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 2: this._context.lineTo(this._x2, this._y2); break;
+ case 3: this.point(this._x2, this._y2); break;
+ }
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+
+ if (this._point) {
+ var x23 = this._x2 - x,
+ y23 = this._y2 - y;
+ this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
+ }
+
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; // proceed
+ default: point$1(this, x, y); break;
+ }
+
+ this._l01_a = this._l12_a, this._l12_a = this._l23_a;
+ this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var catmullRom = (function custom(alpha) {
+
+ function catmullRom(context) {
+ return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);
+ }
+
+ catmullRom.alpha = function(alpha) {
+ return custom(+alpha);
+ };
+
+ return catmullRom;
+})(0.5);
+
+function CatmullRomClosed(context, alpha) {
+ this._context = context;
+ this._alpha = alpha;
+}
+
+CatmullRomClosed.prototype = {
+ areaStart: noop,
+ areaEnd: noop,
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
+ this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
+ this._l01_a = this._l12_a = this._l23_a =
+ this._l01_2a = this._l12_2a = this._l23_2a =
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 1: {
+ this._context.moveTo(this._x3, this._y3);
+ this._context.closePath();
+ break;
+ }
+ case 2: {
+ this._context.lineTo(this._x3, this._y3);
+ this._context.closePath();
+ break;
+ }
+ case 3: {
+ this.point(this._x3, this._y3);
+ this.point(this._x4, this._y4);
+ this.point(this._x5, this._y5);
+ break;
+ }
+ }
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+
+ if (this._point) {
+ var x23 = this._x2 - x,
+ y23 = this._y2 - y;
+ this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
+ }
+
+ switch (this._point) {
+ case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
+ case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
+ case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
+ default: point$1(this, x, y); break;
+ }
+
+ this._l01_a = this._l12_a, this._l12_a = this._l23_a;
+ this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var catmullRomClosed = (function custom(alpha) {
+
+ function catmullRom(context) {
+ return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);
+ }
+
+ catmullRom.alpha = function(alpha) {
+ return custom(+alpha);
+ };
+
+ return catmullRom;
+})(0.5);
+
+function CatmullRomOpen(context, alpha) {
+ this._context = context;
+ this._alpha = alpha;
+}
+
+CatmullRomOpen.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 =
+ this._y0 = this._y1 = this._y2 = NaN;
+ this._l01_a = this._l12_a = this._l23_a =
+ this._l01_2a = this._l12_2a = this._l23_2a =
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+
+ if (this._point) {
+ var x23 = this._x2 - x,
+ y23 = this._y2 - y;
+ this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
+ }
+
+ switch (this._point) {
+ case 0: this._point = 1; break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
+ case 3: this._point = 4; // proceed
+ default: point$1(this, x, y); break;
+ }
+
+ this._l01_a = this._l12_a, this._l12_a = this._l23_a;
+ this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var catmullRomOpen = (function custom(alpha) {
+
+ function catmullRom(context) {
+ return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);
+ }
+
+ catmullRom.alpha = function(alpha) {
+ return custom(+alpha);
+ };
+
+ return catmullRom;
+})(0.5);
+
+function LinearClosed(context) {
+ this._context = context;
+}
+
+LinearClosed.prototype = {
+ areaStart: noop,
+ areaEnd: noop,
+ lineStart: function() {
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._point) this._context.closePath();
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ if (this._point) this._context.lineTo(x, y);
+ else this._point = 1, this._context.moveTo(x, y);
+ }
+};
+
+function linearClosed(context) {
+ return new LinearClosed(context);
+}
+
+function sign(x) {
+ return x < 0 ? -1 : 1;
+}
+
+// Calculate the slopes of the tangents (Hermite-type interpolation) based on
+// the following paper: Steffen, M. 1990. A Simple Method for Monotonic
+// Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.
+// NOV(II), P. 443, 1990.
+function slope3(that, x2, y2) {
+ var h0 = that._x1 - that._x0,
+ h1 = x2 - that._x1,
+ s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),
+ s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),
+ p = (s0 * h1 + s1 * h0) / (h0 + h1);
+ return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
+}
+
+// Calculate a one-sided slope.
+function slope2(that, t) {
+ var h = that._x1 - that._x0;
+ return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
+}
+
+// According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
+// "you can express cubic Hermite interpolation in terms of cubic Bézier curves
+// with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
+function point(that, t0, t1) {
+ var x0 = that._x0,
+ y0 = that._y0,
+ x1 = that._x1,
+ y1 = that._y1,
+ dx = (x1 - x0) / 3;
+ that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
+}
+
+function MonotoneX(context) {
+ this._context = context;
+}
+
+MonotoneX.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 =
+ this._y0 = this._y1 =
+ this._t0 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 2: this._context.lineTo(this._x1, this._y1); break;
+ case 3: point(this, this._t0, slope2(this, this._t0)); break;
+ }
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ var t1 = NaN;
+
+ x = +x, y = +y;
+ if (x === this._x1 && y === this._y1) return; // Ignore coincident points.
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; point(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
+ default: point(this, this._t0, t1 = slope3(this, x, y)); break;
+ }
+
+ this._x0 = this._x1, this._x1 = x;
+ this._y0 = this._y1, this._y1 = y;
+ this._t0 = t1;
+ }
+};
+
+function MonotoneY(context) {
+ this._context = new ReflectContext(context);
+}
+
+(MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {
+ MonotoneX.prototype.point.call(this, y, x);
+};
+
+function ReflectContext(context) {
+ this._context = context;
+}
+
+ReflectContext.prototype = {
+ moveTo: function(x, y) { this._context.moveTo(y, x); },
+ closePath: function() { this._context.closePath(); },
+ lineTo: function(x, y) { this._context.lineTo(y, x); },
+ bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }
+};
+
+function monotoneX(context) {
+ return new MonotoneX(context);
+}
+
+function monotoneY(context) {
+ return new MonotoneY(context);
+}
+
+function Natural(context) {
+ this._context = context;
+}
+
+Natural.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x = [];
+ this._y = [];
+ },
+ lineEnd: function() {
+ var x = this._x,
+ y = this._y,
+ n = x.length;
+
+ if (n) {
+ this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);
+ if (n === 2) {
+ this._context.lineTo(x[1], y[1]);
+ } else {
+ var px = controlPoints(x),
+ py = controlPoints(y);
+ for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
+ this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);
+ }
+ }
+ }
+
+ if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ this._x = this._y = null;
+ },
+ point: function(x, y) {
+ this._x.push(+x);
+ this._y.push(+y);
+ }
+};
+
+// See https://www.particleincell.com/2012/bezier-splines/ for derivation.
+function controlPoints(x) {
+ var i,
+ n = x.length - 1,
+ m,
+ a = new Array(n),
+ b = new Array(n),
+ r = new Array(n);
+ a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];
+ for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];
+ a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];
+ for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
+ a[n - 1] = r[n - 1] / b[n - 1];
+ for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
+ b[n - 1] = (x[n] + a[n - 1]) / 2;
+ for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
+ return [a, b];
+}
+
+function natural(context) {
+ return new Natural(context);
+}
+
+function Step(context, t) {
+ this._context = context;
+ this._t = t;
+}
+
+Step.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x = this._y = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; // proceed
+ default: {
+ if (this._t <= 0) {
+ this._context.lineTo(this._x, y);
+ this._context.lineTo(x, y);
+ } else {
+ var x1 = this._x * (1 - this._t) + x * this._t;
+ this._context.lineTo(x1, this._y);
+ this._context.lineTo(x1, y);
+ }
+ break;
+ }
+ }
+ this._x = x, this._y = y;
+ }
+};
+
+function step(context) {
+ return new Step(context, 0.5);
+}
+
+function stepBefore(context) {
+ return new Step(context, 0);
+}
+
+function stepAfter(context) {
+ return new Step(context, 1);
+}
+
+function none$1(series, order) {
+ if (!((n = series.length) > 1)) return;
+ for (var i = 1, j, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
+ s0 = s1, s1 = series[order[i]];
+ for (j = 0; j < m; ++j) {
+ s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];
+ }
+ }
+}
+
+function none(series) {
+ var n = series.length, o = new Array(n);
+ while (--n >= 0) o[n] = n;
+ return o;
+}
+
+function stackValue(d, key) {
+ return d[key];
+}
+
+function stackSeries(key) {
+ const series = [];
+ series.key = key;
+ return series;
+}
+
+function stack() {
+ var keys = constant([]),
+ order = none,
+ offset = none$1,
+ value = stackValue;
+
+ function stack(data) {
+ var sz = Array.from(keys.apply(this, arguments), stackSeries),
+ i, n = sz.length, j = -1,
+ oz;
+
+ for (const d of data) {
+ for (i = 0, ++j; i < n; ++i) {
+ (sz[i][j] = [0, +value(d, sz[i].key, j, data)]).data = d;
+ }
+ }
+
+ for (i = 0, oz = array(order(sz)); i < n; ++i) {
+ sz[oz[i]].index = i;
+ }
+
+ offset(sz, oz);
+ return sz;
+ }
+
+ stack.keys = function(_) {
+ return arguments.length ? (keys = typeof _ === "function" ? _ : constant(Array.from(_)), stack) : keys;
+ };
+
+ stack.value = function(_) {
+ return arguments.length ? (value = typeof _ === "function" ? _ : constant(+_), stack) : value;
+ };
+
+ stack.order = function(_) {
+ return arguments.length ? (order = _ == null ? none : typeof _ === "function" ? _ : constant(Array.from(_)), stack) : order;
+ };
+
+ stack.offset = function(_) {
+ return arguments.length ? (offset = _ == null ? none$1 : _, stack) : offset;
+ };
+
+ return stack;
+}
+
+function expand(series, order) {
+ if (!((n = series.length) > 0)) return;
+ for (var i, n, j = 0, m = series[0].length, y; j < m; ++j) {
+ for (y = i = 0; i < n; ++i) y += series[i][j][1] || 0;
+ if (y) for (i = 0; i < n; ++i) series[i][j][1] /= y;
+ }
+ none$1(series, order);
+}
+
+function diverging(series, order) {
+ if (!((n = series.length) > 0)) return;
+ for (var i, j = 0, d, dy, yp, yn, n, m = series[order[0]].length; j < m; ++j) {
+ for (yp = yn = 0, i = 0; i < n; ++i) {
+ if ((dy = (d = series[order[i]][j])[1] - d[0]) > 0) {
+ d[0] = yp, d[1] = yp += dy;
+ } else if (dy < 0) {
+ d[1] = yn, d[0] = yn += dy;
+ } else {
+ d[0] = 0, d[1] = dy;
+ }
+ }
+ }
+}
+
+function silhouette(series, order) {
+ if (!((n = series.length) > 0)) return;
+ for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {
+ for (var i = 0, y = 0; i < n; ++i) y += series[i][j][1] || 0;
+ s0[j][1] += s0[j][0] = -y / 2;
+ }
+ none$1(series, order);
+}
+
+function wiggle(series, order) {
+ if (!((n = series.length) > 0) || !((m = (s0 = series[order[0]]).length) > 0)) return;
+ for (var y = 0, j = 1, s0, m, n; j < m; ++j) {
+ for (var i = 0, s1 = 0, s2 = 0; i < n; ++i) {
+ var si = series[order[i]],
+ sij0 = si[j][1] || 0,
+ sij1 = si[j - 1][1] || 0,
+ s3 = (sij0 - sij1) / 2;
+ for (var k = 0; k < i; ++k) {
+ var sk = series[order[k]],
+ skj0 = sk[j][1] || 0,
+ skj1 = sk[j - 1][1] || 0;
+ s3 += skj0 - skj1;
+ }
+ s1 += sij0, s2 += s3 * sij0;
+ }
+ s0[j - 1][1] += s0[j - 1][0] = y;
+ if (s1) y -= s2 / s1;
+ }
+ s0[j - 1][1] += s0[j - 1][0] = y;
+ none$1(series, order);
+}
+
+function appearance(series) {
+ var peaks = series.map(peak);
+ return none(series).sort(function(a, b) { return peaks[a] - peaks[b]; });
+}
+
+function peak(series) {
+ var i = -1, j = 0, n = series.length, vi, vj = -Infinity;
+ while (++i < n) if ((vi = +series[i][1]) > vj) vj = vi, j = i;
+ return j;
+}
+
+function ascending(series) {
+ var sums = series.map(sum);
+ return none(series).sort(function(a, b) { return sums[a] - sums[b]; });
+}
+
+function sum(series) {
+ var s = 0, i = -1, n = series.length, v;
+ while (++i < n) if (v = +series[i][1]) s += v;
+ return s;
+}
+
+function descending(series) {
+ return ascending(series).reverse();
+}
+
+function insideOut(series) {
+ var n = series.length,
+ i,
+ j,
+ sums = series.map(sum),
+ order = appearance(series),
+ top = 0,
+ bottom = 0,
+ tops = [],
+ bottoms = [];
+
+ for (i = 0; i < n; ++i) {
+ j = order[i];
+ if (top < bottom) {
+ top += sums[j];
+ tops.push(j);
+ } else {
+ bottom += sums[j];
+ bottoms.push(j);
+ }
+ }
+
+ return bottoms.reverse().concat(tops);
+}
+
+function reverse(series) {
+ return none(series).reverse();
+}
+
+exports.arc = arc;
+exports.area = area;
+exports.areaRadial = areaRadial;
+exports.curveBasis = basis;
+exports.curveBasisClosed = basisClosed;
+exports.curveBasisOpen = basisOpen;
+exports.curveBumpX = bumpX;
+exports.curveBumpY = bumpY;
+exports.curveBundle = bundle;
+exports.curveCardinal = cardinal;
+exports.curveCardinalClosed = cardinalClosed;
+exports.curveCardinalOpen = cardinalOpen;
+exports.curveCatmullRom = catmullRom;
+exports.curveCatmullRomClosed = catmullRomClosed;
+exports.curveCatmullRomOpen = catmullRomOpen;
+exports.curveLinear = curveLinear;
+exports.curveLinearClosed = linearClosed;
+exports.curveMonotoneX = monotoneX;
+exports.curveMonotoneY = monotoneY;
+exports.curveNatural = natural;
+exports.curveStep = step;
+exports.curveStepAfter = stepAfter;
+exports.curveStepBefore = stepBefore;
+exports.line = line;
+exports.lineRadial = lineRadial$1;
+exports.linkHorizontal = linkHorizontal;
+exports.linkRadial = linkRadial;
+exports.linkVertical = linkVertical;
+exports.pie = pie;
+exports.pointRadial = pointRadial;
+exports.radialArea = areaRadial;
+exports.radialLine = lineRadial$1;
+exports.stack = stack;
+exports.stackOffsetDiverging = diverging;
+exports.stackOffsetExpand = expand;
+exports.stackOffsetNone = none$1;
+exports.stackOffsetSilhouette = silhouette;
+exports.stackOffsetWiggle = wiggle;
+exports.stackOrderAppearance = appearance;
+exports.stackOrderAscending = ascending;
+exports.stackOrderDescending = descending;
+exports.stackOrderInsideOut = insideOut;
+exports.stackOrderNone = none;
+exports.stackOrderReverse = reverse;
+exports.symbol = symbol;
+exports.symbolCircle = circle;
+exports.symbolCross = cross;
+exports.symbolDiamond = diamond;
+exports.symbolSquare = square;
+exports.symbolStar = star;
+exports.symbolTriangle = triangle;
+exports.symbolWye = wye;
+exports.symbols = symbols;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/node_modules/d3-shape/dist/d3-shape.min.js b/node_modules/d3-shape/dist/d3-shape.min.js
new file mode 100644
index 00000000..bda24146
--- /dev/null
+++ b/node_modules/d3-shape/dist/d3-shape.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-shape/ v2.1.0 Copyright 2021 Mike Bostock
+!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports,require("d3-path")):"function"==typeof define&&define.amd?define(["exports","d3-path"],i):i((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{},t.d3)}(this,(function(t,i){"use strict";function n(t){return function(){return t}}var e=Math.abs,s=Math.atan2,o=Math.cos,h=Math.max,_=Math.min,r=Math.sin,a=Math.sqrt,c=1e-12,l=Math.PI,u=l/2,f=2*l;function y(t){return t>1?0:t<-1?l:Math.acos(t)}function x(t){return t>=1?u:t<=-1?-u:Math.asin(t)}function p(t){return t.innerRadius}function v(t){return t.outerRadius}function d(t){return t.startAngle}function T(t){return t.endAngle}function g(t){return t&&t.padAngle}function b(t,i,n,e,s,o,h,_){var r=n-t,a=e-i,l=h-s,u=_-o,f=u*r-l*a;if(!(f*f=0;)n[i]=i;return n}function Ht(t,i){return t[i]}function Ft(t){const i=[];return i.key=t,i}function Gt(t){var i=t.map(Jt);return Wt(t).sort((function(t,n){return i[t]-i[n]}))}function Jt(t){for(var i,n=-1,e=0,s=t.length,o=-1/0;++no&&(o=i,e=n);return e}function Kt(t){var i=t.map(Qt);return Wt(t).sort((function(t,n){return i[t]-i[n]}))}function Qt(t){for(var i,n=0,e=-1,s=t.length;++e=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,i){switch(t=+t,i=+i,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,i):this._context.moveTo(t,i);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,i),this._context.lineTo(t,i);else{var n=this._x*(1-this._t)+t*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,i)}}this._x=t,this._y=i}},t.arc=function(){var t=p,h=v,w=n(0),k=null,N=d,M=T,S=g,E=null;function A(){var n,p,v=+t.apply(this,arguments),d=+h.apply(this,arguments),T=N.apply(this,arguments)-u,g=M.apply(this,arguments)-u,A=e(g-T),P=g>T;if(E||(E=n=i.path()),d