text:
### A Pluto.jl notebook ###
# v0.16.0

using Markdown
using InteractiveUtils

# ╔═╡ 889697ff-7f5a-4106-95f7-ca7a294faeb3
begin
	using JSServe
	Page()
end

# ╔═╡ 6946373c-8035-485b-9048-7b4d0fc6428f
using WGLMakie, Distributions, LinearAlgebra

# ╔═╡ cf1c3faa-1973-11ec-04bf-1f53406ce76b
md"""
# Chapter 1: Landmark location

For our first experiment, let's estimate the location of a **landmark**, some feature that we want to keep track of.

The true position of the landmark is a two-dimensional vector

```math
\mathbf{s} = \begin{bmatrix}
x_0 \\
y_0
\end{bmatrix}
```

At every time step, we'll take a measurement ``\mathbf{z}_t`` of the location of the landmark. This measurement will necessarily have some noise in it. We'll model the noise with an additive Gaussian term:

```math
\mathbf{z}_t = \mathbf{s} + \varepsilon_t
```

where the noise ``\varepsilon_t`` is multivariate normally distributed with a mean of zero and a covariance matrix Q:

```math
\varepsilon_t \sim \mathcal{N}(0,Q)
```

Because the noise is additive and Gaussian, we can write the distribution of each observation ``\mathbf{z}_t`` as

```math
\mathbf{z}_t | \mathbf{s} \sim \mathcal{N}(\mathbf{s},Q)
```

This is a *conditional distribution*: if we fix the position of the landmark at ``\mathbf{s}``, then the observations are independently and identically distributed with a multivariate normal distribution with mean ``\mathbf{s}`` and covariance $Q$.

To see what this model looks like, let's generate a data set. We'll fix our landmark at the origin (``\mathbf{s} = [0,0]``) and create some observations. Let's assume that the covariance matrix is diagonal with a variance of 1 for each component:

```math
Q = \begin{bmatrix}
1 & 0 \\
0 & 1
\end{bmatrix}
```
"""

# ╔═╡ 592cb2f4-7c38-4ecd-b0fc-50d9e409f928
# Landmark position
s = [0.0;0.0]

# ╔═╡ 3f91f4e8-e0c9-4f1f-a5a0-7cdfc8bb9d6b
# Covariance matrix
Q = [1.0 0.0;
	0.0 1.0]

# ╔═╡ 4c06bac4-05b8-4883-b3ca-3da505783fdc
# Distribution of observations
d = MvNormal(s,Q)

# ╔═╡ 54ec7d97-477e-4887-a73a-502eeba97910
# Number of observations
N = 10

# ╔═╡ 7c36f709-7bb0-4986-8337-e6dea6fc7690
# Observation data set
Z = rand(d,N)

# ╔═╡ bc925405-7574-46d4-aa59-7e32bc1acaf7
begin
	fig = Figure()
	ax1 = Axis(fig[1,1],xlabel="X",ylabel="Y")
	scatter!(ax1,Z,color=:black)
	scatter!(ax1,Point2[s],color=:red)
	fig
end

# ╔═╡ 94c08534-71fd-4265-9212-edf76b4517bf
md"""
If we don't know the position of the landmark, but we do have the measurements ``\mathbf{z}_{1:T} = [\mathbf{z}_1,\mathbf{z}_2,\dots,\mathbf{z}_T]``, how do we go about estimating the landmark's position? There are many different ways to do this, and we'll work up from the simplest one: maximum likelihood estimation.

## Maximum likelihood estimation

Recall our probabilistic model for the observations:

```math
\mathbf{z}_t | \mathbf{s} \sim \mathcal{N}(\mathbf{s},Q)
```

This model defines a probability distribution for the whole data set, ``p(\mathbf{z}_{1:T}|\mathbf{s})``.

```math
p(\mathbf{z}_{1:T}|\mathbf{s}) = \prod_{t=1}^T p(\mathbf{z}_t|\mathbf{s}) \propto \prod_{t=1}^T e^{-\frac{1}{2} \left(\mathbf{z}_t - \mathbf{s}\right)^\dagger Q^{-1} \left(\mathbf{z}_t - \mathbf{s}\right)}
```

The first equality here is because we assume that our observations are independently and identically distributed, and thus the joint distribution of the observations ``p(\mathbf{z}_{1:T}|\mathbf{s})`` factors into the product of the distribution of the individual observations. The second equality substitutes the expression for a multivariate normal distribution. We use the ``\propto`` symbol to indicate that we have dropped some terms that don't depend on ``\mathbf{z}_t$ or $\mathbf{s}``.

For convenience, we'll work with the logarithm of this distribution, which is called the (log-)likelihood function

```math
\log p(\mathbf{z}_{1:T}|\mathbf{s}) = \sum_{t=1}^T \log p(\mathbf{z}_t|\mathbf{s}) = \sum_{t=1}^T -\frac{1}{2} \left(\mathbf{z}_t - \mathbf{s}\right)^\dagger Q^{-1} \left(\mathbf{z}_t - \mathbf{s}\right)
```

To estimate ``\mathbf{s}`` by maximum likelihood, we want to find the value of ``\mathbf{s}`` that maximizes this expression when we fix our observations ``\mathbf{z}_{1:T}`` to our dataset. We can find the maximum likelihood estimator, ``\mathbf{s}``, by taking the derivative of the likelihood function with respect to ``\mathbf{s}`` and setting the resulting expression equal to zero. Once we've worked through the algebra, we find that

```math
\hat{\mathbf{s}} = \frac{1}{T}\sum_{t=1}^T \mathbf{z}_t
```

and we see that the maximum likelihood estimator of the position of the landmark is the mean of the observations. Let's plot that along with our dataset.
"""

# ╔═╡ e4b53a36-860b-4c3a-b9c9-6f6eafcaeeb9
# Compute the maximum likelihood estimator
ŝ = mean(Z,dims=2)[:,1]

# ╔═╡ 8b342e24-759b-4ce4-9349-1c46aebe6cad
begin
	fig2 = Figure()
	ax2 = Axis(fig2[1,1],xlabel="X",ylabel="Y")
	scatter!(ax2,Z,color=:black)
	scatter!(ax2,Point2[s],color=:red)
	scatter!(ax2,Point2[ŝ],color=:orange)
	fig2
end

# ╔═╡ dbf4d333-b34a-40ce-b6cf-3a17a20cda8f
md"""
There is a difference between the maximum likelihood estimator and the true landmark position. We will always have some error, and the magnitude of that error basically depends on how many observations we have. With more observations, the average error will shrink and, as the number of observations approaches infinity, the error will go to zero: our maximum likelihood estimator is *consistent*.

We can illustrate this property by simulating a bunch of data sets of different sizes and computing the root mean squared error between the maximum likelihood estimator and the true landmark position.
"""

# ╔═╡ 6312899f-e92b-42d6-977a-fe8fe8b63011
function rms_error_simulation(N)
    # Simulate a new data set of size N
    Z = rand(d,N)

    # Compute the maximum likelihood estimator of the landmark
    ŝ = mean(Z,dims=2)[:,1]

    # Return the distance between s and ŝ
    sqrt(sum(abs2,s .- ŝ))
end

# ╔═╡ 62c45184-2e26-4186-9f16-0b4d33944053
# Simulate 100 times for each value of N from 10 to 10000
errors = [mean(rms_error_simulation(N) for i in 1:100) for N in 10:100:10000]

# ╔═╡ 20610ddc-5160-458d-badd-850046a087e2
begin
	fig3 = Figure()
	ax3 = Axis(fig3[1,1],
    xlabel="Number of observations",
    ylabel="Root mean square error"
	)
	lines!(ax3,10:100:10000,errors)
	fig3
end

# ╔═╡ 12a3d2e5-7f9f-4b8b-94d4-87911e8ad699
md"""
The error decreases with the number of observations and, while it does flatten out as the number of observations increases, it will indeed go to zero as ``N \to \infty`` (it decreases like ``\frac{1}{\sqrt{N}}``).

The maximum likelihood estimator of the landmark location is consistent, and it is really easy to compute: just take the mean of the observations. However, we'll find that the maximum likelihood estimator is not so easy to compute in the more complicated models that we'll encounter in the future. We'll turn to Bayesian inference methods to handle these more complicated models, and we'll start our exploration of Bayesian methods by thinking about the landmark location model sequentially.

## Sequential inference

In the localization and mapping problems that we'll encounter throughout this series, we acquire observations at separate times, and we want our robot to incorporate each observation into its map of the environment when that observation is acquired. We can do this with our maximum likelihood estimator, ``\hat{\mathbf{s}}``. We say that the maximum likelihood estimate of the landmark location at time ``t`` is ``\hat{\mathbf{s}}_t``, then we can update it with an observation at time ``t+1`` by:

```math
\hat{\mathbf{s}}_{t+1} = \frac{1}{t+1} \left(t\hat{\mathbf{s}}_t + \mathbf{z}_t\right)
```

But for more complicated models, this update may not be so simple. Instead, we will represent our current map of the environment by a probability distribution

```math
p_t(\mathbf{s}) = p\left(\mathbf{s}|\mathbf{z}_{1:t}\right)
```

The map at time ``t`` is the conditional distribution of ``\mathbf{s}`` given all of the observations up to and including ``\mathbf{z}_t``.

Bayes' rule tells us how to update ``p_t(\mathbf{s})`` to ``p_{t+1}(\mathbf{s})``:

```math
p_{t+1}(\mathbf{s}) = p(\mathbf{s}|\mathbf{z}_{1:t+1}) = \frac{p(\mathbf{z}_{t+1}|\mathbf{s},\mathbf{z}_{1:t}) p(\mathbf{s}|\mathbf{z}_{1:t})}{p(\mathbf{z}_{t+1})} = \frac{p(\mathbf{z}_{t+1}|\mathbf{s},\mathbf{z}_{1:t})}{p(\mathbf{z}_{t+1})} p_t(\mathbf{s})
```

The first term in the numerator of Bayes' rule ``p(\mathbf{z}_{t+1}|\mathbf{s},\mathbf{z}_{1:t})`` is called the *likelihood*, and it is similar to our likelihood function from before in that it tells us the probability of obtaining an observation ``\mathbf{z}_{t+1}`` given that the landmark is at location ``\mathbf{s}`` and that we've seen the observations ``\mathbf{z}_{1:t}``. Because our model tells us that the observations are independent and identically distributed given the landmark location, ``\mathbf{z}_{t+1}`` is actually conditionally independent of ``\mathbf{z}_{1:t}``, and this part of the likelihood drops out

```math
p(\mathbf{z}_{t+1} | \mathbf{s}, \mathbf{z}_{1:t}) = p(\mathbf{z}_{t+1}|\mathbf{s})
```

which is exactly the same likelihood function we saw before.

The second term in the numerator is just our distribution ``p_t(\mathbf{s})``. This is the *prior distribution* because it reflects a probability distribution over ``\mathbf{s}`` before we have incorporated the next measurement. Bayes' rule tells us how to update the prior distribution ``p_t(\mathbf{s})`` into the *posterior distribution* ``p_{t+1}(\mathbf{s})``. The rule is recursive: we start with a probability distribution ``p_0(\mathbf{s})`` that reflects our uncertainty in the location of ``\mathbf{s}`` before we have seen any data, and from that distribution, we can add information from the observations to form ``p_t(\mathbf{s})`` at any time. While ``p_t(\mathbf{s})`` plays the role of the prior distribution in Bayes' rule when we incorporate the observation ``\mathbf{z}_{t+1}``, ``p_0(\mathbf{s})`` is usually what is meant by the prior distribution in Bayesian statistics: the distribution before we have seen any data.

The denominator is the *marginal probability distribution* of ``\mathbf{z}_{t+1}``. This is given by integrating the numerator over the landmark location

```math
p(\mathbf{z}_{t+1}) = \int p(\mathbf{z}_{t+1}|\mathbf{s}) p(\mathbf{s}|\mathbf{z}_{1:t})\ \mathrm{d}\mathbf{s}
```

Computing this integral is the hard part in Bayesian statistics, and we'll encounter many different ways of calculating it analytically or approximating it when we can't.

### Sequential Bayesian inference for the landmark location model

Our model above says that the observation ``\mathbf{z}_t`` conditioned on the landmark location ``\mathbf{s}`` is multivariate normal with mean ``\mathbf{s}`` and covariance ``Q``.

```math
\mathbf{z}_t | \mathbf{s} \sim \mathcal{N}(\mathbf{s},Q)
```

This gives us the likelihood we need for Bayes' rule.

To complete the specification of our Bayesian model, we need to define the prior distribution ``p_0(\mathbf{s})``. It turns out that everything will be very simple if we let the prior distribution also be a multivariate Gaussian with mean ``\boldsymbol{\mu}_0`` and covariance ``\Sigma_0``. We will write

```math
\mathbf{s} \sim \mathcal{N}(\boldsymbol{\mu}_0,\Sigma_0)
```

to say that ``\mathbf{s}`` has this prior distribution, i.e. that

```math
p_0(\mathbf{s}) \propto e^{-\frac{1}{2} (\mathbf{s} - \boldsymbol{\mu}_0)^\dagger \Sigma_0^{-1} (\mathbf{s} - \boldsymbol{\mu}_0)}
```

Let's specify our prior distribution with a mean of zero and a variance of 100 in each dimension. The high variance reflects a high initial uncertainty about the landmark's location.
"""

