aboutsummaryrefslogtreecommitdiff
path: root/static
diff options
context:
space:
mode:
authorAnthony Wang2024-05-08 12:01:05 -0400
committerAnthony Wang2024-05-08 12:01:05 -0400
commit68c7b6e0eb565df8007fa35b4ef77265ab2fef3a (patch)
tree546af2807e516ddcc04c0b6de0439c1492482061 /static
parent9588f4541cd6ffe25fd616152a7f42755116946c (diff)
Fast multipole methods
Diffstat (limited to 'static')
-rw-r--r--static/src/18.335-project.jl1819
1 files changed, 1819 insertions, 0 deletions
diff --git a/static/src/18.335-project.jl b/static/src/18.335-project.jl
new file mode 100644
index 0000000..d3a2699
--- /dev/null
+++ b/static/src/18.335-project.jl
@@ -0,0 +1,1819 @@
+### A Pluto.jl notebook ###
+# v0.19.41
+
+using Markdown
+using InteractiveUtils
+
+# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
+macro bind(def, element)
+ quote
+ local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
+ local el = $(esc(element))
+ global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
+ el
+ end
+end
+
+# ╔═╡ 13a58ade-bfd3-4c7d-b885-933f92815f1d
+begin
+ using PlutoUI
+ using PlutoUI: combine
+ using ShortCodes
+ using Plots
+ # import instead of using to avoid namespace conflicts with Plots
+ import PlotlyJS
+ plotlyjs()
+end
+
+# ╔═╡ 4ca1549e-032b-11ef-20d2-cb42a75438d9
+md"""
+# An Interactive Guide to Fast Multipole Methods
+
+Anthony Wang
+
+This is a Pluto notebook and should be viewed using [Pluto.jl](https://github.com/fonsp/Pluto.jl). It may take a few minutes to load. If the plots start glitching, restart the notebook and try again.
+"""
+
+# ╔═╡ 77ca8f1b-f25c-437d-94fc-31b339a50896
+md"""
+## Introduction
+
+The $n$-body problem is an important problem in computational astrophysics and involves predicting the motions of $n$ objects interacting with each other through gravitational forces. Similar problems arise in other computational physics fields and can be generally stated as follows: Given a set of $A \subset \mathbb{R}^d$ of $n$ target points, a set $B \subset \mathbb{R}^d$ of $n$ source points, a kernel function $G(a,b)$, and a set $\{f(b) \mid b \in B\}$ of weights for each source point, we would like to compute the potential
+
+$$u(a) = \sum_{b \in B} G(a,b)f(b)$$
+
+for each $b \in B$. We can also express this problem in matrix form as
+
+$$\begin{bmatrix}u(a_1)\\u(a_2)\\\vdots\\u(a_n)\end{bmatrix} = \begin{bmatrix}G(a_1,b_1)&G(a_1,b_2)&\dots&G(a_1,b_n)\\G(a_2,b_1)&G(a_2,b_2)&\dots&G(a_2,b_n)\\\vdots&\vdots&\ddots&\dots\\G(a_n,b_1)&G(a_n,b_2)&\dots&G(a_n,b_n)\end{bmatrix}\begin{bmatrix}f(b_1)\\f(b_2)\\\vdots\\f(b_n)\end{bmatrix}$$
+
+or more compactly as
+
+$$U = GF.$$
+
+For the astrophysics $n$-body problem, we have $A = B$ representing the $n$ objects, $f(b)$ is equal to the mass of each object, and $G(a, b) = \frac{1}{|a-b|}$ is the gravitational potential. This potential is usually multiplied by the gravitational constant, but we can make the constant $0$ using some choice of units. This potential is also equal to the gravitational potential energy at that location divided by the mass. To carry out an $n$-body simulation, we actually need to compute the gravitational force on each object, which is the gradient of the potential. Thus, the kernel for the force is $G_F(a, b) = \frac{b-a}{|a-b|^3}$ and is a vector pointing in the direction from $a$ to $b$. Similarly, in electrostatics, the $A$ is the locations of $n$ test probes, $B$ is the locations of $n$ charged particles, $f(b)$ is the charge of each particle, and the kernel for electrical potential is $G(a, b) = \frac{1}{|a-b|}$.
+
+To compute $U = GF$, the obvious solution of doing a matrix-vector multiplication takes $O(n^2)$ time. We can speed this up at the cost of some accuracy by using fast multipole methods (FMMs). The core idea for FMMs is to group together close points and treat them as a single point. FMMs are actually a class of algorithms that can solve other problems such as certain partial differential equations, but we will specifically focus on the gravitational $n$-body problem in this article. Consequently, we will only explore the classical FMM for non-oscillatory kernels, because the gravitational potential is non-oscillatory. For simplicity, our implementation will be for a 2D $n$-body simulation, but the method can be generalized to arbitrary dimensions."""
+
+# ╔═╡ f8b368dd-e8c2-4545-896b-19b797dd54a0
+md"""
+## Naive $O(n^2)$ algorithm
+
+Before delving into fast multipole methods, we will first solve the $n$-body problem using the naive $O(n^2)$ matrix-vector multiplication solution so that we have a baseline to compare our FMM to.
+
+Our simulation will compute the forces $U_F$ on each object and update the positions and velocities of the objects every $\frac{1}{30}$ of a second. Try dragging the sliders to change the starting configuration of the objects.
+"""
+
+# ╔═╡ 39a79b7c-e90f-45ff-b0f1-dad9dfc60326
+# Gravitational potential kernel
+G(a, b) = 1 / sqrt((a.x - b.x)^2 + (a.y - b.y)^2)
+
+# ╔═╡ c03de0c2-6b63-414b-9b14-ff33713ffb7a
+# Gravitational force kernel
+GF(a, b) = 1 / ((a.x - b.x)^2 + (a.y - b.y)^2)^(3 / 2) * [b.x - a.x, b.y - a.y]
+
+# ╔═╡ c79e01d1-c12a-4cc5-b1db-e180bad6fe6b
+# Gravitational potential
+U(a, B) = sum(G(a, b) * b.m for b in B)
+
+# ╔═╡ f3307af3-2f92-47d4-8063-e0e7a30ae917
+# Gravitational force
+UF(a, B) = sum((b != a ? GF(a, b) * b.m : [0, 0]) for b in B)
+
+# ╔═╡ af77440d-7baa-46c2-9036-68760c978234
+begin
+ mutable struct Point
+ m # mass
+ x # x position
+ y # y position
+ vx # x velocity
+ vy # y velocity
+ end
+ Point(a) = Point(a.m, a.x, a.y, a.vx, a.vy)
+ import Base.isequal, Base.hash
+ function isequal(a::Point, b::Point)
+ return a.m == b.m && a.x == b.x && a.y == b.y && a.vx == b.vx && a.vy == b.vy
+ end
+ function hash(a::Point)
+ return hash([a.m, a.x, a.y, a.vx, a.vy])
+ end
+end
+
+# ╔═╡ b0a15759-1a50-4d91-b1fa-8c717bbb2897
+@bind t Clock(1 / 30)
+
+# ╔═╡ 7ddc04a4-5bca-4fc4-9e18-3de693c541a3
+md"""
+## Approximation for a distant cluster of points
+
+For larger $n$, the $O(n^2)$ algorithm is infeasible because we must compute $U$ for each iteration of the $n$-body simulation. Before explaining the fast multipole method, we will first analyze a simpler problem where the target points $A$ and the source points $B$ are separated by a large distance.
+
+When computing the interaction of $B$ with a point $a \in A$, the $O(n^2)$ algorithm sums over the interactions of all $b \in B$ and computes $\sum_{b \in B} G(a,b)f(b)$. Since the $b$ are close together from the point of view of $a$, we can instead approximate the interaction using a single large object $\apx(B)$ with all $b$ contracted to the center of mass of $B$. This object will have mass $f(B) = \sum_{b \in B} f(b)$ and position $\left(\frac{1}{f(B)}\sum_{b \in B} b_xb_m, \frac{1}{f(B)}\sum_{b \in B} b_yb_m\right)$. Thus, we can approximate $u(a)$ as $G(a,\apx(B))f(B)$.
+
+We can also view this approximation as a rank-$1$ approximation of $G$, where the two rank-$1$ matrices are
+
+$$\begin{bmatrix}G(a_1,\apx(B))\\G(a_2,\apx(B))\\\vdots\\G(a_n,\apx(B))\end{bmatrix}\begin{bmatrix}1&1&\dots&1\end{bmatrix}.$$
+
+### Error analysis
+
+We will ignore error due to floating-point arithmetic and instead focus on the error for gravitational potential due to the rank-$1$ approximation. In the visualization below, we have generated $10$ random objects in $[-1, 1] \times [-1, 1]$, and the ratio between the actual potential and approximation is very close to $1$ everywhere except near the origin.
+"""
+
+# ╔═╡ fbb91e4e-46aa-4500-a834-1b45a6fd3b1c
+begin
+ B = [Point(rand(1:10), 2rand() - 1, 2rand() - 1, 0, 0) for _ = 1:10]
+ m = sum(b.m for b in B)
+ b_cm = Point(m, sum(b.x * b.m for b in B) / m, sum(b.y * b.m for b in B) / m, 0, 0)
+end
+
+# ╔═╡ a9dc9e90-5952-40aa-a6c7-28cb874a3ad6
+surface(range(-25, 25, 100), range(-25, 25, 100), (x, y) -> U((x=x, y=y), B) / U((x=x, y=y), [b_cm]), title="Ratio between actual potential and approximation")
+
+# ╔═╡ a2453b84-5ca7-4dd3-862e-5f77a1d37133
+md"""
+For our error analysis, we will assume that $B$ contains $n$ objects each located within a distance of $1$ from the origin, and the mass and center of mass of $B$ are $f(B)$ and $(0,0)$ respectively. The target point $a$ will be located at $(d,0)$ with $d \gg 1$.
+
+The approximated potential is easy to compute and equal to $\frac{f(B)}{d}$. The actual potential is equal to
+
+$$u(a) = \sum_{b \in B} \frac{f_b}{\sqrt{(b_x+d)^2+b_y^2}}.$$
+
+We will first find a lower bound for the actual potential. Expanding the denominator, we get $b_x^2+2b_xd+d^2+b_y^2$. All the $b$ are located within a distance of $1$ from the origin, so $b_x^2+b_y^2 \leq 1$ and $b_x \leq 1$. Thus, $b_x^2+2b_xd+d^2+b_y^2 \leq 1+2d+d^2 = (d+1)^2$, so we get
+
+$$u(a) \geq \sum_{b \in B} \frac{f_b}{\sqrt{(d+1)^2}} = \frac{f(B)}{d+1}.$$
+
+For the upper bound, we know that all squares are positive and $b_x \geq -1$, so $b_x^2+2b_xd+d^2+b_y^2 \geq d^2-2d$. Thus, we get
+
+$$u(a) \leq \sum_{b \in B} \frac{f_b}{\sqrt{d^2-2d}} = \frac{f(B)}{\sqrt{d^2-2d}}.$$
+
+Therefore, for $d \gg 1$, the approximation factor lies between $\left[\frac{\sqrt{d^2-2d}}{d}, \frac{d+1}{d}\right]$, so the error decreases with order $O\left(\frac{1}{d}\right)$ as $d$ increases.
+"""
+
+# ╔═╡ 4d2b08ef-605e-4692-b912-7427c736871c
+plot(range(2, 25, 100), [x -> U((x=x, y=0), B) * sqrt(x^2-2x) / x, x -> U((x=x, y=0), [b_cm]), x -> U((x=x, y=0), B) * (x + 1) / x], title="Bounds for the approximation")
+
+# ╔═╡ fbe936db-94ea-43d3-a245-168cb91be386
+md"""
+## Solving the general case recursively
+
+This simple approximation suggests a general recursive algorithm for the $n$-body problem where $A = B$. We can use our approximation for a cluster of points in $B$ that are far away from $a$. We can then recurse with $a$ and the remaining points in $B$ and find a new faraway cluster. Eventually, $B$ will be left with $O(1)$ points and we can run the naive algorithm.
+
+Formally, we will construct a quadtree on the $n$ points. A quadtree is a tree data structure where each node represents a square and has $4$ children, corresponding to splitting the node's square into $4$ smaller square. The root of the quadtree will be level $1$ and corresponds to a square containing all the points. If the points are not close together, then the number of levels of the quadtree will be small. The plot below shows the first $4$ levels of a quadtree built on $B$.
+"""
+
+# ╔═╡ 62ed1c01-5344-4003-acb3-95c19de4ea9c
+plot(
+ scatter([b.x for b in B], [b.y for b in B], xlim=(-1, 1), ylim=(-1, 1), xticks=range(-1, 1, 2), yticks=range(-1, 1, 2)),
+ scatter([b.x for b in B], [b.y for b in B], xlim=(-1, 1), ylim=(-1, 1), xticks=range(-1, 1, 3), yticks=range(-1, 1, 3)),
+ scatter([b.x for b in B], [b.y for b in B], xlim=(-1, 1), ylim=(-1, 1), xticks=range(-1, 1, 5), yticks=range(-1, 1, 5)),
+ scatter([b.x for b in B], [b.y for b in B], xlim=(-1, 1), ylim=(-1, 1), xticks=range(-1, 1, 9), yticks=range(-1, 1, 9))
+)
+
+# ╔═╡ 81a4a902-3d0d-49fe-bf98-573be6e6a80e
+md"""
+Consider some node $v$ of the quadtree on level $3$. We will define its near field $N(v)$ to be $8$ adjacent nodes to $v$, except for at the edges where there will be fewer. Let the far field $F(v)$ be all other nodes on the same level as $v$. For a node $w \in F(v)$, we can apply our approximation to compute the interaction of $w$ on $v$. For nodes in $N(v)$, we will compute the interactions at a lower level of the recursion.
+
+In the plot below, $N(v)$ is colored green and $F(v)$ is colored blue. Notice that on the right plot, some of the nodes on the top and right are not included in $F(v)$ because we have already accounted for their interaction on $v$ at level $3$. In general, we will define the far field $F(v)$ to be all other nodes on the same level that are not in $N(v)$ but we have not yet computed their interaction on $v$. $F(v)$ will contain at most $27$ nodes.
+"""
+
+# ╔═╡ 02676896-eb60-4c61-9ba2-60c1ead6edb9
+begin
+ plot(xlim=(-1, 1), ylim=(-1, 1), xticks=range(-1, 1, 5), yticks=range(-1, 1, 5))
+ plot!(Shape([-1, -1, 1, 1], [-1, 1, 1, -1]), fillcolor=RGBA(0, 0, 1, 0.25))
+ plot!(Shape([-1, -1, 0.5, 0.5], [-1, 0.5, 0.5, -1]), fillcolor=RGBA(0, 1, 0, 0.25))
+ plot!(Shape([-0.5, -0.5, 0, 0], [-0.5, 0, 0, -0.5]), fillcolor=RGBA(0, 0, 0, 0.25))
+ plt = annotate!(-0.375, -0.125, "v")
+ plot(xlim=(-1, 1), ylim=(-1, 1), xticks=range(-1, 1, 9), yticks=range(-1, 1, 9))
+ plot!(Shape([-1, -1, 0.5, 0.5], [-1, 0.5, 0.5, -1]), fillcolor=RGBA(0, 0, 1, 0.25))
+ plot!(Shape([-0.75, -0.75, 0, 0], [-0.5, 0.25, 0.25, -0.5]), fillcolor=RGBA(0, 1, 0, 0.25))
+ plot!(Shape([-0.5, -0.5, -0.25, -0.25], [-0.25, 0, 0, -0.25]), fillcolor=RGBA(0, 0, 0, 0.25))
+ plt2 = annotate!(-0.375, -0.125, "v")
+ plot(plt, plt2)
+end
+
+# ╔═╡ 37e0c8b3-abe9-4e2e-a795-ce4210333c5d
+md"""
+The final key idea of the algorithm is that the interaction of some faraway square $w$ on $v$ is roughly the same for any point in $v$, so we can simply compute $G(\apx(v), \apx(w))F(w)$ and add this same term to all points in $v$.
+
+### Code
+
+We are now ready to state the classical FMM algorithm. The ideas behind the algorithm have already been explained, so we will dive straight into the code rather than explaining the algorithm in words.
+"""
+
+# ╔═╡ 6b18bee0-aadc-40f1-8e67-99b1ed69bdce
+function dfs1(B, apx, x, y)
+ # B is the list of source points
+ # apx is the dict of approximations
+ # x is the x coordinates of the endpoints of the current square
+ # y is the y coordinates of the endpoints of the current square
+
+ apx[x, y] = Point(0, 0, 0, 0, 0)
+ if size(B)[1] == 0
+ # Empty square
+ return
+ elseif size(B)[1] == 1
+ # Exactly one point inside, so return it
+ apx[x, y] = B[1]
+ return
+ end
+ xrange = range(x[1], x[2], 3)
+ yrange = range(y[1], y[2], 3)
+ # Construct list of points for each child node
+ chB = [[[]] [[]]; [[]] [[]]]
+ for b in B
+ # Add b to whichever child that it lies in
+ push!(chB[Int64(b.x >= xrange[2]) + 1, Int64(b.y >= yrange[2]) + 1], b)
+ end
+ # Recurse
+ for i = 1:2
+ for j = 1:2
+ # chx, chy are the top, bottom, left, and right coordinates of the child
+ chx = xrange[i:i+1]
+ chy = yrange[j:j+1]
+ dfs1(chB[i, j], apx, chx, chy)
+ # Update apx for this node with the child's mass and location
+ apx[x, y].m += apx[chx, chy].m
+ apx[x, y].x += apx[chx, chy].x * apx[chx, chy].m
+ apx[x, y].y += apx[chx, chy].y * apx[chx, chy].m
+ end
+ end
+ apx[x, y].x /= apx[x, y].m
+ apx[x, y].y /= apx[x, y].m
+end
+
+# ╔═╡ b3865fbc-9f5d-4ff3-93b4-8f8ae96e7a93
+function dfs2(A, B, U, apx, u, ufar, switch, x, y)
+ # B is the list of points
+ # U is the naive O(n^2) solver
+ # apx is the dict of approximations
+ # u is the dict containing the u(a) values
+ # ufar is the current contribution to u from all the far field nodes
+ # switch is the size at which we should switch to running the naive algorithm
+ # x is the x coordinates of the endpoints of the current square
+ # y is the y coordinates of the endpoints of the current square
+
+ if size(B)[1] == 0
+ # Empty square
+ for a in A
+ u[a] = ufar
+ end
+ return
+ elseif size(B)[1] <= switch
+ # Small number of points, run naive algorithm
+ for a in A
+ u[a] = U(a, B) + ufar
+ end
+ return
+ end
+ # Visit all 27 far field square
+ for i = -1:4
+ for j = -1:4
+ # Find coordinates of this square
+ # The x[3], y[3] stuff is because based on which child this is
+ # We might have to go either 2 or 3 steps to the left (see the far field diagram above)
+ xfar = x[1:2] .+ (x[2] - x[1]) * (i - x[3])
+ yfar = y[1:2] .+ (y[2] - y[1]) * (j - y[3])
+ if (0 <= i - x[3] <= 2 && 0 <= j - y[3] <= 2) || !haskey(apx, (xfar, yfar))
+ # In near field or not in apx
+ # If not in apx, then this square contains no points
+ # Either way, we can skip it
+ continue
+ end
+ # Add this far field square's interaction
+ ufar += U(apx[x[1:2], y[1:2]], [apx[xfar, yfar]])
+ end
+ end
+ xrange = range(x[1], x[2], 3)
+ yrange = range(y[1], y[2], 3)
+ # Construct list of points for each child node
+ chA = [[[]] [[]]; [[]] [[]]]
+ chB = [[[]] [[]]; [[]] [[]]]
+ for a in A
+ push!(chA[Int64(a.x >= xrange[2]) + 1, Int64(a.y >= yrange[2]) + 1], a)
+ end
+ for b in B
+ push!(chB[Int64(b.x >= xrange[2]) + 1, Int64(b.y >= yrange[2]) + 1], b)
+ end
+ # Recurse
+ for i = 1:2
+ for j = 1:2
+ # Encode in chx[3], chy[3] which child this is
+ chx = [xrange[i:i+1]; i]
+ chy = [yrange[j:j+1]; j]
+ dfs2(chA[i, j], chB[i, j], U, apx, u, ufar, switch, chx, chy)
+ end
+ end
+end
+
+# ╔═╡ 545abe38-58b0-402c-b151-f84e4e07b9a4
+function fmm(A, B, U, uinit, switch, x, y)
+ # A is the list of target points
+ # B is the list of source points
+ # U is the naive O(n^2) solver
+ # uinit is the initial value of u(a) (0 for potential and [0, 0] for force)
+ # switch is the size at which we should switch to running the naive algorithm
+ # x is the x coordinates of the endpoints of the current square
+ # y is the y coordinates of the endpoints of the current square
+
+ # apx will store the mass and center of mass of approximating a square as a single point
+ apx = Dict()
+ # First compute apx recursively
+ dfs1(B, apx, x, y)
+ # u will store u(a) for each a in A
+ u = Dict()
+ # Now compute u recursively
+ dfs2(A, B, U, apx, u, uinit, switch, [x; 1], [y; 1])
+ return u
+end
+
+# ╔═╡ 44e7f9cb-9f9a-41dc-88ba-b12bd1308fcd
+C = [Point(rand(1:10), 80rand() - 40, 80rand() - 40, 2rand() - 1, 2rand() - 1) for _ = 1:100]
+
+# ╔═╡ 098be928-fb24-4200-b2cf-9bfdd597b2bc
+@bind t2 Clock(1 / 30)
+
+# ╔═╡ 68120cab-374d-4aa9-b540-bed15bc45cbe
+begin
+ t2
+ xlim = [-50, 50]
+ ylim = [-50, 50]
+ # Update velocities using F = ma
+ forces = fmm(C, C, UF, [0, 0], 5, xlim, ylim)
+ # forces = Dict(a => UF(a, D) for a in D)
+ for a in C
+ force = forces[a]
+ a.vx += 10 * force[1] / a.m
+ a.vy += 10 * force[2] / a.m
+ end
+ # Update positions using new velocities
+ for a in C
+ a.x += 0.1 * a.vx
+ a.y += 0.1 * a.vy
+ end
+ filter!(a -> xlim[1] < a.x < xlim[2] && ylim[1] < a.y < ylim[2], C)
+ scatter([(a.x, a.y) for a in C], xlim=xlim, ylim=ylim, title="n-body simulation")
+ plot!([[a.x, a.x + a.vx] for a in C], [[a.y, a.y + a.vy] for a in C])
+end
+
+# ╔═╡ 64f0d118-0af0-4923-8414-fc5872a232be
+begin
+ xrange = yrange = range(-50, 49.9, 100)
+ CA = reduce(vcat, [[Point(0, x, y, 0, 0) for y in yrange] for x in xrange])
+ potential = fmm(CA, C, U, 0, 5, [-50, 50], [-50, 50])
+ surface(xrange, yrange, (x, y) -> log(potential[Point(0, x, y, 0, 0)]), title="FMM potential (log scale)")
+end
+
+# ╔═╡ cc7deb70-aaad-4963-9332-9098e53b648f
+surface(range(-50, 50, 100), range(-50, 50, 100), (x, y) -> log(U((x=x, y=y), C)), title="Actual potential (log scale)")
+
+# ╔═╡ a9b7b3b2-5369-4702-a239-4a1e2714c691
+md"""
+### Time complexity
+
+We will now analyze the time complexity of the fast multipole method. The function `dfs1` takes $O(|B|)$ time for constructing the list of points for each child node, and then recursively calls itself for each child. Here, $B$ is the list of points in the current square. If the points are chosen adversarially, such as $[(\frac{1}{2}, 0), (\frac{1}{4}, 0), \dots, (\frac{1}{2^n}, 0)]$, then the recursion could descend for a depth of $n$ levels, where $|B|$ only decreases by $1$ each level. However, in practice, the machine epsilon limits the recursion depth to approximately $-\log \epsilon$ levels before points become indistinguishably close together. For IEEE 754 doubles, this is around $52$. On each level, we only process a point once when we are processing the square that contains it, so all calls of `dfs1` on a single level take a total of $O(n)$ time. Since the number of levels of recursion is bounded by a constant, this `dfs1` takes $O(n)$ total time.
+
+The other function `dfs2` similarly takes $O(|B|)$ time, plus $27$ iterations through all the far field square. We only run `dfs2` on the square that contain at least $1$ point, so on a single level, `dfs2` takes $O(n + 27n) = O(n)$ time. Thus, `dfs2` also takes $O(n)$ total time, and the entire algorithm runs in $O(n)$.
+
+However, the constant factor for the fast multipole method is very large, so in practice, it is faster to switch to the $O(n^2)$ naive algorithm once $|B|$ falls below a certain value. In the code above, we switched when $|B| \leq 5$, but we can try other values and measure the performance. The plot below shows the runtime for various values on a large set of $10000$ points.
+"""
+
+# ╔═╡ 774d436b-f4fd-46cc-bc53-5edcde07fe45
+begin
+ D = [Point(rand(1:10), 80rand() - 40, 80rand() - 40, 2rand() - 1, 2rand() - 1) for _ = 1:10000]
+ plot(1:200, x -> @elapsed fmm(C, C, UF, [0, 0], x, [-50, 50], [-50, 50]))
+end
+
+# ╔═╡ 34224be0-a3f2-4c05-b7ee-f0fe41706329
+md"""
+### Error analysis
+
+We will now analyze the accuracy of our implementation and compute an upper bound on the error. Let $a$ be a point in the set of target points $A$. Let $C$ be a cluster of points with all located within $r$ from the center of mass of $C$. Using the bound proved in the previous section, the upper bound on the error from contracting $C$ into a single point is $\frac{d/r+1}{d} = \frac{d+r}{d}$, where $d$ is the distance from $a$ to $\apx(C)$. However, $r$ cannot be too big compared to $d$ or we will not contract this cluster while running the FMM. In other words, $\apx(C)$ must be in $F(v)$. To maximize $d$, assume that $\apx(C)$ is located in a square that is two squares away in some direction from $a$, as shown in the diagram below.
+"""
+
+# ╔═╡ ad189673-c33b-4bd7-bbb0-54e2f01ca72e
+begin
+ plot(xlim=(0, 3), ylim=(0, 1), xticks=0:3, yticks=0:1)
+ annotate!(2, 0, "apx(C)")
+ plot!([(2,0), (3, 1)])
+ annotate!(2.5, 0.5, "r")
+ plot!([(1,0), (2, 0)])
+ annotate!(1.5, 0, "d")
+ annotate!(0, 1, "a")
+ plot!([(0,1), (2, 0)])
+ annotate!(1, 0.5, "d'")
+end
+
+# ╔═╡ 9419a61c-32d6-42ef-84cb-2eb1853b2ee2
+md"""
+In the worst case scenario, $d$ is very small and equal to the side length of the squares, while $r$ is the maximum possible value, which is $d\sqrt{2}$. Thus, we get an factor of error of $\frac{d+r}{d} = 1+\sqrt{2}$. However, this is the error for the center of mass of the square that $a$ is in, but $a$ could be located at the opposite corner of the square, so $d' = \sqrt{5}d$. Thus, we gain another $\sqrt{5}$ factor of error, so the final upper bound is $\sqrt{5}+\sqrt{10} \approx 5.398$. The error contribution from each cluster is weighted, so the total error is also at most $5.398$ times the actual answer.
+
+We cannot compute a lower bound, because when $d$ is small, $\frac{\sqrt{d^2-2d}}{d}$ from our bound proven earlier becomes an imaginary number.
+"""
+
+# ╔═╡ 6eb28333-0020-42a6-b1d5-d3f968d6caf1
+md"""
+## Potential improvements
+
+Obviously, a factor of $5.398$ is a terrible amount of error, but fortunately there are several ways to improve this algorithm. We can define the near field to be larger so that we avoid using the approximation on clusters that are close together. However, this increases the constant factor of the algorithm substantially. Another technique for improvement is to use a better low-rank approximation of the kernel $G$.
+"""
+
+# ╔═╡ 5d32c3d4-3f80-47d7-b0d3-eab4e444269d
+md"""
+## References
+"""
+
+# ╔═╡ 2a34a59b-5079-4abe-a914-9565e1e87c0c
+DOI("10.1007/s11425-012-4392-0")
+
+# ╔═╡ c8636f2d-bf7b-46d3-915f-20d52280d38d
+md"""
+## Miscellaneous code
+"""
+
+# ╔═╡ 072d7d32-e7df-403d-b98e-f4d8806658de
+TableOfContents()
+
+# ╔═╡ 0d6e7b13-f0cb-4e68-984b-a97766580598
+md"""
+$\newcommand{\apx}{\text{apx}}$
+"""
+
+# ╔═╡ ac898a8a-296a-4ed0-9703-6397ef001249
+function point_input(defaults::Vector{Int64})
+ return combine() do Child
+ md"""
+ | mass | x position | y position | x velocity | y velocity |
+ | --- | --- | --- | --- | --- |
+ | $(Child("m", Slider(1:10, defaults[1], true))) | $(Child("x", Slider(-10:10, defaults[2], true))) | $(Child("y", Slider(-10:10, defaults[3], true))) | $(Child("vx", Slider(-10:10, defaults[4], true))) | $(Child("vy", Slider(-10:10, defaults[5], true))) |
+ """
+ end
+end
+
+# ╔═╡ 623384dc-13dd-44d1-9b2e-b70148025d34
+@bind p point_input([2, 7, 10, -2, 4])
+
+# ╔═╡ b1a19883-ee37-40fb-94fc-29525c1f50fd
+@bind q point_input([9, 0, 0, 1, -1])
+
+# ╔═╡ fd3b4502-cb18-4458-8829-9a25976539e3
+@bind r point_input([4, 5, 1, -4, 6])
+
+# ╔═╡ 077ab2ef-0163-4af0-ad1e-eae1c6b6752c
+A = map(Point, [p, q, r])
+
+# ╔═╡ c7efabb7-9bac-4fb7-8224-edbd67a2ad0a
+begin
+ t
+ # Update velocities using F = ma
+ for a in A
+ force = UF(a, A)
+ a.vx += 10 * force[1] / a.m
+ a.vy += 10 * force[2] / a.m
+ end
+ # Update positions using new velocities
+ for a in A
+ a.x += 0.1 * a.vx
+ a.y += 0.1 * a.vy
+ end
+ scatter([(a.x, a.y) for a in A], xlim=(-50, 50), ylim=(-50, 50), title="n-body simulation")
+ plot!([[a.x, a.x + a.vx] for a in A], [[a.y, a.y + a.vy] for a in A])
+end
+
+# ╔═╡ 264bad21-433e-4fe0-802e-54f9ed0c1023
+surface(range(-25, 25, 100), range(-25, 25, 100), (x, y) -> log(U((x=x, y=y), A)), title="Potential (log scale)")
+
+# ╔═╡ 00000000-0000-0000-0000-000000000001
+PLUTO_PROJECT_TOML_CONTENTS = """
+[deps]
+PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a"
+Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
+PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
+ShortCodes = "f62ebe17-55c5-4640-972f-b59c0dd11ccf"
+
+[compat]
+PlotlyJS = "~0.18.13"
+Plots = "~1.40.4"
+PlutoUI = "~0.7.59"
+ShortCodes = "~0.3.6"
+"""
+
+# ╔═╡ 00000000-0000-0000-0000-000000000002
+PLUTO_MANIFEST_TOML_CONTENTS = """
+# This file is machine-generated - editing it directly is not advised
+
+julia_version = "1.10.2"
+manifest_format = "2.0"
+project_hash = "26d095d7ef1124091bf616180e58756318514acc"
+
+[[deps.AbstractPlutoDingetjes]]
+deps = ["Pkg"]
+git-tree-sha1 = "6e1d2a35f2f90a4bc7c2ed98079b2ba09c35b83a"
+uuid = "6e696c72-6542-2067-7265-42206c756150"
+version = "1.3.2"
+
+[[deps.ArgTools]]
+uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
+version = "1.1.1"
+
+[[deps.Artifacts]]
+uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
+
+[[deps.AssetRegistry]]
+deps = ["Distributed", "JSON", "Pidfile", "SHA", "Test"]
+git-tree-sha1 = "b25e88db7944f98789130d7b503276bc34bc098e"
+uuid = "bf4720bc-e11a-5d0c-854e-bdca1663c893"
+version = "0.1.0"
+
+[[deps.Base64]]
+uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
+
+[[deps.BitFlags]]
+git-tree-sha1 = "2dc09997850d68179b69dafb58ae806167a32b1b"
+uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35"
+version = "0.1.8"
+
+[[deps.Blink]]
+deps = ["Base64", "Distributed", "HTTP", "JSExpr", "JSON", "Lazy", "Logging", "MacroTools", "Mustache", "Mux", "Pkg", "Reexport", "Sockets", "WebIO"]
+git-tree-sha1 = "bc93511973d1f949d45b0ea17878e6cb0ad484a1"
+uuid = "ad839575-38b3-5650-b840-f874b8c74a25"
+version = "0.12.9"
+
+[[deps.Bzip2_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "9e2a6b69137e6969bab0152632dcb3bc108c8bdd"
+uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
+version = "1.0.8+1"
+
+[[deps.Cairo_jll]]
+deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
+git-tree-sha1 = "a4c43f59baa34011e303e76f5c8c91bf58415aaf"
+uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
+version = "1.18.0+1"
+
+[[deps.CodecZlib]]
+deps = ["TranscodingStreams", "Zlib_jll"]
+git-tree-sha1 = "59939d8a997469ee05c4b4944560a820f9ba0d73"
+uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
+version = "0.7.4"
+
+[[deps.ColorSchemes]]
+deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"]
+git-tree-sha1 = "67c1f244b991cad9b0aa4b7540fb758c2488b129"
+uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
+version = "3.24.0"
+
+[[deps.ColorTypes]]
+deps = ["FixedPointNumbers", "Random"]
+git-tree-sha1 = "b10d0b65641d57b8b4d5e234446582de5047050d"
+uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
+version = "0.11.5"
+
+[[deps.ColorVectorSpace]]
+deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "Requires", "Statistics", "TensorCore"]
+git-tree-sha1 = "a1f44953f2382ebb937d60dafbe2deea4bd23249"
+uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4"
+version = "0.10.0"
+
+ [deps.ColorVectorSpace.extensions]
+ SpecialFunctionsExt = "SpecialFunctions"
+
+ [deps.ColorVectorSpace.weakdeps]
+ SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
+
+[[deps.Colors]]
+deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
+git-tree-sha1 = "fc08e5930ee9a4e03f84bfb5211cb54e7769758a"
+uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
+version = "0.12.10"
+
+[[deps.Compat]]
+deps = ["TOML", "UUIDs"]
+git-tree-sha1 = "c955881e3c981181362ae4088b35995446298b80"
+uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
+version = "4.14.0"
+weakdeps = ["Dates", "LinearAlgebra"]
+
+ [deps.Compat.extensions]
+ CompatLinearAlgebraExt = "LinearAlgebra"
+
+[[deps.CompilerSupportLibraries_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
+version = "1.1.0+0"
+
+[[deps.ConcurrentUtilities]]
+deps = ["Serialization", "Sockets"]
+git-tree-sha1 = "6cbbd4d241d7e6579ab354737f4dd95ca43946e1"
+uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb"
+version = "2.4.1"
+
+[[deps.Contour]]
+git-tree-sha1 = "439e35b0b36e2e5881738abc8857bd92ad6ff9a8"
+uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
+version = "0.6.3"
+
+[[deps.DataAPI]]
+git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe"
+uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
+version = "1.16.0"
+
+[[deps.DataStructures]]
+deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
+git-tree-sha1 = "1d0a14036acb104d9e89698bd408f63ab58cdc82"
+uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
+version = "0.18.20"
+
+[[deps.DataValueInterfaces]]
+git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
+uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
+version = "1.0.0"
+
+[[deps.Dates]]
+deps = ["Printf"]
+uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
+
+[[deps.DelimitedFiles]]
+deps = ["Mmap"]
+git-tree-sha1 = "9e2f36d3c96a820c678f2f1f1782582fcf685bae"
+uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"
+version = "1.9.1"
+
+[[deps.Distributed]]
+deps = ["Random", "Serialization", "Sockets"]
+uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"
+
+[[deps.DocStringExtensions]]
+deps = ["LibGit2"]
+git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d"
+uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
+version = "0.9.3"
+
+[[deps.Downloads]]
+deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
+uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
+version = "1.6.0"
+
+[[deps.EpollShim_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "8e9441ee83492030ace98f9789a654a6d0b1f643"
+uuid = "2702e6a9-849d-5ed8-8c21-79e8b8f9ee43"
+version = "0.0.20230411+0"
+
+[[deps.ExceptionUnwrapping]]
+deps = ["Test"]
+git-tree-sha1 = "dcb08a0d93ec0b1cdc4af184b26b591e9695423a"
+uuid = "460bff9d-24e4-43bc-9d9f-a8973cb893f4"
+version = "0.1.10"
+
+[[deps.Expat_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "4558ab818dcceaab612d1bb8c19cee87eda2b83c"
+uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
+version = "2.5.0+0"
+
+[[deps.FFMPEG]]
+deps = ["FFMPEG_jll"]
+git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8"
+uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
+version = "0.4.1"
+
+[[deps.FFMPEG_jll]]
+deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
+git-tree-sha1 = "466d45dc38e15794ec7d5d63ec03d776a9aff36e"
+uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
+version = "4.4.4+1"
+
+[[deps.FileWatching]]
+uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
+
+[[deps.FixedPointNumbers]]
+deps = ["Statistics"]
+git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
+uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
+version = "0.8.4"
+
+[[deps.Fontconfig_jll]]
+deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"]
+git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03"
+uuid = "a3f928ae-7b40-5064-980b-68af3947d34b"
+version = "2.13.93+0"
+
+[[deps.Format]]
+git-tree-sha1 = "9c68794ef81b08086aeb32eeaf33531668d5f5fc"
+uuid = "1fa38f19-a742-5d3f-a2b9-30dd87b9d5f8"
+version = "1.3.7"
+
+[[deps.FreeType2_jll]]
+deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Zlib_jll"]
+git-tree-sha1 = "d8db6a5a2fe1381c1ea4ef2cab7c69c2de7f9ea0"
+uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
+version = "2.13.1+0"
+
+[[deps.FriBidi_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91"
+uuid = "559328eb-81f9-559d-9380-de523a88c83c"
+version = "1.0.10+0"
+
+[[deps.FunctionalCollections]]
+deps = ["Test"]
+git-tree-sha1 = "04cb9cfaa6ba5311973994fe3496ddec19b6292a"
+uuid = "de31a74c-ac4f-5751-b3fd-e18cd04993ca"
+version = "0.5.0"
+
+[[deps.GLFW_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"]
+git-tree-sha1 = "ff38ba61beff76b8f4acad8ab0c97ef73bb670cb"
+uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89"
+version = "3.3.9+0"
+
+[[deps.GR]]
+deps = ["Artifacts", "Base64", "DelimitedFiles", "Downloads", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Preferences", "Printf", "Random", "Serialization", "Sockets", "TOML", "Tar", "Test", "UUIDs", "p7zip_jll"]
+git-tree-sha1 = "3437ade7073682993e092ca570ad68a2aba26983"
+uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
+version = "0.73.3"
+
+[[deps.GR_jll]]
+deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "FreeType2_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Qt6Base_jll", "Zlib_jll", "libpng_jll"]
+git-tree-sha1 = "a96d5c713e6aa28c242b0d25c1347e258d6541ab"
+uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
+version = "0.73.3+0"
+
+[[deps.Gettext_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"]
+git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046"
+uuid = "78b55507-aeef-58d4-861c-77aaff3498b1"
+version = "0.21.0+0"
+
+[[deps.Glib_jll]]
+deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"]
+git-tree-sha1 = "359a1ba2e320790ddbe4ee8b4d54a305c0ea2aff"
+uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
+version = "2.80.0+0"
+
+[[deps.Graphite2_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011"
+uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472"
+version = "1.3.14+0"
+
+[[deps.Grisu]]
+git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2"
+uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe"
+version = "1.0.2"
+
+[[deps.HTTP]]
+deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"]
+git-tree-sha1 = "2c3ec1f90bb4a8f7beafb0cffea8a4c3f4e636ab"
+uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
+version = "1.10.6"
+
+[[deps.HarfBuzz_jll]]
+deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"]
+git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3"
+uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566"
+version = "2.8.1+1"
+
+[[deps.Hiccup]]
+deps = ["MacroTools", "Test"]
+git-tree-sha1 = "6187bb2d5fcbb2007c39e7ac53308b0d371124bd"
+uuid = "9fb69e20-1954-56bb-a84f-559cc56a8ff7"
+version = "0.2.2"
+
+[[deps.Hyperscript]]
+deps = ["Test"]
+git-tree-sha1 = "179267cfa5e712760cd43dcae385d7ea90cc25a4"
+uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
+version = "0.0.5"
+
+[[deps.HypertextLiteral]]
+deps = ["Tricks"]
+git-tree-sha1 = "7134810b1afce04bbc1045ca1985fbe81ce17653"
+uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
+version = "0.9.5"
+
+[[deps.IOCapture]]
+deps = ["Logging", "Random"]
+git-tree-sha1 = "8b72179abc660bfab5e28472e019392b97d0985c"
+uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
+version = "0.2.4"
+
+[[deps.InteractiveUtils]]
+deps = ["Markdown"]
+uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
+
+[[deps.IrrationalConstants]]
+git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2"
+uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
+version = "0.2.2"
+
+[[deps.IteratorInterfaceExtensions]]
+git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
+uuid = "82899510-4779-5014-852e-03e436cf321d"
+version = "1.0.0"
+
+[[deps.JLFzf]]
+deps = ["Pipe", "REPL", "Random", "fzf_jll"]
+git-tree-sha1 = "a53ebe394b71470c7f97c2e7e170d51df21b17af"
+uuid = "1019f520-868f-41f5-a6de-eb00f4b6a39c"
+version = "0.1.7"
+
+[[deps.JLLWrappers]]
+deps = ["Artifacts", "Preferences"]
+git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca"
+uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
+version = "1.5.0"
+
+[[deps.JSExpr]]
+deps = ["JSON", "MacroTools", "Observables", "WebIO"]
+git-tree-sha1 = "b413a73785b98474d8af24fd4c8a975e31df3658"
+uuid = "97c1335a-c9c5-57fe-bc5d-ec35cebe8660"
+version = "0.5.4"
+
+[[deps.JSON]]
+deps = ["Dates", "Mmap", "Parsers", "Unicode"]
+git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a"
+uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
+version = "0.21.4"
+
+[[deps.JSON3]]
+deps = ["Dates", "Mmap", "Parsers", "PrecompileTools", "StructTypes", "UUIDs"]
+git-tree-sha1 = "eb3edce0ed4fa32f75a0a11217433c31d56bd48b"
+uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
+version = "1.14.0"
+
+ [deps.JSON3.extensions]
+ JSON3ArrowExt = ["ArrowTypes"]
+
+ [deps.JSON3.weakdeps]
+ ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd"
+
+[[deps.JpegTurbo_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "3336abae9a713d2210bb57ab484b1e065edd7d23"
+uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
+version = "3.0.2+0"
+
+[[deps.Kaleido_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "43032da5832754f58d14a91ffbe86d5f176acda9"
+uuid = "f7e6163d-2fa5-5f23-b69c-1db539e41963"
+version = "0.2.1+0"
+
+[[deps.LAME_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c"
+uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d"
+version = "3.100.1+0"
+
+[[deps.LERC_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434"
+uuid = "88015f11-f218-50d7-93a8-a6af411a945d"
+version = "3.0.0+1"
+
+[[deps.LLVMOpenMP_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "d986ce2d884d49126836ea94ed5bfb0f12679713"
+uuid = "1d63c593-3942-5779-bab2-d838dc0a180e"
+version = "15.0.7+0"
+
+[[deps.LZO_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6"
+uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac"
+version = "2.10.1+0"
+
+[[deps.LaTeXStrings]]
+git-tree-sha1 = "50901ebc375ed41dbf8058da26f9de442febbbec"
+uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
+version = "1.3.1"
+
+[[deps.Latexify]]
+deps = ["Format", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Requires"]
+git-tree-sha1 = "e0b5cd21dc1b44ec6e64f351976f961e6f31d6c4"
+uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
+version = "0.16.3"
+
+ [deps.Latexify.extensions]
+ DataFramesExt = "DataFrames"
+ SymEngineExt = "SymEngine"
+
+ [deps.Latexify.weakdeps]
+ DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
+ SymEngine = "123dc426-2d89-5057-bbad-38513e3affd8"
+
+[[deps.Lazy]]
+deps = ["MacroTools"]
+git-tree-sha1 = "1370f8202dac30758f3c345f9909b97f53d87d3f"
+uuid = "50d2b5c4-7a5e-59d5-8109-a42b560f39c0"
+version = "0.15.1"
+
+[[deps.LibCURL]]
+deps = ["LibCURL_jll", "MozillaCACerts_jll"]
+uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
+version = "0.6.4"
+
+[[deps.LibCURL_jll]]
+deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
+uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
+version = "8.4.0+0"
+
+[[deps.LibGit2]]
+deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"]
+uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
+
+[[deps.LibGit2_jll]]
+deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"]
+uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5"
+version = "1.6.4+0"
+
+[[deps.LibSSH2_jll]]
+deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
+uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
+version = "1.11.0+1"
+
+[[deps.Libdl]]
+uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
+
+[[deps.Libffi_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290"
+uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
+version = "3.2.2+1"
+
+[[deps.Libgcrypt_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll"]
+git-tree-sha1 = "9fd170c4bbfd8b935fdc5f8b7aa33532c991a673"
+uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4"
+version = "1.8.11+0"
+
+[[deps.Libglvnd_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"]
+git-tree-sha1 = "6f73d1dd803986947b2c750138528a999a6c7733"
+uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29"
+version = "1.6.0+0"
+
+[[deps.Libgpg_error_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9"
+uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
+version = "1.42.0+0"
+
+[[deps.Libiconv_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "f9557a255370125b405568f9767d6d195822a175"
+uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
+version = "1.17.0+0"
+
+[[deps.Libmount_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "dae976433497a2f841baadea93d27e68f1a12a97"
+uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9"
+version = "2.39.3+0"
+
+[[deps.Libtiff_jll]]
+deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "XZ_jll", "Zlib_jll", "Zstd_jll"]
+git-tree-sha1 = "2da088d113af58221c52828a80378e16be7d037a"
+uuid = "89763e89-9b03-5906-acba-b20f662cd828"
+version = "4.5.1+1"
+
+[[deps.Libuuid_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "0a04a1318df1bf510beb2562cf90fb0c386f58c4"
+uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700"
+version = "2.39.3+1"
+
+[[deps.LinearAlgebra]]
+deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"]
+uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
+
+[[deps.LogExpFunctions]]
+deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
+git-tree-sha1 = "18144f3e9cbe9b15b070288eef858f71b291ce37"
+uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
+version = "0.3.27"
+
+ [deps.LogExpFunctions.extensions]
+ LogExpFunctionsChainRulesCoreExt = "ChainRulesCore"
+ LogExpFunctionsChangesOfVariablesExt = "ChangesOfVariables"
+ LogExpFunctionsInverseFunctionsExt = "InverseFunctions"
+
+ [deps.LogExpFunctions.weakdeps]
+ ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
+ ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0"
+ InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
+
+[[deps.Logging]]
+uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
+
+[[deps.LoggingExtras]]
+deps = ["Dates", "Logging"]
+git-tree-sha1 = "c1dd6d7978c12545b4179fb6153b9250c96b0075"
+uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36"
+version = "1.0.3"
+
+[[deps.MIMEs]]
+git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb"
+uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65"
+version = "0.1.4"
+
+[[deps.MacroTools]]
+deps = ["Markdown", "Random"]
+git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df"
+uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
+version = "0.5.13"
+
+[[deps.Markdown]]
+deps = ["Base64"]
+uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
+
+[[deps.MbedTLS]]
+deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"]
+git-tree-sha1 = "c067a280ddc25f196b5e7df3877c6b226d390aaf"
+uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
+version = "1.1.9"
+
+[[deps.MbedTLS_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
+version = "2.28.2+1"
+
+[[deps.Measures]]
+git-tree-sha1 = "c13304c81eec1ed3af7fc20e75fb6b26092a1102"
+uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
+version = "0.3.2"
+
+[[deps.Memoize]]
+deps = ["MacroTools"]
+git-tree-sha1 = "2b1dfcba103de714d31c033b5dacc2e4a12c7caa"
+uuid = "c03570c3-d221-55d1-a50c-7939bbd78826"
+version = "0.4.4"
+
+[[deps.Missings]]
+deps = ["DataAPI"]
+git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d"
+uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
+version = "1.2.0"
+
+[[deps.Mmap]]
+uuid = "a63ad114-7e13-5084-954f-fe012c677804"
+
+[[deps.MozillaCACerts_jll]]
+uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
+version = "2023.1.10"
+
+[[deps.Mustache]]
+deps = ["Printf", "Tables"]
+git-tree-sha1 = "a7cefa21a2ff993bff0456bf7521f46fc077ddf1"
+uuid = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70"
+version = "1.0.19"
+
+[[deps.Mux]]
+deps = ["AssetRegistry", "Base64", "HTTP", "Hiccup", "MbedTLS", "Pkg", "Sockets"]
+git-tree-sha1 = "7295d849103ac4fcbe3b2e439f229c5cc77b9b69"
+uuid = "a975b10e-0019-58db-a62f-e48ff68538c9"
+version = "1.0.2"
+
+[[deps.NaNMath]]
+deps = ["OpenLibm_jll"]
+git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4"
+uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
+version = "1.0.2"
+
+[[deps.NetworkOptions]]
+uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
+version = "1.2.0"
+
+[[deps.Observables]]
+git-tree-sha1 = "7438a59546cf62428fc9d1bc94729146d37a7225"
+uuid = "510215fc-4207-5dde-b226-833fc4488ee2"
+version = "0.5.5"
+
+[[deps.Ogg_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f"
+uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051"
+version = "1.3.5+1"
+
+[[deps.OpenBLAS_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
+uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
+version = "0.3.23+4"
+
+[[deps.OpenLibm_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "05823500-19ac-5b8b-9628-191a04bc5112"
+version = "0.8.1+2"
+
+[[deps.OpenSSL]]
+deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"]
+git-tree-sha1 = "38cb508d080d21dc1128f7fb04f20387ed4c0af4"
+uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c"
+version = "1.4.3"
+
+[[deps.OpenSSL_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "3da7367955dcc5c54c1ba4d402ccdc09a1a3e046"
+uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
+version = "3.0.13+1"
+
+[[deps.Opus_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720"
+uuid = "91d4177d-7536-5919-b921-800302f37372"
+version = "1.3.2+0"
+
+[[deps.OrderedCollections]]
+git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5"
+uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
+version = "1.6.3"
+
+[[deps.PCRE2_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15"
+version = "10.42.0+1"
+
+[[deps.Parameters]]
+deps = ["OrderedCollections", "UnPack"]
+git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe"
+uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
+version = "0.12.3"
+
+[[deps.Parsers]]
+deps = ["Dates", "PrecompileTools", "UUIDs"]
+git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821"
+uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
+version = "2.8.1"
+
+[[deps.Pidfile]]
+deps = ["FileWatching", "Test"]
+git-tree-sha1 = "2d8aaf8ee10df53d0dfb9b8ee44ae7c04ced2b03"
+uuid = "fa939f87-e72e-5be4-a000-7fc836dbe307"
+version = "1.3.0"
+
+[[deps.Pipe]]
+git-tree-sha1 = "6842804e7867b115ca9de748a0cf6b364523c16d"
+uuid = "b98c9c47-44ae-5843-9183-064241ee97a0"
+version = "1.3.0"
+
+[[deps.Pixman_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl"]
+git-tree-sha1 = "64779bc4c9784fee475689a1752ef4d5747c5e87"
+uuid = "30392449-352a-5448-841d-b1acce4e97dc"
+version = "0.42.2+0"
+
+[[deps.Pkg]]
+deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
+uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
+version = "1.10.0"
+
+[[deps.PlotThemes]]
+deps = ["PlotUtils", "Statistics"]
+git-tree-sha1 = "1f03a2d339f42dca4a4da149c7e15e9b896ad899"
+uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
+version = "3.1.0"
+
+[[deps.PlotUtils]]
+deps = ["ColorSchemes", "Colors", "Dates", "PrecompileTools", "Printf", "Random", "Reexport", "Statistics"]
+git-tree-sha1 = "7b1a9df27f072ac4c9c7cbe5efb198489258d1f5"
+uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
+version = "1.4.1"
+
+[[deps.PlotlyBase]]
+deps = ["ColorSchemes", "Dates", "DelimitedFiles", "DocStringExtensions", "JSON", "LaTeXStrings", "Logging", "Parameters", "Pkg", "REPL", "Requires", "Statistics", "UUIDs"]
+git-tree-sha1 = "56baf69781fc5e61607c3e46227ab17f7040ffa2"
+uuid = "a03496cd-edff-5a9b-9e67-9cda94a718b5"
+version = "0.8.19"
+
+[[deps.PlotlyJS]]
+deps = ["Base64", "Blink", "DelimitedFiles", "JSExpr", "JSON", "Kaleido_jll", "Markdown", "Pkg", "PlotlyBase", "PlotlyKaleido", "REPL", "Reexport", "Requires", "WebIO"]
+git-tree-sha1 = "e62d886d33b81c371c9d4e2f70663c0637f19459"
+uuid = "f0f68f2c-4968-5e81-91da-67840de0976a"
+version = "0.18.13"
+
+ [deps.PlotlyJS.extensions]
+ CSVExt = "CSV"
+ DataFramesExt = ["DataFrames", "CSV"]
+ IJuliaExt = "IJulia"
+ JSON3Ext = "JSON3"
+
+ [deps.PlotlyJS.weakdeps]
+ CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
+ DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
+ IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
+ JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
+
+[[deps.PlotlyKaleido]]
+deps = ["Base64", "JSON", "Kaleido_jll"]
+git-tree-sha1 = "2650cd8fb83f73394996d507b3411a7316f6f184"
+uuid = "f2990250-8cf9-495f-b13a-cce12b45703c"
+version = "2.2.4"
+
+[[deps.Plots]]
+deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "JLFzf", "JSON", "LaTeXStrings", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "PrecompileTools", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "RelocatableFolders", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "UnitfulLatexify", "Unzip"]
+git-tree-sha1 = "442e1e7ac27dd5ff8825c3fa62fbd1e86397974b"
+uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
+version = "1.40.4"
+
+ [deps.Plots.extensions]
+ FileIOExt = "FileIO"
+ GeometryBasicsExt = "GeometryBasics"
+ IJuliaExt = "IJulia"
+ ImageInTerminalExt = "ImageInTerminal"
+ UnitfulExt = "Unitful"
+
+ [deps.Plots.weakdeps]
+ FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
+ GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
+ IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
+ ImageInTerminal = "d8c32880-2388-543b-8c61-d9f865259254"
+ Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
+
+[[deps.PlutoUI]]
+deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"]
+git-tree-sha1 = "ab55ee1510ad2af0ff674dbcced5e94921f867a9"
+uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
+version = "0.7.59"
+
+[[deps.PrecompileTools]]
+deps = ["Preferences"]
+git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f"
+uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
+version = "1.2.1"
+
+[[deps.Preferences]]
+deps = ["TOML"]
+git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6"
+uuid = "21216c6a-2e73-6563-6e65-726566657250"
+version = "1.4.3"
+
+[[deps.Printf]]
+deps = ["Unicode"]
+uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
+
+[[deps.Qt6Base_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Vulkan_Loader_jll", "Xorg_libSM_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_cursor_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "libinput_jll", "xkbcommon_jll"]
+git-tree-sha1 = "37b7bb7aabf9a085e0044307e1717436117f2b3b"
+uuid = "c0090381-4147-56d7-9ebc-da0b1113ec56"
+version = "6.5.3+1"
+
+[[deps.REPL]]
+deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
+uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
+
+[[deps.Random]]
+deps = ["SHA"]
+uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
+
+[[deps.RecipesBase]]
+deps = ["PrecompileTools"]
+git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff"
+uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
+version = "1.3.4"
+
+[[deps.RecipesPipeline]]
+deps = ["Dates", "NaNMath", "PlotUtils", "PrecompileTools", "RecipesBase"]
+git-tree-sha1 = "45cf9fd0ca5839d06ef333c8201714e888486342"
+uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c"
+version = "0.6.12"
+
+[[deps.Reexport]]
+git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
+uuid = "189a3867-3050-52da-a836-e630ba90ab69"
+version = "1.2.2"
+
+[[deps.RelocatableFolders]]
+deps = ["SHA", "Scratch"]
+git-tree-sha1 = "ffdaf70d81cf6ff22c2b6e733c900c3321cab864"
+uuid = "05181044-ff0b-4ac5-8273-598c1e38db00"
+version = "1.0.1"
+
+[[deps.Requires]]
+deps = ["UUIDs"]
+git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7"
+uuid = "ae029012-a4dd-5104-9daa-d747884805df"
+version = "1.3.0"
+
+[[deps.SHA]]
+uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
+version = "0.7.0"
+
+[[deps.Scratch]]
+deps = ["Dates"]
+git-tree-sha1 = "3bac05bc7e74a75fd9cba4295cde4045d9fe2386"
+uuid = "6c6a2e73-6563-6170-7368-637461726353"
+version = "1.2.1"
+
+[[deps.Serialization]]
+uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
+
+[[deps.ShortCodes]]
+deps = ["Base64", "CodecZlib", "Downloads", "JSON3", "Memoize", "URIs", "UUIDs"]
+git-tree-sha1 = "5844ee60d9fd30a891d48bab77ac9e16791a0a57"
+uuid = "f62ebe17-55c5-4640-972f-b59c0dd11ccf"
+version = "0.3.6"
+
+[[deps.Showoff]]
+deps = ["Dates", "Grisu"]
+git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de"
+uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
+version = "1.0.3"
+
+[[deps.SimpleBufferStream]]
+git-tree-sha1 = "874e8867b33a00e784c8a7e4b60afe9e037b74e1"
+uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7"
+version = "1.1.0"
+
+[[deps.Sockets]]
+uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
+
+[[deps.SortingAlgorithms]]
+deps = ["DataStructures"]
+git-tree-sha1 = "66e0a8e672a0bdfca2c3f5937efb8538b9ddc085"
+uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
+version = "1.2.1"
+
+[[deps.SparseArrays]]
+deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"]
+uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
+version = "1.10.0"
+
+[[deps.Statistics]]
+deps = ["LinearAlgebra", "SparseArrays"]
+uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
+version = "1.10.0"
+
+[[deps.StatsAPI]]
+deps = ["LinearAlgebra"]
+git-tree-sha1 = "1ff449ad350c9c4cbc756624d6f8a8c3ef56d3ed"
+uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
+version = "1.7.0"
+
+[[deps.StatsBase]]
+deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
+git-tree-sha1 = "5cf7606d6cef84b543b483848d4ae08ad9832b21"
+uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
+version = "0.34.3"
+
+[[deps.StructTypes]]
+deps = ["Dates", "UUIDs"]
+git-tree-sha1 = "ca4bccb03acf9faaf4137a9abc1881ed1841aa70"
+uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"
+version = "1.10.0"
+
+[[deps.SuiteSparse_jll]]
+deps = ["Artifacts", "Libdl", "libblastrampoline_jll"]
+uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c"
+version = "7.2.1+1"
+
+[[deps.TOML]]
+deps = ["Dates"]
+uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
+version = "1.0.3"
+
+[[deps.TableTraits]]
+deps = ["IteratorInterfaceExtensions"]
+git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
+uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
+version = "1.0.1"
+
+[[deps.Tables]]
+deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits"]
+git-tree-sha1 = "cb76cf677714c095e535e3501ac7954732aeea2d"
+uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
+version = "1.11.1"
+
+[[deps.Tar]]
+deps = ["ArgTools", "SHA"]
+uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
+version = "1.10.0"
+
+[[deps.TensorCore]]
+deps = ["LinearAlgebra"]
+git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6"
+uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50"
+version = "0.1.1"
+
+[[deps.Test]]
+deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
+uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
+
+[[deps.TranscodingStreams]]
+git-tree-sha1 = "71509f04d045ec714c4748c785a59045c3736349"
+uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
+version = "0.10.7"
+weakdeps = ["Random", "Test"]
+
+ [deps.TranscodingStreams.extensions]
+ TestExt = ["Test", "Random"]
+
+[[deps.Tricks]]
+git-tree-sha1 = "eae1bb484cd63b36999ee58be2de6c178105112f"
+uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775"
+version = "0.1.8"
+
+[[deps.URIs]]
+git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b"
+uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
+version = "1.5.1"
+
+[[deps.UUIDs]]
+deps = ["Random", "SHA"]
+uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
+
+[[deps.UnPack]]
+git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
+uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
+version = "1.0.2"
+
+[[deps.Unicode]]
+uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
+
+[[deps.UnicodeFun]]
+deps = ["REPL"]
+git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf"
+uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1"
+version = "0.4.1"
+
+[[deps.Unitful]]
+deps = ["Dates", "LinearAlgebra", "Random"]
+git-tree-sha1 = "3c793be6df9dd77a0cf49d80984ef9ff996948fa"
+uuid = "1986cc42-f94f-5a68-af5c-568840ba703d"
+version = "1.19.0"
+
+ [deps.Unitful.extensions]
+ ConstructionBaseUnitfulExt = "ConstructionBase"
+ InverseFunctionsUnitfulExt = "InverseFunctions"
+
+ [deps.Unitful.weakdeps]
+ ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
+ InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
+
+[[deps.UnitfulLatexify]]
+deps = ["LaTeXStrings", "Latexify", "Unitful"]
+git-tree-sha1 = "e2d817cc500e960fdbafcf988ac8436ba3208bfd"
+uuid = "45397f5d-5981-4c77-b2b3-fc36d6e9b728"
+version = "1.6.3"
+
+[[deps.Unzip]]
+git-tree-sha1 = "ca0969166a028236229f63514992fc073799bb78"
+uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d"
+version = "0.2.0"
+
+[[deps.Vulkan_Loader_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Wayland_jll", "Xorg_libX11_jll", "Xorg_libXrandr_jll", "xkbcommon_jll"]
+git-tree-sha1 = "2f0486047a07670caad3a81a075d2e518acc5c59"
+uuid = "a44049a8-05dd-5a78-86c9-5fde0876e88c"
+version = "1.3.243+0"
+
+[[deps.Wayland_jll]]
+deps = ["Artifacts", "EpollShim_jll", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"]
+git-tree-sha1 = "7558e29847e99bc3f04d6569e82d0f5c54460703"
+uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89"
+version = "1.21.0+1"
+
+[[deps.Wayland_protocols_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "93f43ab61b16ddfb2fd3bb13b3ce241cafb0e6c9"
+uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
+version = "1.31.0+0"
+
+[[deps.WebIO]]
+deps = ["AssetRegistry", "Base64", "Distributed", "FunctionalCollections", "JSON", "Logging", "Observables", "Pkg", "Random", "Requires", "Sockets", "UUIDs", "WebSockets", "Widgets"]
+git-tree-sha1 = "0eef0765186f7452e52236fa42ca8c9b3c11c6e3"
+uuid = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29"
+version = "0.8.21"
+
+[[deps.WebSockets]]
+deps = ["Base64", "Dates", "HTTP", "Logging", "Sockets"]
+git-tree-sha1 = "4162e95e05e79922e44b9952ccbc262832e4ad07"
+uuid = "104b5d7c-a370-577a-8038-80a2059c5097"
+version = "1.6.0"
+
+[[deps.Widgets]]
+deps = ["Colors", "Dates", "Observables", "OrderedCollections"]
+git-tree-sha1 = "fcdae142c1cfc7d89de2d11e08721d0f2f86c98a"
+uuid = "cc8bc4a8-27d6-5769-a93b-9d913e69aa62"
+version = "0.6.6"
+
+[[deps.XML2_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"]
+git-tree-sha1 = "532e22cf7be8462035d092ff21fada7527e2c488"
+uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
+version = "2.12.6+0"
+
+[[deps.XSLT_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"]
+git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a"
+uuid = "aed1982a-8fda-507f-9586-7b0439959a61"
+version = "1.1.34+0"
+
+[[deps.XZ_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "ac88fb95ae6447c8dda6a5503f3bafd496ae8632"
+uuid = "ffd25f8a-64ca-5728-b0f7-c24cf3aae800"
+version = "5.4.6+0"
+
+[[deps.Xorg_libICE_jll]]
+deps = ["Libdl", "Pkg"]
+git-tree-sha1 = "e5becd4411063bdcac16be8b66fc2f9f6f1e8fe5"
+uuid = "f67eecfb-183a-506d-b269-f58e52b52d7c"
+version = "1.0.10+1"
+
+[[deps.Xorg_libSM_jll]]
+deps = ["Libdl", "Pkg", "Xorg_libICE_jll"]
+git-tree-sha1 = "4a9d9e4c180e1e8119b5ffc224a7b59d3a7f7e18"
+uuid = "c834827a-8449-5923-a945-d239c165b7dd"
+version = "1.2.3+0"
+
+[[deps.Xorg_libX11_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
+git-tree-sha1 = "afead5aba5aa507ad5a3bf01f58f82c8d1403495"
+uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc"
+version = "1.8.6+0"
+
+[[deps.Xorg_libXau_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "6035850dcc70518ca32f012e46015b9beeda49d8"
+uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec"
+version = "1.0.11+0"
+
+[[deps.Xorg_libXcursor_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"]
+git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd"
+uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724"
+version = "1.2.0+4"
+
+[[deps.Xorg_libXdmcp_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "34d526d318358a859d7de23da945578e8e8727b7"
+uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05"
+version = "1.1.4+0"
+
+[[deps.Xorg_libXext_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
+git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3"
+uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3"
+version = "1.3.4+4"
+
+[[deps.Xorg_libXfixes_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
+git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4"
+uuid = "d091e8ba-531a-589c-9de9-94069b037ed8"
+version = "5.0.3+4"
+
+[[deps.Xorg_libXi_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"]
+git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246"
+uuid = "a51aa0fd-4e3c-5386-b890-e753decda492"
+version = "1.7.10+4"
+
+[[deps.Xorg_libXinerama_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"]
+git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123"
+uuid = "d1454406-59df-5ea1-beac-c340f2130bc3"
+version = "1.1.4+4"
+
+[[deps.Xorg_libXrandr_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"]
+git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631"
+uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484"
+version = "1.5.2+4"
+
+[[deps.Xorg_libXrender_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
+git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96"
+uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa"
+version = "0.9.10+4"
+
+[[deps.Xorg_libpthread_stubs_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "8fdda4c692503d44d04a0603d9ac0982054635f9"
+uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74"
+version = "0.1.1+0"
+
+[[deps.Xorg_libxcb_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"]
+git-tree-sha1 = "b4bfde5d5b652e22b9c790ad00af08b6d042b97d"
+uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b"
+version = "1.15.0+0"
+
+[[deps.Xorg_libxkbfile_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"]
+git-tree-sha1 = "730eeca102434283c50ccf7d1ecdadf521a765a4"
+uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a"
+version = "1.1.2+0"
+
+[[deps.Xorg_xcb_util_cursor_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_jll", "Xorg_xcb_util_renderutil_jll"]
+git-tree-sha1 = "04341cb870f29dcd5e39055f895c39d016e18ccd"
+uuid = "e920d4aa-a673-5f3a-b3d7-f755a4d47c43"
+version = "0.1.4+0"
+
+[[deps.Xorg_xcb_util_image_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
+git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97"
+uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b"
+version = "0.4.0+1"
+
+[[deps.Xorg_xcb_util_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"]
+git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1"
+uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5"
+version = "0.4.0+1"
+
+[[deps.Xorg_xcb_util_keysyms_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
+git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00"
+uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7"
+version = "0.4.0+1"
+
+[[deps.Xorg_xcb_util_renderutil_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
+git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e"
+uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e"
+version = "0.3.9+1"
+
+[[deps.Xorg_xcb_util_wm_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
+git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67"
+uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361"
+version = "0.4.1+1"
+
+[[deps.Xorg_xkbcomp_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxkbfile_jll"]
+git-tree-sha1 = "330f955bc41bb8f5270a369c473fc4a5a4e4d3cb"
+uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4"
+version = "1.4.6+0"
+
+[[deps.Xorg_xkeyboard_config_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xkbcomp_jll"]
+git-tree-sha1 = "691634e5453ad362044e2ad653e79f3ee3bb98c3"
+uuid = "33bec58e-1273-512f-9401-5d533626f822"
+version = "2.39.0+0"
+
+[[deps.Xorg_xtrans_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "e92a1a012a10506618f10b7047e478403a046c77"
+uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10"
+version = "1.5.0+0"
+
+[[deps.Zlib_jll]]
+deps = ["Libdl"]
+uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
+version = "1.2.13+1"
+
+[[deps.Zstd_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "e678132f07ddb5bfa46857f0d7620fb9be675d3b"
+uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
+version = "1.5.6+0"
+
+[[deps.eudev_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "gperf_jll"]
+git-tree-sha1 = "431b678a28ebb559d224c0b6b6d01afce87c51ba"
+uuid = "35ca27e7-8b34-5b7f-bca9-bdc33f59eb06"
+version = "3.2.9+0"
+
+[[deps.fzf_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "a68c9655fbe6dfcab3d972808f1aafec151ce3f8"
+uuid = "214eeab7-80f7-51ab-84ad-2988db7cef09"
+version = "0.43.0+0"
+
+[[deps.gperf_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "3516a5630f741c9eecb3720b1ec9d8edc3ecc033"
+uuid = "1a1c6b14-54f6-533d-8383-74cd7377aa70"
+version = "3.1.1+0"
+
+[[deps.libaom_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "3a2ea60308f0996d26f1e5354e10c24e9ef905d4"
+uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b"
+version = "3.4.0+0"
+
+[[deps.libass_jll]]
+deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
+git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47"
+uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
+version = "0.15.1+0"
+
+[[deps.libblastrampoline_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"
+version = "5.8.0+1"
+
+[[deps.libevdev_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "141fe65dc3efabb0b1d5ba74e91f6ad26f84cc22"
+uuid = "2db6ffa8-e38f-5e21-84af-90c45d0032cc"
+version = "1.11.0+0"
+
+[[deps.libfdk_aac_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55"
+uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
+version = "2.0.2+0"
+
+[[deps.libinput_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "eudev_jll", "libevdev_jll", "mtdev_jll"]
+git-tree-sha1 = "ad50e5b90f222cfe78aa3d5183a20a12de1322ce"
+uuid = "36db933b-70db-51c0-b978-0f229ee0e533"
+version = "1.18.0+0"
+
+[[deps.libpng_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"]
+git-tree-sha1 = "d7015d2e18a5fd9a4f47de711837e980519781a4"
+uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
+version = "1.6.43+1"
+
+[[deps.libvorbis_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"]
+git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c"
+uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
+version = "1.3.7+1"
+
+[[deps.mtdev_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "814e154bdb7be91d78b6802843f76b6ece642f11"
+uuid = "009596ad-96f7-51b1-9f1b-5ce2d5e8a71e"
+version = "1.1.6+0"
+
+[[deps.nghttp2_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
+version = "1.52.0+1"
+
+[[deps.p7zip_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
+version = "17.4.0+2"
+
+[[deps.x264_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2"
+uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
+version = "2021.5.5+0"
+
+[[deps.x265_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9"
+uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
+version = "3.5.0+0"
+
+[[deps.xkbcommon_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"]
+git-tree-sha1 = "9c304562909ab2bab0262639bd4f444d7bc2be37"
+uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd"
+version = "1.4.1+1"
+"""
+
+# ╔═╡ Cell order:
+# ╟─4ca1549e-032b-11ef-20d2-cb42a75438d9
+# ╟─77ca8f1b-f25c-437d-94fc-31b339a50896
+# ╟─f8b368dd-e8c2-4545-896b-19b797dd54a0
+# ╠═39a79b7c-e90f-45ff-b0f1-dad9dfc60326
+# ╠═c03de0c2-6b63-414b-9b14-ff33713ffb7a
+# ╠═c79e01d1-c12a-4cc5-b1db-e180bad6fe6b
+# ╠═f3307af3-2f92-47d4-8063-e0e7a30ae917
+# ╠═af77440d-7baa-46c2-9036-68760c978234
+# ╠═623384dc-13dd-44d1-9b2e-b70148025d34
+# ╠═b1a19883-ee37-40fb-94fc-29525c1f50fd
+# ╠═fd3b4502-cb18-4458-8829-9a25976539e3
+# ╠═077ab2ef-0163-4af0-ad1e-eae1c6b6752c
+# ╠═b0a15759-1a50-4d91-b1fa-8c717bbb2897
+# ╠═c7efabb7-9bac-4fb7-8224-edbd67a2ad0a
+# ╠═264bad21-433e-4fe0-802e-54f9ed0c1023
+# ╟─7ddc04a4-5bca-4fc4-9e18-3de693c541a3
+# ╠═fbb91e4e-46aa-4500-a834-1b45a6fd3b1c
+# ╠═a9dc9e90-5952-40aa-a6c7-28cb874a3ad6
+# ╟─a2453b84-5ca7-4dd3-862e-5f77a1d37133
+# ╠═4d2b08ef-605e-4692-b912-7427c736871c
+# ╟─fbe936db-94ea-43d3-a245-168cb91be386
+# ╠═62ed1c01-5344-4003-acb3-95c19de4ea9c
+# ╟─81a4a902-3d0d-49fe-bf98-573be6e6a80e
+# ╠═02676896-eb60-4c61-9ba2-60c1ead6edb9
+# ╟─37e0c8b3-abe9-4e2e-a795-ce4210333c5d
+# ╠═545abe38-58b0-402c-b151-f84e4e07b9a4
+# ╠═6b18bee0-aadc-40f1-8e67-99b1ed69bdce
+# ╠═b3865fbc-9f5d-4ff3-93b4-8f8ae96e7a93
+# ╠═44e7f9cb-9f9a-41dc-88ba-b12bd1308fcd
+# ╠═098be928-fb24-4200-b2cf-9bfdd597b2bc
+# ╠═68120cab-374d-4aa9-b540-bed15bc45cbe
+# ╠═64f0d118-0af0-4923-8414-fc5872a232be
+# ╠═cc7deb70-aaad-4963-9332-9098e53b648f
+# ╟─a9b7b3b2-5369-4702-a239-4a1e2714c691
+# ╠═774d436b-f4fd-46cc-bc53-5edcde07fe45
+# ╟─34224be0-a3f2-4c05-b7ee-f0fe41706329
+# ╠═ad189673-c33b-4bd7-bbb0-54e2f01ca72e
+# ╟─9419a61c-32d6-42ef-84cb-2eb1853b2ee2
+# ╟─6eb28333-0020-42a6-b1d5-d3f968d6caf1
+# ╟─5d32c3d4-3f80-47d7-b0d3-eab4e444269d
+# ╠═2a34a59b-5079-4abe-a914-9565e1e87c0c
+# ╟─c8636f2d-bf7b-46d3-915f-20d52280d38d
+# ╠═13a58ade-bfd3-4c7d-b885-933f92815f1d
+# ╠═072d7d32-e7df-403d-b98e-f4d8806658de
+# ╠═0d6e7b13-f0cb-4e68-984b-a97766580598
+# ╠═ac898a8a-296a-4ed0-9703-6397ef001249
+# ╟─00000000-0000-0000-0000-000000000001
+# ╟─00000000-0000-0000-0000-000000000002