# ╔═╡ f4751245-b653-45fb-8950-0043fdc20018
begin
	μ₀ = [0.0;0.0]
	Σ₀ = [100.0 0.0;0.0 100.0]
	p₀ = MvNormal(μ₀,Σ₀)
end

# ╔═╡ de7b4d82-f035-4f26-989a-bbe0f5d6daa6
md"""
Let's focus on updating this prior distribution with the information from our first observation ``\mathbf{z}_1``. We write Bayes' rule

```math
p(\mathbf{s}|\mathbf{z}_1) = \frac{p(\mathbf{z}_1|\mathbf{s})}{p(\mathbf{z}_1)} p_0(\mathbf{s})
```

To make some of the algebra easier, let's take the logarithm of both sides of this equation

```math
\log p(\mathbf{s}|\mathbf{z}_1) = \log p(\mathbf{z}_1|\mathbf{s}) + \log p_0(\mathbf{s}) - \log p(\mathbf{z}_1)
```

and substitute in our expressions for the likelihood and the prior

```math
\log p(\mathbf{s}|\mathbf{z}_1) = -\frac{1}{2}(\mathbf{z}_1 - \mathbf{s})^\dagger Q^{-1}(\mathbf{z}_1 - \mathbf{s}) - \frac{1}{2}(\mathbf{s} - \boldsymbol{\mu}_0)^\dagger \Sigma_0^{-1} (\mathbf{s} - \boldsymbol{\mu}_0) - \log p(\mathbf{z}_1) + C
```

where the constant ``C`` contains some terms that we won't worry about right now because they don't depend on ``\mathbf{s}``.

We still haven't written down what the marginal distribution ``p(\mathbf{z}_1)`` is. However, we don't really need to do that at this point. ``p(\mathbf{z}_1)`` doesn't depend on ``\mathbf{s}`` at all, and we can include it in the constant ``C``. There are times when we will want to compute the marginal distribution, but now is not one of them.

Our log posterior density is

```math
\log p(\mathbf{s}|\mathbf{z}_1) = -\frac{1}{2}(\mathbf{z}_1 - \mathbf{s})^\dagger Q^{-1}(\mathbf{z}_1 - \mathbf{s}) - \frac{1}{2}(\mathbf{s} - \boldsymbol{\mu}_0)^\dagger \Sigma_0^{-1} (\mathbf{s} - \boldsymbol{\mu}_0) + C
```

which we might not immediately recognize as a familiar probability distribution. But we can expand the quadratic functions of ``\mathbf{s}`` to find:

```math
\log p(\mathbf{s}|\mathbf{z}_1) = -\frac{1}{2} \left( \mathbf{s}^\dagger \left(Q^{-1} + \Sigma_0^{-1}\right) \mathbf{s} - 2\mathbf{s}^\dagger\left(Q^{-1}\mathbf{z}_1 + \Sigma_0^{-1} \boldsymbol{\mu}_0\right)\right) + C
```

Messing around a bit further with the algebra, we ultimately find that the posterior distribution is a multivariate normal with a mean

```math
\boldsymbol{\mu}_1 = \left(Q^{-1} + \Sigma_0^{-1}\right)^{-1} \left(Q^{-1}\mathbf{z}_1 + \Sigma_0^{-1}\boldsymbol{\mu}\right)
```

and covariance

```math
\Sigma_1 = \left(Q^{-1} + \Sigma_0^{-1}\right)^{-1}
```

These are the update equations that we need, and it will work the same for updating at any time step: simply replace ``\boldsymbol{\mu}_0`` and ``\Sigma_0`` on the right-hand side of these equations with ``\boldsymbol{\mu}_t`` and ``\Sigma_t``, and the observation ``\mathbf{z}_1`` with ``\mathbf{z}_{t+1}`` to find the updated mean and covariance ``\boldsymbol{\mu}_{t+1}`` and ``\Sigma_{t+1}``.

Let's see how this works in practice. We'll first implement our update equations
"""

# ╔═╡ 8a174193-2916-4a01-a2c9-8663e7f4aca2
function update(p₀,z,Q)
	μ₀,Σ₀ = p₀.μ,p₀.Σ
    Σ₁ = inv(inv(Q) + inv(Σ₀))
    μ₁ = Σ₁ * (Q\z + Σ₀\μ₀)
    MvNormal(μ₁,Σ₁)
end

# ╔═╡ 90007f4c-1ded-4a08-afa7-a5c344b6c03b
md"""
And then we'll apply the update equations to our model by scanning through the data set one point at a type, updating the probability distribution as we go. We can do this simply with the `accumulate` function.
"""

# ╔═╡ ab3b1a1b-8e74-47cf-9b95-df044e2fb86b
md"""
The contours represent the posterior probability density function, with the yellow contour surrounding the area with the highest probability density. As we add observations by moving the slider to the right, we can see how the contours shrink and the maximum of the probability density moves towards the origin, which is the true location of the landmark.

### Another parameterization

The update equations in their current form are slightly complicated. One particularly annoying problem is that you have to invert a couple of matrices to figure out the covariance. This isn't too bad when we're working with 2x2 covariance matrices, but with models that have more degrees of freedom, we'd like to avoid inverting big matrices both because it is slow and because it can lead to numerical problems if we're not careful.

We've parameterized our posterior probability density with its mean ``\boldsymbol{\mu}_t`` and covariance ``\Sigma_t``, which leads to the log posterior probability

```math
\log p(\mathbf{s}|\mathbf{z}_{1:t}) = -\frac{1}{2} \left(\mathbf{s} - \boldsymbol{\mu}_t\right)^{\dagger} \Sigma_t^{-1} \left(\mathbf{s} - \boldsymbol{\mu}_t\right) + C
```

If we expand the quadratic form and put the terms that don't depend on ``\mathbf{s}`` in the constant, we end up with

```math
\log p(\mathbf{s}|\mathbf{z}_{1:t}) = -\frac{1}{2} \mathbf{s}^{\dagger}\Sigma_t^{-1}\mathbf{s} + \Sigma_t^{-1}\boldsymbol{\mu}_t^{\dagger}\mathbf{s} + C
```

The coefficients in this parameterization of the multivariate normal distribution are

```math
\begin{align}
\Lambda_t &= \Sigma_t^{-1} \\
\mathbf{j}_t &= \Sigma_t^{-1} \boldsymbol{\mu}_t
\end{align}
```

We call the matrix ``\Lambda_t`` the *precision matrix* and the vector $\mathbf{j}_t$ the *potential vector* or the *information vector*. With these substitutions, the posterior log probability density becomes

```math
\log p(\mathbf{s}|\mathbf{z}_{1:t}) = -\frac{1}{2} \mathbf{s}^{\dagger}\Lambda_t\mathbf{s} + \mathbf{j}_t^{\dagger}\mathbf{s} + C
```

We can represent any multivariate normal distribution with this parameterization. For example, our prior distribution with ``\boldsymbol{\mu}_0 = 0`` and ``\Sigma_t = \begin{bmatrix} 100 & 0 \\ 0 & 100 \end{bmatrix}`` has a precision matrix ``\Lambda_0 = \begin{bmatrix} 0.01 & 0 \\ 0 & 0.01 \end{bmatrix}`` and a potential vector ``\mathbf{j}_0 = 0``

The benefit of this parameterization is that the update equations become very simple:

```math
\begin{align}
\Lambda_{t+1} &= \Lambda_t + Q^{-1} \\
\mathbf{j}_{t+1} &= \mathbf{j}_t + Q^{-1}\mathbf{z}_{t+1}
\end{align}
```

If we store ``Q^{-1}`` rather than ``Q``, we don't need to invert any matrices to update our probability distribution.
"""

# ╔═╡ 329dae9e-a9b4-4608-bc6e-88953679ea1a
Qi = inv(Q)

# ╔═╡ b00453b8-beb5-4e5f-ac75-ec0d4acc8e72
md"""
The Distributions package gives us an `MvNormalCanon` type that uses this "canonical" parameterization directly. We can create a new prior distribution using the canonical parameterization.
"""

# ╔═╡ bd6bbe7d-5e46-4bab-8d75-6439614a747d
begin
	Λ₀ = inv(Σ₀)
	j₀ = Σ₀\μ₀
	q₀ = MvNormalCanon(j₀,Λ₀)
end

# ╔═╡ cd9b1e2a-8049-4c44-8d52-c7dcd146708f
md"""
And we can rewrite our update method to work on canonically parameterized distributions. We need to be careful to pass the inverse of the observation noise covariance rather than the the noise covariance.
"""

# ╔═╡ 68107d23-f41e-46cc-b6ac-b3195651c35b
function update(q₀::D,z,Qi) where {D <: MvNormalCanon}
	j₀,Λ₀ = q₀.h,q₀.J

	j₁ = j₀ + Qi*z
	Λ₁ = Λ₀ + Qi
	MvNormalCanon(j₁,Λ₁)
end

# ╔═╡ 55a37b10-7163-4887-942c-1b2d42b7330b
begin
	Zs = Point2[Z[:,i] for i in 1:N]
	ps = [p₀;accumulate((p,z) -> update(p,z,Q),Zs,init=p₀)]
end

# ╔═╡ 2985b01b-c602-4cb5-80b2-b39457f3686d
begin

	fig4 = Figure()
	ax4 = Axis(fig4[1,1],xlabel="X",ylabel="Y")
	b1 = Makie.Slider(fig4[2,1],range=0:10)

	xs = range(-10,10,length=256)

	P = lift(b1.value) do i
		[pdf(ps[i+1],[x;y]) for x in xs, y in xs]
	end

	obs = lift(b1.value) do i
		if i == 0
			[Point2(20,20.0)]
		else
			Zs[1:i]
		end
	end

	contour!(ax4,xs,xs,P)
	scatter!(ax4,obs,color=:black)

	xlims!(ax4,-10,10)
	ylims!(ax4,-10,10)
	fig4
end

# ╔═╡ 5b07dc5d-6676-4d93-bb4a-7296beded4c3
md"""
And apply our new parameterization to our data set.
"""

# ╔═╡ 18cb7c76-5721-4023-b475-edaf410ea1da
qs = [q₀;accumulate((q,z) -> update(q,z,Qi),Zs,init=q₀)]

# ╔═╡ a098c5b0-6734-4bd2-90d7-5daf69cfd111
md"""
We can visualize the results the same way, and they should look the same. We haven't changed the model, just how we write the model.
"""

# ╔═╡ 51369139-452b-4fe9-a441-9f0f13713faf
begin

	fig5 = Figure()
	ax5 = Axis(fig5[1,1],xlabel="X",ylabel="Y")
	sl5 = Makie.Slider(fig5[2,1],range=0:N)

	P5 = lift(sl5.value) do i
		[pdf(qs[i+1],[x;y]) for x in xs, y in xs]
	end

	obs5 = lift(sl5.value) do i
		if i == 0
			[Point2(20,20.0)]
		else
			Zs[1:i]
		end
	end

	contour!(ax5,xs,xs,P5)
	scatter!(ax5,obs5,color=:black)

	xlims!(ax5,-10,10)
	ylims!(ax5,-10,10)
	fig5
end

# ╔═╡ b7c5a266-8264-4829-a040-7d11fe635b8a
md"""
This canonical parameterization is very useful for Bayesian inference problems because the Bayesian update equations become simple additions. There are tradeoffs, though. You have to solve a system of linear equations to recover the mean of the posterior distribution, which is also the maximum a posteriori estimate of the landmark location. Computing the marginal probability ``p(\mathbf{z}_t)`` is also harder in the canonical parameterization. So you have to choose which is right for the particular application you are using, and we'll flip back and forth throughout these experiments.

That's it for our first lesson. In future lessons, we'll look at increasingly complicated localization and mapping problems and how we can solve them with Bayesian inference.
"""

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
JSServe = "824d6782-a2ef-11e9-3a09-e5662e0c26f9"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
WGLMakie = "276b4fcb-3e11-5398-bf8b-a0c2d153d008"

[compat]
Distributions = "~0.25.16"
JSServe = "~1.2.3"
WGLMakie = "~0.4.6"
"""

# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised

[[AbstractFFTs]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "485ee0867925449198280d4af84bdb46a2a404d0"
uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c"
version = "1.0.1"

[[AbstractTrees]]
git-tree-sha1 = "03e0550477d86222521d254b741d470ba17ea0b5"
uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
version = "0.3.4"

[[Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.1"

[[Animations]]
deps = ["Colors"]
git-tree-sha1 = "e81c509d2c8e49592413bfb0bb3b08150056c79d"
uuid = "27a7e980-b3e6-11e9-2bcd-0b925532e340"
version = "0.4.1"

[[ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

[[ArrayInterface]]
deps = ["Compat", "IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"]
git-tree-sha1 = "b8d49c34c3da35f220e7295659cd0bab8e739fed"
uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
version = "3.1.33"

[[Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[Automa]]
deps = ["Printf", "ScanByte", "TranscodingStreams"]
git-tree-sha1 = "d50976f217489ce799e366d9561d56a98a30d7fe"
uuid = "67c07d97-cdcb-5c2c-af73-a7f9c32a568b"
version = "0.8.2"

[[AxisAlgorithms]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"]
git-tree-sha1 = "a4d07a1c313392a77042855df46c5f534076fab9"
uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950"
version = "1.0.0"

[[Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.8+0"

[[CEnum]]
git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9"
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
version = "0.4.1"

[[Cairo_jll]]
deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "f2202b55d816427cd385a9a4f3ffb226bee80f99"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+0"

[[ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "4ce9393e871aca86cc457d9f66976c3da6902ea7"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.4.0"

[[CodecZlib]]
deps = ["TranscodingStreams", "Zlib_jll"]
git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da"
uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
version = "0.7.0"

[[ColorBrewer]]
deps = ["Colors", "JSON", "Test"]
git-tree-sha1 = "61c5334f33d91e570e1d0c3eb5465835242582c4"
uuid = "a2cac450-b92f-5266-8821-25eda20663c8"
version = "0.4.0"

[[ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
git-tree-sha1 = "9995eb3977fbf67b86d0a0a0508e83017ded03f2"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.14.0"

[[ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[ColorVectorSpace]]
deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"]
git-tree-sha1 = "a66a8e024807c4b3d186eb1cab2aff3505271f8e"
uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4"
version = "0.9.6"

[[Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"

[[Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "4866e381721b30fac8dda4c8cb1d9db45c8d2994"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.37.0"

[[CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

[[Contour]]
deps = ["StaticArrays"]
git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7"
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
version = "0.5.7"

[[DataAPI]]
git-tree-sha1 = "bec2532f8adb82005476c141ec23e921fc20971b"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.8.0"

[[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "7d9d316f04214f7efdbb6398d545446e246eff02"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.10"

[[DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"

[[Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[DelimitedFiles]]
deps = ["Mmap"]
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"

[[Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

[[Distributions]]
deps = ["ChainRulesCore", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns"]
git-tree-sha1 = "f4efaa4b5157e0cdb8283ae0b5428bc9208436ed"
uuid = "31c24e10-a181-5473-b8eb-7969acd0382f"
version = "0.25.16"

[[DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.5"

[[Downloads]]
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"

[[EarCut_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d"
uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
version = "2.2.3+0"

[[EllipsisNotation]]
deps = ["ArrayInterface"]
git-tree-sha1 = "8041575f021cba5a099a456b4163c9a08b566a02"
uuid = "da5c29d0-fa7d-589e-88eb-ea29b0a81949"
version = "1.1.0"

[[Expat_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.2.10+0"

[[FFMPEG]]
deps = ["FFMPEG_jll"]
git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8"
uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
version = "0.4.1"

[[FFMPEG_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f"
uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
version = "4.4.0+0"

[[FFTW]]
deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"]
git-tree-sha1 = "463cb335fa22c4ebacfd1faba5fde14edb80d96c"
uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
version = "1.4.5"

[[FFTW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea"
uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a"
version = "3.3.10+0"

[[FileIO]]
deps = ["Pkg", "Requires", "UUIDs"]
git-tree-sha1 = "3c041d2ac0a52a12a27af2782b34900d9c3ee68c"
uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
version = "1.11.1"

[[FillArrays]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"]
git-tree-sha1 = "caf289224e622f518c9dbfe832cdafa17d7c80a6"
uuid = "1a297f60-69ca-5386-bcde-b61e274b549b"
version = "0.12.4"

[[FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.4"

[[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"

[[Formatting]]
deps = ["Printf"]
git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8"
uuid = "59287772-0a20-5a39-b81b-1366585eb4c0"
version = "0.4.2"

[[FreeType]]
deps = ["CEnum", "FreeType2_jll"]
git-tree-sha1 = "cabd77ab6a6fdff49bfd24af2ebe76e6e018a2b4"
uuid = "b38be410-82b0-50bf-ab77-7b57e271db43"
version = "4.0.0"

[[FreeType2_jll]]
deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9"
uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
version = "2.10.4+0"

[[FreeTypeAbstraction]]
deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics", "StaticArrays"]
git-tree-sha1 = "19d0f1e234c13bbfd75258e55c52aa1d876115f5"
uuid = "663a7486-cb36-511b-a19d-713bb74d65c9"
version = "0.9.2"

[[FriBidi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91"
uuid = "559328eb-81f9-559d-9380-de523a88c83c"
version = "1.0.10+0"

[[GeometryBasics]]
deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"]
git-tree-sha1 = "58bcdf5ebc057b085e58d95c138725628dd7453c"
uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
version = "0.4.1"

[[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"

[[Glib_jll]]
deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "7bf67e9a481712b3dbe9cb3dac852dc4b1162e02"
uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
version = "2.68.3+0"

[[Graphics]]
deps = ["Colors", "LinearAlgebra", "NaNMath"]
git-tree-sha1 = "2c1cf4df419938ece72de17f368a021ee162762e"
uuid = "a2bd30eb-e257-5431-a919-1863eab51364"
version = "1.1.0"

[[Graphite2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011"
uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472"
version = "1.3.14+0"

[[GridLayoutBase]]
deps = ["GeometryBasics", "InteractiveUtils", "Match", "Observables"]
git-tree-sha1 = "e2f606c87d09d5187bb6069dab8cee0af7c77bdb"
uuid = "3955a311-db13-416c-9275-1d80ed98e5e9"
version = "0.6.1"

[[Grisu]]
git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2"
uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe"
version = "1.0.2"

[[HTTP]]
deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"]
git-tree-sha1 = "60ed5f1643927479f845b0135bb369b031b541fa"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.14"

[[HarfBuzz_jll]]
deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"]
git-tree-sha1 = "8a954fed8ac097d5be04921d595f741115c1b2ad"
uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566"
version = "2.8.1+0"

[[Hyperscript]]
deps = ["Test"]
git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9"
uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
version = "0.0.4"

[[IfElse]]
git-tree-sha1 = "28e837ff3e7a6c3cdb252ce49fb412c8eb3caeef"
uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
version = "0.1.0"

[[ImageCore]]
deps = ["AbstractFFTs", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Graphics", "MappedArrays", "MosaicViews", "OffsetArrays", "PaddedViews", "Reexport"]
git-tree-sha1 = "595155739d361589b3d074386f77c107a8ada6f7"
uuid = "a09fc81d-aa75-5fe9-8630-4744c3626534"
version = "0.9.2"

[[ImageIO]]
deps = ["FileIO", "Netpbm", "OpenEXR", "PNGFiles", "TiffImages", "UUIDs"]
git-tree-sha1 = "13c826abd23931d909e4c5538643d9691f62a617"
uuid = "82e4d734-157c-48bb-816b-45c225c6df19"
version = "0.5.8"

[[ImageMagick]]
deps = ["FileIO", "ImageCore", "ImageMagick_jll", "InteractiveUtils", "Libdl", "Pkg", "Random"]
git-tree-sha1 = "5bc1cb62e0c5f1005868358db0692c994c3a13c6"
uuid = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
version = "1.2.1"

[[ImageMagick_jll]]
deps = ["JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pkg", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "1c0a2295cca535fabaf2029062912591e9b61987"
uuid = "c73af94c-d91f-53ed-93a7-00f77d67a9d7"
version = "6.9.10-12+3"

[[Imath_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "87f7662e03a649cffa2e05bf19c303e168732d3e"
uuid = "905a6f67-0a94-5f89-b386-d35d92009cd1"
version = "3.1.2+0"

[[IndirectArrays]]
git-tree-sha1 = "012e604e1c7458645cb8b436f8fba789a51b257f"
uuid = "9b13fd28-a010-5f03-acff-a1bbcff69959"
version = "1.0.0"

[[Inflate]]
git-tree-sha1 = "f5fc07d4e706b84f72d54eedcc1c13d92fb0871c"
uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9"
version = "0.1.2"

[[IniFile]]
deps = ["Test"]
git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.0"

[[IntelOpenMP_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d979e54b71da82f3a65b62553da4fc3d18c9004c"
uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0"
version = "2018.0.3+2"

[[InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[Interpolations]]
deps = ["AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"]
git-tree-sha1 = "61aa005707ea2cebf47c8d780da8dc9bc4e0c512"
uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
version = "0.13.4"

[[IntervalSets]]
deps = ["Dates", "EllipsisNotation", "Statistics"]
git-tree-sha1 = "3cc368af3f110a767ac786560045dceddfc16758"
uuid = "8197267c-284f-5f27-9208-e0e47529a953"
version = "0.5.3"

[[IrrationalConstants]]
git-tree-sha1 = "f76424439413893a832026ca355fe273e93bce94"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.1.0"

[[Isoband]]
deps = ["isoband_jll"]
git-tree-sha1 = "f9b6d97355599074dc867318950adaa6f9946137"
uuid = "f1662d9f-8043-43de-a69a-05efc1cc6ff4"
version = "0.1.1"

[[IterTools]]
git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.3.0"

[[IteratorInterfaceExtensions]]
git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
uuid = "82899510-4779-5014-852e-03e436cf321d"
version = "1.0.0"

[[JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

[[JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.2"

[[JSON3]]
deps = ["Dates", "Mmap", "Parsers", "StructTypes", "UUIDs"]
git-tree-sha1 = "b3e5984da3c6c95bcf6931760387ff2e64f508f3"
uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
version = "1.9.1"

[[JSServe]]
deps = ["Base64", "CodecZlib", "Colors", "HTTP", "Hyperscript", "JSON3", "LinearAlgebra", "Markdown", "MsgPack", "Observables", "SHA", "Sockets", "Tables", "Test", "UUIDs", "WebSockets", "WidgetsBase"]
git-tree-sha1 = "91101a4b8ac8eefeed6ca8eb4f663fc660e4d9f9"
uuid = "824d6782-a2ef-11e9-3a09-e5662e0c26f9"
version = "1.2.3"

[[JpegTurbo_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943"
uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
version = "2.1.0+0"

[[KernelDensity]]
deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"]
git-tree-sha1 = "591e8dc09ad18386189610acafb970032c519707"
uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b"
version = "0.6.3"

[[LAME_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c"
uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d"
version = "3.100.1+0"

[[LZO_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6"
uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac"
version = "2.10.1+0"

[[LaTeXStrings]]
git-tree-sha1 = "c7f1c695e06c01b95a67f0cd1d34994f3e7db104"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.2.1"

[[LazyArtifacts]]
deps = ["Artifacts", "Pkg"]
uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"

[[LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"

[[LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"

[[LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[Libffi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "761a393aeccd6aa92ec3515e428c26bf99575b3b"
uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
version = "3.2.2+0"

[[Libgcrypt_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"]
git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae"
uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4"
version = "1.8.7+0"

[[Libgpg_error_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9"
uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
version = "1.42.0+0"

[[Libiconv_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778"
uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
version = "1.16.1+1"

[[Libmount_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73"
uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9"
version = "2.35.0+0"

[[Libtiff_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.3.0+0"

[[Libuuid_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066"
uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700"
version = "2.36.0+0"

[[LinearAlgebra]]
deps = ["Libdl"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[LogExpFunctions]]
deps = ["ChainRulesCore", "DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "34dc30f868e368f8a17b728a1238f3fcda43931a"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.3"

[[Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"

[[MKL_jll]]
deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"]
git-tree-sha1 = "5455aef09b40e5020e1520f551fa3135040d4ed0"
uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7"
version = "2021.1.1+2"

[[Makie]]
deps = ["Animations", "Base64", "ColorBrewer", "ColorSchemes", "ColorTypes", "Colors", "Contour", "Distributions", "DocStringExtensions", "FFMPEG", "FileIO", "FixedPointNumbers", "Formatting", "FreeType", "FreeTypeAbstraction", "GeometryBasics", "GridLayoutBase", "ImageIO", "IntervalSets", "Isoband", "KernelDensity", "LaTeXStrings", "LinearAlgebra", "MakieCore", "Markdown", "Match", "MathTeXEngine", "Observables", "Packing", "PlotUtils", "PolygonOps", "Printf", "Random", "RelocatableFolders", "Serialization", "Showoff", "SignedDistanceFields", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "StatsFuns", "StructArrays", "UnicodeFun"]
git-tree-sha1 = "7e49f989e7c7f50fe55bd92d45329c9cf3f2583d"
uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
version = "0.15.2"

[[MakieCore]]
deps = ["Observables"]
git-tree-sha1 = "7bcc8323fb37523a6a51ade2234eee27a11114c8"
uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b"
version = "0.1.3"

[[MappedArrays]]
git-tree-sha1 = "e8b359ef06ec72e8c030463fe02efe5527ee5142"
uuid = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900"
version = "0.4.1"

[[Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[Match]]
git-tree-sha1 = "5cf525d97caf86d29307150fcba763a64eaa9cbe"
uuid = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf"
version = "1.1.0"

[[MathTeXEngine]]
deps = ["AbstractTrees", "Automa", "DataStructures", "FreeTypeAbstraction", "GeometryBasics", "LaTeXStrings", "REPL", "RelocatableFolders", "Test"]
git-tree-sha1 = "f5c8789464aed7058107463e5cef53e6ad3f1f3e"
uuid = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53"
version = "0.2.0"

[[MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"]
git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe"
uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
version = "1.0.3"

[[MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.0.2"

[[Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[MosaicViews]]
deps = ["MappedArrays", "OffsetArrays", "PaddedViews", "StackViews"]
git-tree-sha1 = "b34e3bc3ca7c94914418637cb10cc4d1d80d877d"
uuid = "e94cdb99-869f-56ef-bcf0-1ae2bcbe0389"
version = "0.3.3"

[[MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[MsgPack]]
deps = ["Serialization"]
git-tree-sha1 = "a8cbf066b54d793b9a48c5daa5d586cf2b5bd43d"
uuid = "99f44e22-a591-53d1-9472-aa23ef4bd671"
version = "1.1.0"

[[NaNMath]]
git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "0.3.5"

[[Netpbm]]
deps = ["FileIO", "ImageCore"]
git-tree-sha1 = "18efc06f6ec36a8b801b23f076e3c6ac7c3bf153"
uuid = "f09324ee-3d7c-5217-9330-fc30815ba969"
version = "1.0.2"

[[NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[Observables]]
git-tree-sha1 = "fe29afdef3d0c4a8286128d4e45cc50621b1e43d"
uuid = "510215fc-4207-5dde-b226-833fc4488ee2"
version = "0.4.0"

[[OffsetArrays]]
deps = ["Adapt"]
git-tree-sha1 = "c0e9e582987d36d5a61e650e6e543b9e44d9914b"
uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
version = "1.10.7"

[[Ogg_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f"
uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051"
version = "1.3.5+0"

[[OpenEXR]]
deps = ["Colors", "FileIO", "OpenEXR_jll"]
git-tree-sha1 = "327f53360fdb54df7ecd01e96ef1983536d1e633"
uuid = "52e1d378-f018-4a11-a4be-720524705ac7"
version = "0.3.2"

[[OpenEXR_jll]]
deps = ["Artifacts", "Imath_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "923319661e9a22712f24596ce81c54fc0366f304"
uuid = "18a262bb-aa17-5467-a713-aee519bc75cb"
version = "3.1.1+0"

[[OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "1.1.10+0"

[[OpenSpecFun_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1"
uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.5+0"

[[Opus_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720"
uuid = "91d4177d-7536-5919-b921-800302f37372"
version = "1.3.2+0"

[[OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[PCRE_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488"
uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc"
version = "8.44.0+0"

[[PDMats]]
deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"]
git-tree-sha1 = "4dd403333bcf0909341cfe57ec115152f937d7d8"
uuid = "90014a1f-27ba-587c-ab20-58faa44d9150"
version = "0.11.1"

[[PNGFiles]]
deps = ["Base64", "CEnum", "ImageCore", "IndirectArrays", "OffsetArrays", "libpng_jll"]
git-tree-sha1 = "e14c485f6beee0c7a8dcf6128bf70b85f1fe201e"
uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883"
version = "0.3.9"

[[Packing]]
deps = ["GeometryBasics"]
git-tree-sha1 = "1155f6f937fa2b94104162f01fa400e192e4272f"
uuid = "19eb6ba3-879d-56ad-ad62-d5c202156566"
version = "0.4.2"

[[PaddedViews]]
deps = ["OffsetArrays"]
git-tree-sha1 = "646eed6f6a5d8df6708f15ea7e02a7a2c4fe4800"
uuid = "5432bcbf-9aad-5242-b902-cca2824c8663"
version = "0.5.10"

[[Parsers]]
deps = ["Dates"]
git-tree-sha1 = "438d35d2d95ae2c5e8780b330592b6de8494e779"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.0.3"

[[Pixman_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29"
uuid = "30392449-352a-5448-841d-b1acce4e97dc"
version = "0.40.1+0"

[[Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[PkgVersion]]
deps = ["Pkg"]
git-tree-sha1 = "a7a7e1a88853564e551e4eba8650f8c38df79b37"
uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688"
version = "0.1.1"

[[PlotUtils]]
deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"]
git-tree-sha1 = "2537ed3c0ed5e03896927187f5f2ee6a4ab342db"
uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
version = "1.0.14"

[[PolygonOps]]
git-tree-sha1 = "c031d2332c9a8e1c90eca239385815dc271abb22"
uuid = "647866c9-e3ac-4575-94e7-e3d426903924"
version = "0.1.1"

[[Preferences]]
deps = ["TOML"]
git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"

[[Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[ProgressMeter]]
deps = ["Distributed", "Printf"]
git-tree-sha1 = "afadeba63d90ff223a6a48d2009434ecee2ec9e8"
uuid = "92933f4c-e287-5a05-a399-4b506db050ca"
version = "1.7.1"

[[QuadGK]]
deps = ["DataStructures", "LinearAlgebra"]
git-tree-sha1 = "78aadffb3efd2155af139781b8a8df1ef279ea39"
uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
version = "2.4.2"

[[REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[Random]]
deps = ["Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[Ratios]]
deps = ["Requires"]
git-tree-sha1 = "01d341f502250e81f6fec0afe662aa861392a3aa"
uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
version = "0.4.2"

[[Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

[[RelocatableFolders]]
deps = ["SHA", "Scratch"]
git-tree-sha1 = "0529f4188bc8efee85a7e580aca1c7dff6b103f8"
uuid = "05181044-ff0b-4ac5-8273-598c1e38db00"
version = "0.1.0"

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

[[Rmath]]
deps = ["Random", "Rmath_jll"]
git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f"
uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa"
version = "0.7.0"

[[Rmath_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "68db32dff12bb6127bac73c209881191bf0efbb7"
uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f"
version = "0.3.0+0"

[[SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[SIMD]]
git-tree-sha1 = "9ba33637b24341aba594a2783a502760aa0bff04"
uuid = "fdea26ae-647d-5447-a871-4b548cad5224"
version = "3.3.1"

[[ScanByte]]
deps = ["Libdl", "SIMD"]
git-tree-sha1 = "9cc2955f2a254b18be655a4ee70bc4031b2b189e"
uuid = "7b38b023-a4d7-4c5e-8d43-3f3097f304eb"
version = "0.3.0"

[[Scratch]]
deps = ["Dates"]
git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda"
uuid = "6c6a2e73-6563-6170-7368-637461726353"
version = "1.1.0"

[[Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[ShaderAbstractions]]
deps = ["ColorTypes", "FixedPointNumbers", "GeometryBasics", "LinearAlgebra", "Observables", "StaticArrays", "StructArrays", "Tables"]
git-tree-sha1 = "0d97c895406b552bed78f3a1fe9925248e908ae2"
uuid = "65257c39-d410-5151-9873-9b3e5be5013e"
version = "0.2.8"

[[SharedArrays]]
deps = ["Distributed", "Mmap", "Random", "Serialization"]
uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"

[[Showoff]]
deps = ["Dates", "Grisu"]
git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de"
uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
version = "1.0.3"

[[SignedDistanceFields]]
deps = ["Random", "Statistics", "Test"]
git-tree-sha1 = "d263a08ec505853a5ff1c1ebde2070419e3f28e9"
uuid = "73760f76-fbc4-59ce-8f25-708e95d2df96"
version = "0.4.0"

[[Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[SortingAlgorithms]]
deps = ["DataStructures"]
git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508"
uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
version = "1.0.1"

[[SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[SpecialFunctions]]
deps = ["ChainRulesCore", "LogExpFunctions", "OpenSpecFun_jll"]
git-tree-sha1 = "a322a9493e49c5f3a10b50df3aedaf1cdb3244b7"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "1.6.1"

[[StackViews]]
deps = ["OffsetArrays"]
git-tree-sha1 = "46e589465204cd0c08b4bd97385e4fa79a0c770c"
uuid = "cae243ae-269e-4f55-b966-ac2d0dc13c15"
version = "0.1.1"

[[Static]]
deps = ["IfElse"]
git-tree-sha1 = "a8f30abc7c64a39d389680b74e749cf33f872a70"
uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
version = "0.3.3"

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "3240808c6d463ac46f1c1cd7638375cd22abbccb"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.12"

[[Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[StatsAPI]]
git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.0.0"

[[StatsBase]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "8cbbc098554648c84f79a463c9ff0fd277144b6c"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.33.10"

[[StatsFuns]]
deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"]
git-tree-sha1 = "46d7ccc7104860c38b11966dd1f72ff042f382e4"
uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
version = "0.9.10"

[[StructArrays]]
deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"]
git-tree-sha1 = "2ce41e0d042c60ecd131e9fb7154a3bfadbf50d3"
uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
version = "0.6.3"

[[StructTypes]]
deps = ["Dates", "UUIDs"]
git-tree-sha1 = "8445bf99a36d703a09c601f9a57e2f83000ef2ae"
uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"
version = "1.7.3"

[[SuiteSparse]]
deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"]
uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"

[[TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"

[[TableTraits]]
deps = ["IteratorInterfaceExtensions"]
git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
version = "1.0.1"

[[Tables]]
deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"]
git-tree-sha1 = "1162ce4a6c4b7e31e0e6b14486a6986951c73be9"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.5.2"

[[Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"

[[TensorCore]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6"
uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50"
version = "0.1.1"

[[Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[TiffImages]]
deps = ["ColorTypes", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "OffsetArrays", "OrderedCollections", "PkgVersion", "ProgressMeter"]
git-tree-sha1 = "632a8d4dbbad6627a4d2d21b1c6ebcaeebb1e1ed"
uuid = "731e570b-9d59-4bfa-96dc-6df516fadf69"
version = "0.4.2"

[[TranscodingStreams]]
deps = ["Random", "Test"]
git-tree-sha1 = "216b95ea110b5972db65aa90f88d8d89dcb8851c"
uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
version = "0.9.6"

[[URIs]]
git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.3.0"

[[UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[[Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[UnicodeFun]]
deps = ["REPL"]
git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf"
uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1"
version = "0.4.1"

[[WGLMakie]]
deps = ["Colors", "FileIO", "FreeTypeAbstraction", "GeometryBasics", "Hyperscript", "ImageMagick", "JSServe", "LinearAlgebra", "Makie", "Observables", "ShaderAbstractions", "StaticArrays"]
git-tree-sha1 = "bafa1c4ab77626f8d8199209b740e097ae03805f"
uuid = "276b4fcb-3e11-5398-bf8b-a0c2d153d008"
version = "0.4.6"

[[WebSockets]]
deps = ["Base64", "Dates", "HTTP", "Logging", "Sockets"]
git-tree-sha1 = "f91a602e25fe6b89afc93cf02a4ae18ee9384ce3"
uuid = "104b5d7c-a370-577a-8038-80a2059c5097"
version = "1.5.9"

[[WidgetsBase]]
deps = ["Observables"]
git-tree-sha1 = "c1ef6e02bc457c3b23aafc765b94c3dcd25f174d"
uuid = "eead4739-05f7-45a1-878c-cee36b57321c"
version = "0.1.3"

[[WoodburyMatrices]]
deps = ["LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "59e2ad8fd1591ea019a5259bd012d7aee15f995c"
uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6"
version = "0.5.3"

[[XML2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a"
uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
version = "2.9.12+0"

[[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"

[[Xorg_libX11_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527"
uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc"
version = "1.6.9+4"

[[Xorg_libXau_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e"
uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec"
version = "1.0.9+4"

[[Xorg_libXdmcp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4"
uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05"
version = "1.1.3+4"

[[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"

[[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"

[[Xorg_libpthread_stubs_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb"
uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74"
version = "0.1.0+3"

[[Xorg_libxcb_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"]
git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6"
uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b"
version = "1.13.0+3"

[[Xorg_xtrans_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845"
uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10"
version = "1.4.0+3"

[[Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[Zstd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.0+0"

[[isoband_jll]]
deps = ["Libdl", "Pkg"]
git-tree-sha1 = "a1ac99674715995a536bbce674b068ec1b7d893d"
uuid = "9a68df92-36a6-505f-a73e-abb412b6bfb4"
version = "0.2.2+0"

[[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"

[[libfdk_aac_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55"
uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
version = "2.0.2+0"

[[libpng_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c"
uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
version = "1.6.38+0"

[[libvorbis_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"]
git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb"
uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
version = "1.3.7+0"

[[nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"

[[x264_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2"
uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
version = "2021.5.5+0"

[[x265_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9"
uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
version = "3.5.0+0"
"""

# ╔═╡ Cell order:
# ╠═889697ff-7f5a-4106-95f7-ca7a294faeb3
# ╠═6946373c-8035-485b-9048-7b4d0fc6428f
# ╟─cf1c3faa-1973-11ec-04bf-1f53406ce76b
# ╠═592cb2f4-7c38-4ecd-b0fc-50d9e409f928
# ╠═3f91f4e8-e0c9-4f1f-a5a0-7cdfc8bb9d6b
# ╠═4c06bac4-05b8-4883-b3ca-3da505783fdc
# ╠═54ec7d97-477e-4887-a73a-502eeba97910
# ╠═7c36f709-7bb0-4986-8337-e6dea6fc7690
# ╟─bc925405-7574-46d4-aa59-7e32bc1acaf7
# ╟─94c08534-71fd-4265-9212-edf76b4517bf
# ╠═e4b53a36-860b-4c3a-b9c9-6f6eafcaeeb9
# ╟─8b342e24-759b-4ce4-9349-1c46aebe6cad
# ╟─dbf4d333-b34a-40ce-b6cf-3a17a20cda8f
# ╠═6312899f-e92b-42d6-977a-fe8fe8b63011
# ╠═62c45184-2e26-4186-9f16-0b4d33944053
# ╟─20610ddc-5160-458d-badd-850046a087e2
# ╟─12a3d2e5-7f9f-4b8b-94d4-87911e8ad699
# ╠═f4751245-b653-45fb-8950-0043fdc20018
# ╟─de7b4d82-f035-4f26-989a-bbe0f5d6daa6
# ╠═8a174193-2916-4a01-a2c9-8663e7f4aca2
# ╟─90007f4c-1ded-4a08-afa7-a5c344b6c03b
# ╠═55a37b10-7163-4887-942c-1b2d42b7330b
# ╟─2985b01b-c602-4cb5-80b2-b39457f3686d
# ╟─ab3b1a1b-8e74-47cf-9b95-df044e2fb86b
# ╠═329dae9e-a9b4-4608-bc6e-88953679ea1a
# ╟─b00453b8-beb5-4e5f-ac75-ec0d4acc8e72
# ╠═bd6bbe7d-5e46-4bab-8d75-6439614a747d
# ╟─cd9b1e2a-8049-4c44-8d52-c7dcd146708f
# ╠═68107d23-f41e-46cc-b6ac-b3195651c35b
# ╟─5b07dc5d-6676-4d93-bb4a-7296beded4c3
# ╠═18cb7c76-5721-4023-b475-edaf410ea1da
# ╟─a098c5b0-6734-4bd2-90d7-5daf69cfd111
# ╟─51369139-452b-4fe9-a441-9f0f13713faf
# ╟─b7c5a266-8264-4829-a040-7d11fe635b8a
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002

max_stars_repo_name: wkearn/SLAMNotes

max_issues_repo_name: wkearn/SLAMNotes

max_forks_repo_name: wkearn/SLAMNotes


text:
# ---
# title: 204. Count Primes
# id: problem204
# author: AquaIndigo
# date: 2020-12-03
# difficulty: Easy
# categories: Hash Table, Math
# link: <https://leetcode.com/problems/count-primes/description/>
# hidden: true
# ---
#
# Count the number of prime numbers less than a non-negative number, `n`.
#
#
#
# **Example 1:**
#
#
#
#     Input: n = 10
#     Output: 4
#     Explanation: There are 4 prime numbers less than 10, they are 2, 3, 5, 7.
#
#
# **Example 2:**
#
#
#
#     Input: n = 0
#     Output: 0
#
#
# **Example 3:**
#
#
#
#     Input: n = 1
#     Output: 0
#
#
#
#
# **Constraints:**
#
#   * `0 <= n <= 5 * 106`
#
#
## @lc code=start
using LeetCode

function count_primes(n::Int)
    if n <= 1
        return 0
    end
    arr = fill(true, n - 1)
    for i in 2 : n - 1
        for j in i ^ 2 : i : (n - 1)
            arr[j] = false
        end
    end
    return sum(arr) - 1
end
## @lc code=end

ext: jl


text:
using Statistics
using CUDA
using Oceananigans.Architectures
using Oceananigans.AbstractOperations: AbstractOperation

using OffsetArrays: OffsetArray
using Oceananigans.ImmersedBoundaries: ImmersedBoundaryGrid

import Base: getindex, size, show, minimum, maximum
import Statistics: mean

import Oceananigans.Fields: AbstractField, Field, minimum, maximum, mean, location, short_show, set!
import Oceananigans.Grids: new_data
import Oceananigans.BoundaryConditions: FieldBoundaryConditions

struct CubedSphereFaces{E, F}
    faces :: F
end

function CubedSphereFaces(faces::F) where F
    E = typeof(faces[1])
    return CubedSphereFaces{E, F}(faces)
end

@inline Base.getindex(f::CubedSphereFaces, i::Int) = @inbounds f.faces[i]

#####
##### Dispatch the world / insane type unions
#####

const CubedSphereData = CubedSphereFaces{<:OffsetArray}

# Some dispatch foo to make a type union for CubedSphereFaceField...
#
# Conformal cubed sphere grid wrapped in ImmersedBoundaryGrid:
const ImmersedConformalCubedSphereFaceGrid = ImmersedBoundaryGrid{FT, TX, TY, TZ, <:ConformalCubedSphereFaceGrid} where {FT, TX, TY, TZ}

# CubedSphereFaceField:
const NonImmersedCubedSphereFaceField = AbstractField{LX, LY, LZ, <:ConformalCubedSphereFaceGrid} where {LX, LY, LZ}
const ImmersedCubedSphereFaceField    = AbstractField{LX, LY, LZ, <:ImmersedConformalCubedSphereFaceGrid} where {LX, LY, LZ}

const CubedSphereFaceField = Union{NonImmersedCubedSphereFaceField{LX, LY, LZ},
                                      ImmersedCubedSphereFaceField{LX, LY, LZ}} where {LX, LY, LZ}

# CubedSphereField

# Flavors of CubedSphereField
const CubedSphereField{LX, LY, LZ} =
    Union{Field{LX, LY, LZ, <:Nothing, <:ConformalCubedSphereGrid},
          Field{LX, LY, LZ, <:AbstractOperation, <:ConformalCubedSphereGrid}}

const CubedSphereAbstractField{LX, LY, LZ} = AbstractField{LX, LY, LZ, <:ConformalCubedSphereGrid}

const AbstractCubedSphereField{LX, LY, LZ} =
    Union{CubedSphereAbstractField{LX, LY, LZ},
                  CubedSphereField{LX, LY, LZ}}

#####
##### new data
#####

function new_data(FT, grid::ConformalCubedSphereGrid, (LX, LY, LZ))
    faces = Tuple(new_data(FT, face_grid, (LX, LY, LZ)) for face_grid in grid.faces)
    return CubedSphereFaces{typeof(faces[1]), typeof(faces)}(faces)
end

#####
##### FieldBoundaryConditions
#####

function FieldBoundaryConditions(grid::ConformalCubedSphereGrid, (LX, LY, LZ); user_defined_bcs...)

    faces = Tuple(
        inject_cubed_sphere_exchange_boundary_conditions(
            FieldBoundaryConditions(face_grid, (LX, LY, LZ); user_defined_bcs...),
            face_index,
            grid.face_connectivity
        )
        for (face_index, face_grid) in enumerate(grid.faces)
    )

    return CubedSphereFaces{typeof(faces[1]), typeof(faces)}(faces)
end

#####
##### Utils
#####

function Base.show(io::IO, field::Union{CubedSphereField, AbstractCubedSphereField})
    LX, LY, LZ = location(field)
    arch = architecture(field)
    A = typeof(arch)
    return print(io, "$(typeof(field).name.wrapper) at ($LX, $LY, $LZ)\n",
          "├── architecture: $A\n",
          "└── grid: $(short_show(field.grid))")
end

@inline function interior(field::AbstractCubedSphereField)
    faces = Tuple(interior(face_field_face) for face_field in faces(field))
    return CubedSphereFaces(faces)
end

Base.size(field::CubedSphereField) = size(field.data)
Base.size(data::CubedSphereData) = (size(data.faces[1])..., length(data.faces))

@inline get_face(field::CubedSphereField, face_index) =
    Field(location(field), get_face(field.grid, face_index);
          data = get_face(field.data, face_index),
          boundary_conditions = get_face(field.boundary_conditions, face_index))

faces(field::AbstractCubedSphereField) = Tuple(get_face(field, face_index) for face_index in 1:length(field.data.faces))

#####
##### set!
#####

function cubed_sphere_set!(u, v)
    for face = 1:length(u.grid.faces)
        set!(get_face(u, face), get_face(v, face))
    end
    return nothing
end

# Resolve ambiguities
set!(u::CubedSphereField, v) = cubed_sphere_set!(u, v)
set!(u::CubedSphereField, v::Function) = cubed_sphere_set!(u, v)
set!(u::CubedSphereField, v::Union{Array, CuArray, OffsetArray}) = cubed_sphere_set!(u, v)
set!(u::CubedSphereField, v::CubedSphereField) = cubed_sphere_set!(u, v)

#####
##### Random utils
#####

minimum(field::AbstractCubedSphereField; dims=:) = minimum(minimum(face_field; dims) for face_field in faces(field))
maximum(field::AbstractCubedSphereField; dims=:) = maximum(maximum(face_field; dims) for face_field in faces(field))
mean(field::AbstractCubedSphereField; dims=:) = mean(mean(face_field; dims) for face_field in faces(field))

minimum(f::Function, field::AbstractCubedSphereField; dims=:) = minimum(minimum(f, face_field; dims) for face_field in faces(field))
maximum(f::Function, field::AbstractCubedSphereField; dims=:) = maximum(maximum(f, face_field; dims) for face_field in faces(field))
mean(f::Function, field::AbstractCubedSphereField; dims=:) = mean(mean(f, face_field; dims) for face_field in faces(field))

λnodes(field::CubedSphereFaceField{LX, LY, LZ}) where {LX, LY, LZ} = λnodes(LX(), LY(), LZ(), field.grid)
φnodes(field::CubedSphereFaceField{LX, LY, LZ}) where {LX, LY, LZ} = φnodes(LX(), LY(), LZ(), field.grid)


text:
function fav(x::Vector{Float64},Vs::Float64,vs::Float64,ts::Float64,zs::Float64,
    Vlv::Float64,zeta::Float64,Q::Float64,rho::Float64,beta::Float64,W2root::Float64,
    c0::Float64,Kvo::Float64,Kvc::Float64,Ks::Float64,E::Float64,V0::Float64,
    A0::Float64,Aann::Float64,leff::Float64,h::Float64,state::String)

    if length(x) == 3
        f = zeros(3);
        f[1] = ((Vlv./Vs .- x[2]).*ts./h .- ts.*vs.^5./Vs.*(2.*rho./beta).^2.*
            ((x[1] .- W2root./vs)./8 .+ c0./vs).^4.*((x[1] .+ W2root./vs)./2));
        if state == "opening"
            f[2] = (x[3] .- h.*((1./zs .- x[3]).*Kvo.*(E.*Vs.*(x[2] .- V0./Vs) .-
                beta.*((2.*rho./beta).*vs.^2.*((x[1] .- W2root./vs)./8 .+
                c0./vs).^2 .- sqrt.(A0)))) .- zeta./zs);
            f[3] = (x[3].*(Vlv./Vs .- x[2]).*ts./h .- Aann.*ts./(rho.*leff.*Vs).*
                ((zs.*x[3].^3 .- zeta.*(x[3]).^2)./(Kvo.*(1./zs .- x[3])) .- 1./zs.*
                rho.*Vs.^2./(2.*Aann.^2.*h).*(Vlv./Vs .- x[2]).*
                abs.(Vlv./Vs .- x[2]) .- zs.*x[3].^2.*Ks.*E.*Vs.^2.*(x[2] .- V0./Vs).*
                (Vlv./Vs .- x[2])) .- ts./Vs.*x[3].*Q);
        else
            f[2] = (x[3] .- h.*((x[3]).*Kvc.*(E.*Vs.*(x[2] .- V0./Vs) .-
                beta.*((2.*rho./beta).*vs.^2.*((x[1] .- W2root./vs)./8 .+
                c0./vs).^2 .- sqrt.(A0)))) .- zeta./zs);
            f[3] = (x[3].*(Vlv./Vs .- x[2]).*ts./h .- Aann.*ts./(rho.*leff.*Vs).*
                ((zs.*x[3].^2 .- zeta.*x[3])./Kvc .- 1./zs.*rho.*Vs.^2./(2.*Aann.^2.*
                h).*(Vlv./Vs .- x[2]).*abs.(Vlv./Vs .- x[2]) .- zs.*x[3].^2.*Ks.*
                E.*Vs.^2.*(x[2] .- V0./Vs).*(Vlv./Vs .- x[2])) .- ts./Vs.*x[3].*Q);
        end
    else
        f = zeros(2);
        f[1] = ((Vlv./Vs .- x[2]).*ts./h .- ts.*vs.^5./Vs.*(2.*rho./beta).^2.*
            ((x[1] .- W2root./vs)./8 .+ c0./vs).^4.*((x[1] .+ W2root./vs)./2));
        f[2] = ((Vlv./Vs .- x[2]).*ts./h .- Aann.*ts./(rho.*leff.*Vs).*
            (-1./zs.*rho.*Vs.^2./(2.*Aann.^2.*h).*(Vlv./Vs .- x[2]).*
            abs.(Vlv./Vs .- x[2]) .- zs.*Ks.*E.*Vs.^2.*(x[2] .- V0./Vs).*
            (Vlv./Vs .- x[2])) .- ts./Vs.*Q);
    end
    return f
end

max_stars_repo_name: dcanuto/CardioModeling

max_issues_repo_name: dcanuto/CardioModeling

max_forks_repo_name: dcanuto/CardioModeling


text:
@testset "Basic operations" begin
    for T in (Float32, Float64)
        x = rand(Tensor{Tuple{2,          3,3, 2,@Symmetry{2,2}}, T})
        y = rand(Tensor{Tuple{2,@Symmetry{3,3},@Symmetry{2,2,2}}, T})
        a = 2
        @test size(x) == size(y)
        @test (@inferred x + y)::Tensor{Tuple{2,3,3,2,@Symmetry{2,2}}, T} == Array(x) + Array(y)
        @test (@inferred x - y)::Tensor{Tuple{2,3,3,2,@Symmetry{2,2}}, T} == Array(x) - Array(y)
        @test (@inferred a * x)::typeof(x) == a * Array(x)
        @test (@inferred a * y)::typeof(y) == a * Array(y)
        @test (@inferred x * a)::typeof(x) == a * Array(x)
        @test (@inferred y * a)::typeof(y) == a * Array(y)
        @test (@inferred x / a)::typeof(x) == Array(x) / a
        @test (@inferred y / a)::typeof(y) == Array(y) / a
        @test (@inferred +x)::typeof(x) == x
        @test (@inferred +y)::typeof(y) == y
        @test (@inferred -x)::typeof(x) == -Array(x)
        @test (@inferred -y)::typeof(y) == -Array(y)
        # with Array
        @test (@inferred x + Array(y))::Tensor{Tuple{size(x)...}, T} == Array(x) + Array(y)
        @test (@inferred Array(x) + y)::Tensor{Tuple{size(y)...}, T} == Array(x) + Array(y)
        @test (@inferred x - Array(y))::Tensor{Tuple{size(x)...}, T} == Array(x) - Array(y)
        @test (@inferred Array(x) - y)::Tensor{Tuple{size(y)...}, T} == Array(x) - Array(y)
        # check eltype promotion
        x = Vec(1, 0)
        y = Vec(T(1), 0)
        a = T(0.5)
        @test (@inferred x + y)::Vec{2, T} == Array(x) + Array(y)
        @test (@inferred x - y)::Vec{2, T} == Array(x) - Array(y)
        @test (@inferred a * x)::Vec{2, T} == a * Array(x)
        @test (@inferred x * a)::Vec{2, T} == Array(x) * a
        @test (@inferred x / a)::Vec{2, T} == Array(x) / a
        # bad operations
        @test_throws Exception x * y
        @test_throws Exception y * x
    end
end

@testset "Tensor operations" begin
    @testset "contraction" begin
        for T in (Float32, Float64)
            x = rand(Tensor{Tuple{3,@Symmetry{3,3}}, T})
            y = rand(Tensor{Tuple{@Symmetry{3,3,3}}, T})
            # single contraction
            z = (@inferred contraction(x, y, Val(1)))::Tensor{Tuple{3,3,@Symmetry{3,3}}, T}
            X = Array(x);
            Y = Array(y);
            Z = zeros(T, 3,3,3,3)
            for i in axes(X,1), j in axes(X,2), k in axes(X,3), l in axes(Y,2), m in axes(Y,3)
                Z[i,j,l,m] += X[i,j,k] * Y[k,l,m]
            end
            @test z ≈ Z
            # double contraction
            z = (@inferred contraction(x, y, Val(2)))::Tensor{Tuple{3,3}, T}
            X = Array(x);
            Y = Array(y);
            Z = zeros(T, 3,3)
            for i in axes(X,1), j in axes(X,2), k in axes(X,3), l in axes(Y,3)
                Z[i,l] += X[i,j,k] * Y[j,k,l]
            end
            @test z ≈ Z
            # triple contraction
            z = (@inferred contraction(x, y, Val(3)))::T
            X = Array(x);
            Y = Array(y);
            Z = zero(T)
            for i in axes(X,1), j in axes(X,2), k in axes(X,3)
                Z += X[i,j,k] * Y[i,j,k]
            end
            @test z ≈ Z
            # zero contraction (otimes)
            z = (@inferred contraction(x, y, Val(0)))::Tensor{Tuple{3,@Symmetry{3,3},@Symmetry{3,3,3}}, T}
            X = Array(x);
            Y = Array(y);
            Z = zeros(T, 3,3,3,3,3,3)
            for i in axes(X,1), j in axes(X,2), k in axes(X,3), l in axes(Y,1), m in axes(Y,2), n in axes(Y,3)
                Z[i,j,k,l,m,n] = X[i,j,k] * Y[l,m,n]
            end
            @test z ≈ Z
        end
    end
    @testset "otimes/dot/norm/normalize" begin
        for T in (Float32, Float64)
            # square
            x = rand(Vec{3, T})
            y = rand(Vec{3, T})
            z = (@inferred x ⊗ y)::Tensor{Tuple{3,3}, T}
            @test z ≈ Array(x) * Array(y)'
            @test (@inferred x ⋅ y) ≈ Array(x)' * Array(y)
            @test (@inferred norm(x)) ≈ norm(Array(x))
            @test (@inferred norm(z)) ≈ norm(Array(z))
            @test (@inferred normalize(x))::typeof(x) ≈ normalize(Array(x))
            @test (@inferred normalize(z))::typeof(z) ≈ normalize(Array(z))
            # nonsquare
            x = rand(Vec{3, T})
            y = rand(Vec{2, T})
            z = (@inferred x ⊗ y)::Tensor{Tuple{3,2}, T}
            @test z ≈ Array(x) * Array(y)'
            @test (@inferred norm(z)) ≈ norm(Array(z))
            @test (@inferred normalize(z))::typeof(z) ≈ normalize(Array(z))
        end
    end
    @testset "dotdot" begin
        for T in (Float32, Float64)
            x = rand(Vec{3, T})
            y = rand(Vec{3, T})
            S = rand(SymmetricFourthOrderTensor{3, T})
            A = FourthOrderTensor{3, T}((i,j,k,l) -> S[i,k,j,l])
            @test (@inferred dotdot(x, S, y))::Tensor{Tuple{3,3}, T} ≈ A ⊡ (x ⊗ y)
        end
    end
    @testset "tr" begin
        for T in (Float32, Float64)
            x = rand(SecondOrderTensor{3, T})
            y = rand(SymmetricSecondOrderTensor{3, T})
            # tr
            @test (@inferred tr(x))::T ≈ tr(Array(x))
            @test (@inferred tr(y))::T ≈ tr(Array(y))
        end
    end
    @testset "transpose/adjoint" begin
        for T in (Float32, Float64)
            x = rand(SecondOrderTensor{3, T})
            y = rand(SymmetricSecondOrderTensor{3, T})
            xᵀ = (@inferred transpose(x))::typeof(x)
            @test x' == xᵀ == Array(x)'
            @test (@inferred transpose(y))::typeof(y) == y' == y
        end
    end
    @testset "symmetric" begin
        for T in (Float32, Float64), dim in 1:4
            x = rand(SecondOrderTensor{dim, T})
            y = rand(SymmetricSecondOrderTensor{dim, T})
            @test (@inferred symmetric(x))::SymmetricSecondOrderTensor{dim, T} ≈ (x + x')/2
            @test (@inferred symmetric(x, :U))::SymmetricSecondOrderTensor{dim, T} ≈ Symmetric(Array(x), :U)
            @test (@inferred symmetric(x, :L))::SymmetricSecondOrderTensor{dim, T} ≈ Symmetric(Array(x), :L)
            @test (@inferred symmetric(y))::typeof(y) == y
            @test (@inferred symmetric(y, :U))::typeof(y) == y
            @test (@inferred symmetric(y, :L))::typeof(y) == y
            @test_throws Exception symmetric(x, :X)
            @test_throws Exception symmetric(y, :X)
        end
    end
    @testset "skew" begin
        for T in (Float32, Float64), dim in 1:4
            x = rand(SecondOrderTensor{dim, T})
            @test (@inferred skew(x))::SecondOrderTensor{dim, T} ≈ (x - x') / 2
            @test symmetric(x) + skew(x) ≈ x
            x = rand(SymmetricSecondOrderTensor{dim, T})
            @test (@inferred skew(x))::SecondOrderTensor{dim, T} ≈ zero(SecondOrderTensor{dim})
        end
        for T in (Float32, Float64)
            ω = rand(Vec{3, T})
            @test (@inferred skew(ω))::SecondOrderTensor{3, T} ≈ [ 0    -ω[3]  ω[2]
                                                                   ω[3]  0    -ω[1]
                                                                  -ω[2]  ω[1]  0]
            x = rand(Vec{3, T})
            @test skew(ω) ⋅ x ≈ ω × x
        end
    end
    @testset "det" begin
        for T in (Float32, Float64), dim in 1:4
            Random.seed!(1234)
            x = rand(SecondOrderTensor{dim, T})
            y = rand(SymmetricSecondOrderTensor{dim, T})
            @test (@inferred det(x))::T ≈ det(Array(x))
            @test (@inferred det(y))::T ≈ det(Array(y))
        end
    end
    @testset "cross" begin
        for T in (Float32, Float64), dim in 1:3
            x = rand(Vec{dim, T})
            y = rand(Vec{dim, T})
            @test (@inferred x × x)::Vec{3, T} ≈ zero(Vec{3, T})
            @test x × y ≈ -y × x
            if dim == 2
                a = Vec{2, T}(1,0)
                b = Vec{2, T}(0,1)
                @test (@inferred a × b)::Vec{3, T} ≈ Vec{3, T}(0,0,1)
            end
            if dim == 3
                a = Vec{3, T}(1,0,0)
                b = Vec{3, T}(0,1,0)
                @test (@inferred a × b)::Vec{3, T} ≈ Vec{3, T}(0,0,1)
            end
        end
    end
    @testset "pow" begin
        for T in (Float32, Float64), dim in 1:3
            x = rand(SecondOrderTensor{dim, T})
            y = rand(SymmetricSecondOrderTensor{dim, T})
            fm3, fm2, fm1, f0, fp1, fp2, fp3 = x -> x^-3, x -> x^-2, x -> x^-1, x -> x^0, x -> x^1, x -> x^2, x -> x^3
            @test (@inferred fm3(x))::typeof(x) ≈ inv(x) ⋅ inv(x) ⋅ inv(x)
            @test (@inferred fm2(x))::typeof(x) ≈ inv(x) ⋅ inv(x)
            @test (@inferred fm1(x))::typeof(x) == inv(x)
            @test (@inferred f0(x))::typeof(x) == one(x)
            @test (@inferred fp1(x))::typeof(x) == x
            @test (@inferred fp2(x))::typeof(x) ≈ x ⋅ x
            @test (@inferred fp3(x))::typeof(x) ≈ x ⋅ x ⋅ x
        end
    end
    @testset "rotmat" begin
        for T in (Float32, Float64)
            α = deg2rad(T(10))
            β = deg2rad(T(20))
            γ = deg2rad(T(30))
            for (XYZ, zyx) in ((:XZX, :xzx), (:XYX, :xyx), (:YXY, :yxy), (:YZY, :yzy), (:ZYZ, :zyz), (:ZXZ, :zxz),
                               (:XZY, :yzx), (:XYZ, :zyx), (:YXZ, :zxy), (:YZX, :xzy), (:ZYX, :xyz), (:ZXY, :yxz))
                @test (@inferred rotmat(Vec(α,β,γ), sequence = XYZ))::Mat{3,3,T} ≈ (@inferred rotmat(Vec(γ,β,α), sequence = zyx))::Mat{3,3,T}
                @test (@inferred rotmat(Vec(α,β,γ), sequence = XYZ))::Mat{3,3,T} ≈ (@inferred rotmat(Vec(rad2deg(α),rad2deg(β),rad2deg(γ)), sequence = XYZ, degree = true))::Mat{3,3,T}
                @test (@inferred rotmat(Vec(α,β,γ), sequence = zyx))::Mat{3,3,T} ≈ (@inferred rotmat(Vec(rad2deg(α),rad2deg(β),rad2deg(γ)), sequence = zyx, degree = true))::Mat{3,3,T}
            end
            # 2D rotmat
            @test (@inferred rotmat(α))::Mat{2,2,T} ≈ (@inferred rotmat(rad2deg(α), degree = true))
            @test (@inferred rotmat(α)) ≈ (@inferred rotmatx(α))[[2,3], [2,3]]
            @test (@inferred rotmat(α)) ≈ (@inferred rotmaty(α))[[3,1], [3,1]]
            @test (@inferred rotmat(α)) ≈ (@inferred rotmatz(α))[[1,2], [1,2]]
            # 3D rotmat
            @test (@inferred rotmatx(α))::Mat{3,3,T} ≈ (@inferred rotmatx(rad2deg(α), degree = true))::Mat{3,3,T}
            @test (@inferred rotmaty(α))::Mat{3,3,T} ≈ (@inferred rotmaty(rad2deg(α), degree = true))::Mat{3,3,T}
            @test (@inferred rotmatz(α))::Mat{3,3,T} ≈ (@inferred rotmatz(rad2deg(α), degree = true))::Mat{3,3,T}
            for dim in (2, 3)
                a = normalize(rand(Vec{dim, T}))
                b = normalize(rand(Vec{dim, T}))
                @test (@inferred rotmat(a => b))::Mat{dim, dim, T} ⋅ a ≈ b
            end
            @test (@inferred rotmat(T(π/3), Vec{3, T}(0,0,1)))::Mat{3,3,T} ⋅ Vec(1,0,0) ≈ [cos(π/3), sin(π/3), 0]
            @test (@inferred rotmat(T(60), Vec{3, T}(0,0,1); degree = true))::Mat{3,3,T} ⋅ Vec(1,0,0) ≈ [cos(π/3), sin(π/3), 0]
        end
        @test_throws Exception rotmat(Vec(1,0) => Vec(1,1)) # length of two vectors must be the same
    end
    @testset "rotate" begin
        for T in (Float32, Float64)
            for dim in 2:3
                a = normalize(rand(Vec{dim, T}))
                b = normalize(rand(Vec{dim, T}))
                R = rotmat(a => b)
                v = rand(Vec{dim, T})
                A = rand(SecondOrderTensor{dim, T})
                S = rand(SymmetricSecondOrderTensor{dim, T})
                @test (@inferred rotate(v, R))::Vec{dim, T} ≈ v ⋅ R
                @test (@inferred rotate(A, R))::SecondOrderTensor{dim, T} ≈ R ⋅ A ⋅ R'
                @test (@inferred rotate(S, R))::SymmetricSecondOrderTensor{dim, T} ≈ R ⋅ S ⋅ R'
            end
            # v in 2D, R in 3D
            v = Vec{2, T}(1,0)
            R = rotmatz(T(π/4))
            @test (@inferred rotate(v, R))::Vec{2, T} ≈ (x = rotate(Vec(v[1], v[2], 0), R); Vec(x[1], x[2]))
        end
    end
    @testset "angleaxis" begin
        Random.seed!(1234)
        for T in (Float32, Float64)
            a = normalize(rand(Vec{3, T}))
            b = normalize(rand(Vec{3, T}))
            R = rotmat(a => b)
            @test rotmat((@inferred angleaxis(R))::Tuple{T, Vec{3, T}}...) ≈ R
        end
    end
end

@testset "Call methods in StaticArrays" begin
    @testset "eigen" begin
        for T in (Float32, Float64)
            for dim in (2, 3)
                x = rand(SymmetricSecondOrderTensor{dim, T})
                @test (@inferred eigvals(x)) ≈ eigvals(Array(x))
                @test (@inferred eigen(x)).values ≈ eigen(Array(x)).values
                @test (@inferred eigen(x)).vectors ≈ (@inferred eigvecs(x))
            end
        end
    end
    @testset "exp" begin
        # error for `Float32`
        # see https://github.com/JuliaArrays/StaticArrays.jl/issues/785
        for T in (Float64,)
            for dim in (2, 3)
                x = rand(SecondOrderTensor{dim, T})
                y = rand(SymmetricSecondOrderTensor{dim, T})
                @test (@inferred exp(x))::SecondOrderTensor{dim, T} ≈ exp(Array(x))
                @test (@inferred exp(y))::SymmetricSecondOrderTensor{dim, T} ≈ exp(Array(y))
            end
        end
    end
    @testset "diag/diagm" begin
        x = @Mat [1 2 3
                  4 5 6
                  7 8 9]
        @test @inferred(diag(x)) === Vec(1,5,9)
        @test @inferred(diag(x, Val(1))) === Vec(2,6)
        @test @inferred(diag(x, Val(2))) === Vec(3)
        @test @inferred(diag(x, Val(3))) === Vec{0,Int}()
        @test @inferred(diag(x, Val(-1))) === Vec(4,8)
        @test @inferred(diag(x, Val(-2))) === Vec(7)
        @test @inferred(diag(x, Val(-3))) === Vec{0,Int}()
        d = Vec(1,2,3)
        @test @inferred(diagm(d)) === @Mat [1 0 0
                                            0 2 0
                                            0 0 3]
        @test @inferred(diagm(Val(1)=>d, Val(-1)=>d)) === @Mat [0 1 0 0
                                                                1 0 2 0
                                                                0 2 0 3
                                                                0 0 3 0]
    end
    @testset "qr" begin
        Random.seed!(1234)
        At = rand(Mat{3,3})
        Q, R, p = @inferred qr(At)
        As = SArray(At)
        Fs = qr(As)
        @test Q == Fs.Q
        @test R == Fs.R
        @test p == Fs.p
    end
    @testset "lu" begin
        Random.seed!(1234)
        At = rand(Mat{3,3})
        L, U, p = @inferred lu(At)
        As = SArray(At)
        Fs = lu(As)
        @test L == Fs.L
        @test U == Fs.U
        @test p == Fs.p
    end
    @testset "svd" begin
        Random.seed!(1234)
        At = rand(Mat{3,3})
        Ft = @inferred svd(At)
        U, S, V = Ft
        As = SArray(At)
        Fs = svd(As)
        @test U == Fs.U
        @test S == Fs.S
        @test V == Fs.V
        @test Ft.Vt == Fs.Vt
    end
end

@testset "UniformScaling" begin
    for T in (Float32, Float64)
        for SquareTensorType in (Tensor{Tuple{3, 3}, T}, Tensor{Tuple{@Symmetry{3, 3}}, T})
            x = rand(SquareTensorType)
            @test (@inferred x + I)::SquareTensorType == x + one(x)
            @test (@inferred x - I)::SquareTensorType == x - one(x)
            @test (@inferred I + x)::SquareTensorType == one(x) + x
            @test (@inferred I - x)::SquareTensorType == one(x) - x
            y = rand(Mat{3, 4, T})
            v = rand(Vec{3, T})
            @test (@inferred x ⋅ I)::SquareTensorType == x ⋅ one(x)
            @test (@inferred I ⋅ x)::SquareTensorType == one(x) ⋅ x
            @test (@inferred y ⋅ I)::Mat{3, 4, T} == y ⋅ one(Mat{4, 4})
            @test (@inferred I ⋅ y)::Mat{3, 4, T} == one(Mat{3, 3}) ⋅ y
            @test (@inferred v ⋅ I)::Vec{3, T} == v ⋅ one(x)
            @test (@inferred I ⋅ v)::Vec{3, T} == one(x) ⋅ v
            @test (@inferred I ⊡ x)::T == one(x) ⊡ x
            @test (@inferred x ⊡ I)::T == x ⊡ one(x)
            # wrong input
            @test_throws Exception x * I
            @test_throws Exception y * I
            @test_throws Exception v * I
            @test_throws Exception I * x
            @test_throws Exception I * y
            @test_throws Exception I * v
        end
    end
end


text:
include("types.jl")
include("util.jl")

max_stars_repo_name: RvSpectML/EchelleCCFs

max_issues_repo_name: RvSpectML/EchelleCCFs

max_forks_repo_name: RvSpectML/EchelleCCFs


text:
function backsub(A::AbstractArray{T,2}, b::AbstractVector{T}) where {T<:Number}
#
# assume A is an upper triangular matrix
# backsub performs backward substitution to solve Ax=b
#
    n = size(A,1)
    N = zero(T)
    s = maximum(abs, diag(A)) * eps(real(T))
    for k = 1:n
        if iszero(A[k,k])
            A[k,k] = s
        end
    end
    UpperTriangular(A) \ b[1:n]
end


text:
"""
COnstruit la liste reponses
Explore dans momo (typiquement BIGMOMO) les mots qui commencent par out
et dont la lettre suivante ne fait pas partie du ii ème mot de la liste AMOTS

"""
function explore_2(amots, reponses, out, momo, ii0, ii)
    for i in 1:length(amots)
        if i == ii
            continue
        end
    	istart = ii0 == 0 ? i : ii0
        for c in amots[i]
            nout, nm = explore(out, momo, c)
            if isnothing(nm)
                continue
            end
            if !isnothing(findc(nm, 0x00))
	        push!(reponses, (nout, istart, i))
            end
            explore_2(amots, reponses, nout, nm, istart, i)
        end
    end
end

explore_2(amots, reponses, ii0, i) = explore_2(amots, reponses, "", BIGMOMO, ii0, i)

function liste_mots(mots)
    amots = Array{Array{UInt8,1},1}()
    for m in split(mots, ' ')
        s = Set{UInt8}()
        for c in m
            push!(s, UInt8(c))
        end
        push!(amots, sort!(collect(s)))
    end
    amots
end

function sizeforword(lili)
    lw = 0
    for mot in lili
        lm = length(mot)
        if lm > lw
            lw = lm
        end
    end
    lw
end

function haikusaga(s)
    AMOTS = liste_mots(s)
    REPONS = Array{Tuple{String,Int8,Int8}, 1}()
    explore_2(AMOTS, REPONS, 0, 0)

    dicom = Dict{String, Array{Tuple{Int8,Int8},1}}()
    for (s,i1,i2) in REPONS
        if haskey(dicom, s)
            if !((i1,i2) in dicom[s])
                push!(dicom[s], (i1,i2))
	    end
        else
            dicom[s] = [(i1,i2)]
        end
    end

    lw = sizeforword(keys(dicom))

    for mot in sort(collect(keys(dicom)))
        print(rpad(mot, lw))
        first = true
        for v in sort(dicom[mot])
            print(' ',v[1],v[2])
        end
        println()
    end
end


text:
# What packages are we using?
using Logging

# Include my types -
include("Types.jl")
include("Checks.jl")


text:
@testset "linear expressions variables" begin
    vars = @linvars x y z

    @test vars == [x, y, z]
    @test x isa AffineExpression{Int}
    @test x.coeffs == [1, 0, 0, 0]
    @test y.coeffs == [0, 1, 0, 0]
    @test z.coeffs == [0, 0, 1, 0]

    vars2 = @linvars x[1:5]
    @test vars2 == [x1, x2, x3, x4, x5]

    @test x1 isa AffineExpression{Int}
    @test x1.coeffs == [1, 0, 0, 0, 0, 0]
    @test x5.coeffs == [0, 0, 0, 0, 1, 0]

    vars3 = @linvars x
    @test vars3 == [x]

    @test x isa AffineExpression{Int}
    @test x.coeffs == [1, 0]
end

@testset "linear expressions operations" begin
    @linvars x y z

    p1 = x - y + 3z
    @test IntervalLinearAlgebra._tostring(p1) == "x-y+3z"
    p2 = y + x - z - 2
    @test IntervalLinearAlgebra._tostring(p2) == "x+y-z-2"
    @test IntervalLinearAlgebra._tostring(p1 - p1) == "0"

    @test +p1 == p1
    @test -p1 == -x + y - 3z
    @test p2([1, 1, 1]) == -1

    psum = p1 + p2
    pdiff = p1 - p2
    psumnumleft = 1 + p1
    psumnumright = p1 + 1
    pdiffnumright = p1 - 1
    pdiffnumleft = 1 - p1
    pprodleft = 2 * p1
    pprodright = p1 * 2
    pdiv = p1 / 2

    @test psum.coeffs == [2, 0, 2, -2]
    @test pdiff.coeffs == [0, -2, 4, 2]
    @test psumnumleft.coeffs == [1, -1, 3, 1]
    @test psumnumright.coeffs == [1, -1, 3, 1]
    @test pdiffnumright.coeffs ==  [1, -1, 3, -1]
    @test pdiffnumleft.coeffs == [-1, 1, -3, 1]
    @test pprodleft.coeffs == [2, -2, 6, 0]
    @test pprodright.coeffs == [2, -2, 6, 0]
    @test pdiv.coeffs == [0.5, -0.5, 1.5, 0]

    @test p2 + 0.5 == x + y - z - 1.5

    A = [1 2;3 4]
    @test x * A == [x 2x;3x 4x]
    @test A * x == [x 2x;3x 4x]

    @test zero(p1) == AffineExpression(0)
    @test one(p1) == AffineExpression(1)
    @test zero(AffineExpression{Int}) == AffineExpression(0)
    @test one(AffineExpression{Int}) == AffineExpression(1)
end

@testset "linear expressions conversions" begin
    @test promote_type(AffineExpression{Int}, Float64) == AffineExpression{Float64}
    @test promote_type(AffineExpression{Int}, AffineExpression{Float64}) == AffineExpression{Float64}

    @linvars x y

    p1 = x + y + 1
    a, b = promote(p1, 1.5)

    @test a isa AffineExpression{Float64}
    @test b isa AffineExpression{Float64}

    @test a == x + y + 1
    @test b == 1.5

    @test convert(AffineExpression, 1.2) isa AffineExpression{Float64}
    @test convert(AffineExpression, 1.2) == 1.2
end

max_stars_repo_name: lucaferranti/IntervalLinearAlgebra

max_issues_repo_name: lucaferranti/IntervalLinearAlgebra

max_forks_repo_name: lucaferranti/IntervalLinearAlgebra


text:
#################################
# Tropical API                  #
#################################
# Get current position, past positions, and forecasts for tropical cyclones worldwide.

# Contains a centralized function to make calls to the API.
include("request.jl")

function get_storms_active_by_governmentid(apikey::String, basinID::String, governmentID::String)
    # Returns basic information about tropical cyclones that are currently active in the specified basin.

    url = "http://dataservice.accuweather.com/tropical/v1/gov/storms/active/"

    # Add required parameters to the URL
    url = url * basinID * "/"
    url = url * governmentID
    url = url * "?apikey=" * apikey

    return make_API_call(url)
end

function get_storms_active_all(apikey::String)
    # Returns basic information about tropical cyclones that are currently active in the specified basin.

    url = "http://dataservice.accuweather.com/tropical/v1/gov/storms/active"

    # Add required parameters to the URL
    url = url * "?apikey=" * apikey

    return make_API_call(url)
end

function get_storms_by_basinid_and_year(apikey::String, year::Int64, basinID::String)
    # Returns basic information about tropical cyclones for a specific year and basin.
    # Year: 4-digit year. Example: '2017'

    url = "http://dataservice.accuweather.com/tropical/v1/gov/storms/"

    # Add required parameters to the URL
    url = url * year * "/"
    url = url * basinID
    url = url * "?apikey=" * apikey

    return make_API_call(url)
end

function get_storms_active_by_basinid(apikey::String, basinID::String)
    # Returns basic information about tropical cyclones that are currently active in the specified basin.

    url = "http://dataservice.accuweather.com/tropical/v1/gov/storms/active/"

    # Add required parameters to the URL
    url = url * basinID
    url = url * "?apikey=" * apikey

    return make_API_call(url)
end

function get_storms_by_basinid_govenmentid_and_year(apikey::String, year::Int64, basinID::String, governmentID::String)
    # Returns basic information about tropical cyclones for a specific year and basin.
    # Year: 4-digit year. Example: '2017'

    url = "http://dataservice.accuweather.com/tropical/v1/gov/storms/"

    # Add required parameters to the URL
    url = url * year * "/"
    url = url * basinID * "/"
    url = url * governmentID
    url = url * "?apikey=" * apikey

    return make_API_call(url)
end

function get_storms_active_by_basinid(apikey::String, basinID::String)
    # Returns basic information about tropical cyclones for a specific basin.
    # Year: 4-digit year. Example: '2017'

    url = "http://dataservice.accuweather.com/tropical/v1/gov/storms/active/"

    # Add required parameters to the URL
    url = url * basinID
    url = url * "?apikey=" * apikey

    return make_API_call(url)
end

# Category: Position
function get_storm_location(apikey::String, year::Int64, basinID::String, governmentID::String, details::Bool, radiigeometry::Bool, includeLandmarks::Bool)
    # Returns all position information for a specific tropical cyclone or list of tropical cyclones.
    # Year: 4-digit year. Example: '2017'

    url = "http://dataservice.accuweather.com/tropical/v1/gov/storms/"

    # Add required parameters to the URL
    url = url * year * "/"
    url = url * basinID * "/"
    url = url * governmentID * "/positions"
    url = url * "?apikey=" * apikey

    # Add optional parameters to the URL
    if details == true url = url * "&details=true" end
    if radiigeometry == true url = url * "&radiigeometry=true" end
    if includeLandmarks == true url = url * "&includeLandmarks=true" end

    return make_API_call(url)
end

function get_storm_location_currently(apikey::String, year::Int64, basinID::String, governmentID::String, details::Bool, radiigeometry::Bool, includeLandmarks::Bool)
    # Returns all position information for a specific tropical cyclone or list of tropical cyclones.
    # Year: 4-digit year. Example: '2017'

    url = "http://dataservice.accuweather.com/tropical/v1/gov/storms/"

    # Add required parameters to the URL
    url = url * year * "/"
    url = url * basinID * "/"
    url = url * governmentID * "/positions/current"
    url = url * "?apikey=" * apikey

    # Add optional parameters to the URL
    if details == true url = url * "&details=true" end
    if radiigeometry == true url = url * "&radiigeometry=true" end
    if includeLandmarks == true url = url * "&includeLandmarks=true" end

    return make_API_call(url)
end

# Category: Forecast
function get_storm_forecast(apikey::String, year::Int64, basinID::String, details::Bool, radiigeometry::Bool, windowgeometry::Bool)
    # Returns all recorded forecast information for a specific government-issued tropical cyclone.
    # Year: 4-digit year. Example: '2017'

    url = "http://dataservice.accuweather.com/tropical/v1/gov/storms/"

    # Add required parameters to the URL
    url = url * year * "/"
    url = url * basinID * "/"
    url = url * governmentID * "/forecasts"
    url = url * "?apikey=" * apikey

    # Add optional parameters to the URL
    if details == true url = url * "&details=true" end
    if radiigeometry == true url = url * "&radiigeometry=true" end
    if windowgeometry == true url = url * "&includeLandmarks=true" end

    return make_API_call(url)
end