function parseinput(lines)
    sep1, sep2 = findall(==(""), lines)
    rules = Dict{String,Vector{UnitRange{Int}}}()
    for i in 1:sep1 - 1
        key, values = split(lines[i], ": ")
        regex = r"(\d+)-(\d+)"
        rule = [parse(Int, m.captures[1]):parse(Int, m.captures[2]) for m in eachmatch(regex, values)]
        rules[key] = rule
    end
    parseticket = x -> parse.(Int, [m.match for m in eachmatch(r"\d+", x)])
    ticket = parseticket(lines[sep1 + 2])
    tickets = Vector{Int}[]
    for i in sep2 + 2:length(lines)
        push!(tickets, parseticket(lines[i]))
    end
    return rules, ticket, tickets
end

function invalid(ticket::Vector{Int}, rules_values)
    mask = [sum(sum(t .∈ r) for r in rules_values) == 0 for t in ticket]
    return  sum(ticket[mask])
end

const rules, ticket, tickets = parseinput(readlines("day16.txt"))

println("Part 1: $(sum(invalid(t, values(rules)) for t in tickets))")

function isvalidticket(ticket::Vector{Int}, rules_values)
    return all(sum(sum(t .∈ r) for r in rules_values) >= 1 for t in ticket)
end

function part2(tickets::Vector{Vector{Int}}, rules::Dict{String,Vector{UnitRange{Int}}})
    valid_tickets = filter(x -> isvalidticket(x, values(rules)), tickets)
    # create a 2D array where each row is a ticket and each colum a field
    T = [t[i] for t in valid_tickets, i = 1:length(valid_tickets[1])]
    # We want to check each column of the array, to see how many rules can apply. We
    # will find one rule that has only one possibility, we will remove it from the
    # others possible values and so on, until we know which field corresponds to which
    # rule
    possibilities = Dict{String,Vector{Int}}()
    num_tickets = length(valid_tickets)
    for (name, rule) in rules
        # this is ugly because it collects everything, but I had trouble with
        # broadcasting when I kept the 2 unit ranges.
        ranges = union(rule...)
        # Ref is necessary to avoid the broadcasting, we just want to check is each
        # element of the column (i.e. each field) is possible with this rule
        # We sum to know if the rule is valid for all tickets and findall to know which
        # columns are applicable for this rule
        possibles = findall([sum(col .∈ Ref(ranges)) == num_tickets for col in eachcol(T)])
        possibilities[name] = possibles
    end
    seen = Set{Int}()
    fields = Dict{String,Int}()
    sorted = sort(collect(possibilities), by=x -> length(x[2]))
    for (name, values) in sorted
        field = setdiff(values, seen)[1]
        seen = seen ∪ values
        fields[name] = field
    end
    return prod(ticket[fields[i]] for i in keys(fields) if startswith(i, "departure"))
end

println("Part 2: $(part2(tickets, rules))")


export create_grid

"""
    create_grid(bounds[, steps])

Create a Cartesian grid by discretizing the line segment, rectangle, or box
defined by `bounds` in increments of `steps`.  If `steps` is not defined, a
default step size of 1.0 will be used in all directions.

# Arguments
- `bounds::Array{<:Number}`: Array that defines the min/max values of a line
  segment (1D), rectangle (2D), or box (3D) that the grid will be placed in.
  The first row of the array defines the minimum values, the second row defines
  the maximum values.
- `steps::Array{Union{AbstractFloat, Integer}}`: Array that defines how many
  steps in each direction.  If the array values in `steps` are of type
  `<:Integer` integers then those values define how many points are used in
  each direction.  If the array values in `steps` are of type `<:AbstractFloat`
  numbers then those values define the step size in each direction.

# Examples
```jldoctest
julia> create_grid([0; 2], [2])
2-element Array{Float64,1}:
 0.0
 2.0
```

```jldoctest
julia> create_grid([0 0; 2 2], [2.0 1.0])
6×2 Array{Float64,2}:
 0.0  0.0
 0.0  1.0
 0.0  2.0
 2.0  0.0
 2.0  1.0
 2.0  2.0
```

```jldoctest
julia> create_grid([0 0 0; 2 2 2], [2 2 2])
8×3 Array{Float64,2}:
 0.0  0.0  0.0
 0.0  0.0  2.0
 0.0  2.0  0.0
 0.0  2.0  2.0
 2.0  0.0  0.0
 2.0  0.0  2.0
 2.0  2.0  0.0
 2.0  2.0  2.0
```
"""
function create_grid(bounds::Array{<:Number}, steps::Array{T}) where {T<:Union{AbstractFloat, Integer}}

    if length(size(bounds)) == 1
        dimension = 1
    else
        dimension = size(bounds)[2]
    end

    if dimension ≠ length(steps)
        throw(ArgumentError("""Dimension mismatch in arguments.  bounds indicates
                dimension = $dimension. steps indicates dimension = $(length(steps))"""))
    end

    if T <: AbstractFloat
        my_range = (start, step, stop) -> start:step:stop
    elseif T <: Integer
        my_range = (start, step, stop) -> LinRange(start, stop, step)
    end

    if dimension == 1
        xrange = my_range(bounds[1], steps[1], bounds[2])
        number_of_points = length(xrange)
        x = [ i for i in xrange ]
    elseif dimension == 2
        xrange = my_range(bounds[1,1], steps[1], bounds[2, 1])
        yrange = my_range(bounds[1,2], steps[2], bounds[2, 2])
        x = [ x for x in xrange for j in 1:length(yrange) ]
        y = [ y for i in 1:length(xrange) for y in yrange ]
        [x y]
    elseif dimension == 3
        xrange = my_range(bounds[1,1], steps[1], bounds[2, 1])
        yrange = my_range(bounds[1,2], steps[2], bounds[2, 2])
        zrange = my_range(bounds[1,2], steps[3], bounds[2, 3])
        x = [ x for x in xrange for j in 1:length(yrange) for k in 1:length(zrange) ]
        y = [ y for i in 1:length(xrange) for y in yrange for k in 1:length(zrange) ]
        z = [ z for i in 1:length(xrange) for j in 1:length(yrange) for z in zrange ]
        [x y z]
    else
        throw(ArgumentError("Can't have more than 3 spatial dimensions for grid."))
    end

end

function create_grid(bounds::Array{<:Number})

    if length(size(bounds)) == 1
        dimension = 1
    else
        dimension = size(bounds)[2]
    end

    if dimension == 1
        steps = [1.0]
    elseif dimension == 2
        steps = [1.0 1.0]
    elseif dimension == 3
        steps = [1.0 1.0 1.0]
    else
        throw(ArgumentError("Can't have more than 3 spatial dimensions for grid."))
    end

    create_grid(bounds, steps)

end


### A Pluto.jl notebook ###
# v0.18.2

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    quote
        local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
        el
    end
end

# ╔═╡ 7291ecff-dca9-4cf1-a2b4-97e97d41c98f
using CommonMark

# ╔═╡ 57b9638f-cd2e-4687-a85d-f7fb32dea1d0
using  Unitful, UnitfulRecipes, Plots, PlotlyJS, ColorSchemes

# ╔═╡ e748ed86-7bbc-4d30-b6de-283b680f60bb
begin

	using LaTeXStrings,
		PlutoUI,
		HypertextLiteral,
		Lazy,
		MarkdownLiteral,
		Hyperscript,
		Random

	import MarkdownLiteral: @mdx

	"https://gitlab.com/Good-Trouble/youCAN/doThermodynamics/-/raw/main/src/infrastructure.jl" |> download |> include

	HTML("""

		infrastructure

	  packages

	""")

end

# ╔═╡ 9da8b652-11d5-4239-abb2-b165f89c7a51
title"Problem 03.025"ms9

# ╔═╡ d94ce667-2f71-4bcc-ad32-e7b03beaec6a
cm"""
## Given

As shown in **Fig. P3.25**{.addblue}, Refrigerant 134a is contained in a piston–cylinder assembly, initially as saturated vapor. The refrigerant is slowly heated until its temperature is 160 °C. During the process, the piston moves smoothly in the cylinder.

{ .center .w-50 title="Textbook Figure P3.25" }
![Figure P3.25](https://imgur.com/11oMMd1.png)

{ .fig_caption }
Figure P3.25 from the textbook.

"""

# ╔═╡ 420ac294-a186-4277-bd56-9c6334c8b9f8
cm"""

## Find

For the refrigerant, evaluate the work, in kJ/kg.

"""

# ╔═╡ acc997cf-8244-4001-9caa-37f33ce947c3
cm"""

## Get Organized

_A little bit of thought_{.newthought} early on keeps us from running around aimlessly with our hair on fire.  Notice these things right away:

1. We're asked to find work. It's best to separate our forms of work into

   ```math
   W = W_\text{boundary} + W_\text{every other kind of work}
   ```

   {.greek}
   1. The moving piston suggests a volume change, so we definitely expect
      moving boundary work. Have no worries about being wrong; if it turns out
      we have no volume change, the boundary work simply calculates to zero.
      For now, we just note our expression for boundary work and move on.

      ```math
      W_{b,out} = \int P\, {\rm d}V
      ```

   1. We have no signs of shaft work, electricity, or any other forms of work,
      so all of our work will be boundary work.

      ```math
      W = W_{b,out}
      ```

1. **The units requested are kJ/kg, so we need to find _mass specific_{.killerorange} work,
   ``W/m``.**

1. Let _...the piston moves smoothly in the cylinder_ scream to you:
   This is an **isobaric process**{.killerorange}!!

1. We are given the piston's weight and area. Those are the ingredients
   of pressure. _We may not need it,_ but we have it. Stick it in your pocket.

{style="padding-block-start: 1em;"}
**SO WHAT DO WE NOW KNOW?**{.addblue}

We are calculating specific isobaric boundary work,

```math
w = \int P\, {\rm d}v = P(v_2 - v_1),
```

so we need to find ``P, v_2,`` and ``v_1``, perform the calculation, and we're done.
"""

# ╔═╡ cb438563-e0b4-480d-ab58-c8162717a886
cm"""

## Attack

Let's go find our three fugitive properties. The questions for you are the same every single time. _Was it given? Have I already calculated it? Do I have two independent properties so I can get it from the tables?_{.killerorange}

``\bf P``: **Calculate it.**

   Remember that piston weight and area? Don't forget the
   contribution from the atmosphere... we work in absolute pressure
   (except in very limited situations).

   ```math
   P_{sys} = P_{atm} + \frac{F_{piston}}{A_\textit{cross, piston}}
   ```

``\bf v_1``: **Thanks to ``P``, we have two independent properties.**

   ```math
    v_1 = v(P, x_1)
   ```

   {style="text-align:center; padding-block-end:2em;"}
   ``P`` is calculated. ``x_1`` is given (saturated vapor).

``\bf v_2``: **Two independent properties.**

   ```math
	\begin{equation}
    v_2 = v(P, T_2)
	\end{equation}
   ```

   {style="text-align:center;"}
   ``P`` is calculated. ``T_2 = 160\, \rm°C`` is given.

"""

# ╔═╡ 26ba1d81-a7a5-46e1-bbab-892a659eb18d
begin
	W_piston = 471.1u"N"
	D_piston = 0.02u"m"
	P_atm = 1u"bar"

	A_piston = π/4 * D_piston^2

end;

# ╔═╡ 76529ec7-c678-4569-b121-8391b22b43a1

# ╔═╡ 491f71f3-1dc9-48d6-852b-a09b1663e658
P = P_atm + W_piston/A_piston |> u"bar"

# ╔═╡ 65dded8b-1197-432e-93ea-d02f9d6c775a
begin

	v1 = 0.0121u"m^3/kg"         # Table A-11
	v2 = 0.02017u"m^3/kg"        # Table A-12

end;

# ╔═╡ fc33d878-71a7-443f-9157-f905ccded4c7
cm"""

I'm pretty sure P = $(P) can be safely rounded to 16 bar for our dives into the tables:

{.message .danger}
> actually, **do not round** if your property pair is ``P, T`` and you're testing for saturation conditions. A ``(T_{sat},P_{sat})`` combination must be exact.

 - From `Table A-11`{.mcs .highlight .property-table},
   ``v_1 = v_{\rm g@16bar} = `` $(v1 |> u"m^3/kg" |> ustrip) m³/kg

 - From `Table A-12`{.mcs .highlight .property-table},
   ``v_2 = v_{\rm 16bar,160°C} = `` $(v2 |> u"m^3/kg" |> ustrip) m³/kg

"""

# ╔═╡ 74975d87-9999-4ef9-bf62-a0294d60c511
w = P * (v2 - v1) |> u"kJ/kg"

# ╔═╡ 58bb2681-9699-477a-8fb2-fdf4208d48f7
w_rounded = round(typeof(w), w, digits=4)

# ╔═╡ 5bffc527-b8f7-4fbf-bbff-b5ae8a5a4178

# ╔═╡ 5104846f-0dc1-4711-b948-77c69a9db2df
cm"""

_Get in the habit of plotting your processes_{.newthought}, even if it's only a sketch. You gain a deeper understanding of the processes involved, and plots give insights that lead to faster, more robust solutions... **especially**{.killerorange} when you sketch your plots while you're getting organized.

For example, in the current scenario, we knew from the problem statement that our process began on the saturated vapor line, and we knew we had an isobaric process.

Mouse over the plot to find and play with its features.
"""

# ╔═╡ f9a5c3f0-5e05-45da-acfc-e03e81a7b36d
cm"""

{.finis}
### _finis_

{.message .success}
> w = $(w_rounded |> ustrip) kJ/kg
> {.addblue}
> ``\quad`` _Go read [**Find**](#find){.mcs .faux-heading .font-style-normal} again. Ensure you're reporting what was actually requested._
"""

# ╔═╡ a225f838-bd6e-425d-b531-d7adf7f3768d
cm"""

{.count-appendix .silly-heading-border}
## Appendix

One of the major benefits of reactive notebooks like Pluto is that allow large, unwieldy chunks of code to be placed outside the reading flow without removing them from their proper place in the computation flow. Their results can be used in calculations or spliced into the narrative (eg, the _P-v_ plot).

{.center .appendix}
_Those code chunks live here._

"""

# ╔═╡ 52866331-2bdb-4e0d-b8f6-5cfcdff56057
# saturation dome

begin

	Psat_r134a = [0.5164,0.6332,0.7704,0.9305,1.0199,1.1160,1.2192,1.3299,1.4483,1.5748,1.8540,2.1704,2.5274,2.9282,3.3765,3.8756,4.4294,5.0416,5.7160,6.4566,6.8530,7.2675,7.7006,8.1528,8.6247,9.1168,9.6298,10.164,10.720,11.299,12.526,13.851,15.278,16.813,21.162,26.324,32.435,39.742]u"bar"

	vf_r134a = [0.7055e-03,0.7113e-03,0.7172e-03,0.7233e-03,0.7265e-03,0.7296e-03,0.7328e-03,0.7361e-03,0.7395e-03,0.7428e-03,0.7498e-03,0.7569e-03,0.7644e-03,0.7721e-03,0.7801e-03,0.7884e-03,0.7971e-03,0.8062e-03,0.8157e-03,0.8257e-03,0.8309e-03,0.8362e-03,0.8417e-03,0.8473e-03,0.8530e-03,0.8590e-03,0.8651e-03,0.8714e-03,0.8780e-03,0.8847e-03,0.8989e-03,0.9142e-03,0.9308e-03,0.9488e-03,1.0027e-03,1.0766e-03,1.1949e-03,1.5443e-03]u"m^3/kg"

	vg_r134a = [0.3569,0.2947,0.2451,0.2052,0.1882,0.1728,0.1590,0.1464,0.1350,0.1247,0.1068,0.0919,0.0794,0.0689,0.0600,0.0525,0.0460,0.0405,0.0358,0.0317,0.0298,0.0281,0.0265,0.0250,0.0236,0.0223,0.0210,0.0199,0.0188,0.0177,0.0159,0.0142,0.0127,0.0114,0.0086,0.0064,0.0046,0.0027]u"m^3/kg"

	@mdx("""
	{.appendix-item}
	_data_{.newthought .appendix}   R-134a saturation dome
	""")

end

# ╔═╡ b1449db0-c818-4fb5-9d72-78936db99cbe
begin
	# ═══ load css ════════════════════════════════════════════*═

	const gentleblue            = colorant"#5e81ac"
	const troublered            = colorant"#ff2600"
	const killerorange          = colorant"#db5728"
	const wellhellothereorange  = colorant"#f7800f"
	const addblue               = colorant"#037db6"
	const ayustringgreen        = colorant"#86b300"
	const onsomeothergreen      = colorant"#439d00"
	const linkgreen             = colorant"#008800"
	const audiblegreen          = colorant"#00f900"
	const tiger 				= colorant"#411ff5"
	const chartreuse 			= colorant"#c1f80a"
	const cyan 			        = colorant"#00ffff"
	const hyabusabright 		= colorant"#c3eaff"

	@mdx("""

	{.appendix-item .dull}
	_infrastructure_{.newthought}   styles

	""")
end

# ╔═╡ 6c9eaa0e-d1b5-4442-993e-d1b6ae15a27d
# begin

# 	macro css_str(stylesheet_url)
# 		the_css = open(download(stylesheet_url)) do io
# 			read(io, String)
# 		end
# 		return the_css
# 	end

#   # ══ title-bloc ═══════════════════════════════════════════════════*═

# 	macro title_str(title::String, bookID::String="")
# 		cm_parser = CommonMark.Parser()
# 		enable!(cm_parser, AttributeRule)

# 		bookID == "" && return title |> cm_parser

# 		bib = Dict(
# 			"ms6" 	=> 	"""
# 						Moran, MJ & HN Shapiro (2008)
# 						Fundamentals of engineering thermodynamics 6e,
# 						978-0471787358
# 						https://gitlab.com/Good-Trouble/youCAN/doThermodynamics/-/raw/main/images/ms6cover.jpg
# 						""",
# 			"ms8" 	=> 	"""
# 						Moran, MJ Ed (2014)
# 						Fundamentals of engineering thermodynamics 8e,
# 						978-1118412930
# 						https://gitlab.com/Good-Trouble/youCAN/doThermodynamics/-/raw/main/images/ms8cover.jpg
# 						""",
# 			"ms9" 	=> 	"""
# 						Moran, MJ, _et al_ (2018)
# 						Fundamentals of engineering thermodynamics 9e,
# 						978-1119391388
# 						https://gitlab.com/Good-Trouble/youCAN/doThermodynamics/-/raw/main/images/ms9cover47x60.png
# 						""",
# 			"cb7" 	=> 	"""
# 						Çengel, YA & MA Boles (2011)
# 						Thermodynamics: An engineering approach 7e,
# 						978-0073529325
# 						https://gitlab.com/Good-Trouble/youCAN/doThermodynamics/-/raw/main/images/cb7cover.jpg
# 						""",
# 			"cb8" 	=> 	"""
# 						Çengel, YA & MA Boles (2015)
# 						Thermodynamics: An engineering approach 8e,
# 						978-0073398174
# 						https://gitlab.com/Good-Trouble/youCAN/doThermodynamics/-/raw/main/images/cb8cover.jpg
# 						""",
# 			"cb9" 	=> 	"""
# 						Çengel, YA, Boles, MA, & M Kanoglu (2019)
# 						Thermodynamics: An engineering approach 9e,
# 						978-1259822674
# 						https://gitlab.com/Good-Trouble/youCAN/doThermodynamics/-/raw/main/images/cb9cover48x60.jpg
# 						""",
# 		)

# 		haskey(bib, bookID) || return KeyError(bookID)

# 		the_bibliography, the_thumb =
# 			@as bb bib[bookID] begin
# 				split(bb, '\n', keepempty=false)
# 				strip.(bb)
# 				(
# 					join(bb[1:3], " _", "_ "),
# 					m("img", class="no-dark-invert", src=bb[4], title=join(bb[2:3]," "))

# 				)
# 			end

# 		out = @mdx("""
#

#
\n\n
# 			\n\n# $title\n\n{.source}\n$the_bibliography\n
#

# 			$the_thumb
#

# 			""")

# 		return out
# 	end

#   # ═════════════════════════════════════════════════════════════════*═

	@mdx("""
	{.appendix-item .dull}
	_infrastructure_{.newthought}   macros
	""")

# end

# ╔═╡ 6b26235d-d148-4dd5-a1ad-13acea9a878a
#=

Monitors system darkmode status

// we dispatch the input event on the span, not the button, because
// Pluto's `@bind` mechanism listens for events on the **first element** in the
// HTML output. In our case, that's the span.

=#

begin
	isdarkmode() = @htl("""

		infrastructure
		  realtime system darkmode monitor

	""")

	@bind darkmode isdarkmode()

end

# ╔═╡ 12524387-5a27-499b-9933-8c4f0522b425
begin

  # substitue dark mode color(s)
	colered = nthColor(darkmode, ColorSchemes.julialegacy, 3, audiblegreen)

	# theme(:default)
	process_color = colered[3]

  # choose Plotly.js as the plotting engine
	plotlyjs()

  # the annotations routines don't do Unitful quantities,
  # so we strip off the units now to keep our code cleaner later
    (_v1, _v2, _P) = (v1, v2, P) .|> ustrip

  # saturation dome
    Plots.plot([vf_r134a, vg_r134a], Psat_r134a,
		palette = palette(colered),
		lab = ["sat.liquid" "sat.vapor"],
		linewidth = 1,
	)

  # the process
	Plots.plot!([v1, v2], [P, P],
		linewidth = 2,
		label  = "process",

		marker = :dot,
		markersize = 3,
		markerstrokecolor = process_color,

		annotations = [
			(_v1, _P, Plots.text("1", :right, :bottom, process_color, 12)),
			(_v2, _P, Plots.text("2", :left , :bottom, process_color, 12)),
			((_v1+_v2)/2, _P/2, Plots.text("work", :center, process_color, 12)),
		],

		fill = (0, ),
		fillalpha = 0.15,

		xlabel = "specific volume",
		ylabel = "pressure",
		xlims  = (0, 0.025),
		# xscale  = :log,

		# yaxis = (bottommargin = 6),

		size = (675, 400),
	)

	p = Plots.plot!(
		legend = :none,
		ticks  = :native,
		widen  = true,
	)

	@mdx("""
	{.appendix-item}
	_plot_{.newthought .appendix}   The process and its associated work
	""")
end

# ╔═╡ ba11c481-bd6c-449b-aaf3-b0609582e371
cm"""

{.center title="Plot of the process and associated work"}
$(p)

{ .fig_caption }
The process and its associated work.

"""

# ╔═╡ 8e4c40f3-26f0-4fb4-b7ae-5c47e7de1cd3
# TableOfContents()		# uncomment to show table of comments

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
CommonMark = "a80b9123-70ca-4bc0-993e-6e3bcb318db6"
Hyperscript = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
Lazy = "50d2b5c4-7a5e-59d5-8109-a42b560f39c0"
MarkdownLiteral = "736d6165-7244-6769-4267-6b50796e6954"
PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
UnitfulRecipes = "42071c24-d89e-48dd-8a24-8a12d9b8861f"

[compat]
ColorSchemes = "~3.17.1"
CommonMark = "~0.8.6"
Hyperscript = "~0.0.4"
HypertextLiteral = "~0.9.3"
LaTeXStrings = "~1.3.0"
Lazy = "~0.15.1"
MarkdownLiteral = "~0.1.1"
PlotlyJS = "~0.18.8"
Plots = "~1.27.0"
PlutoUI = "~0.7.23"
Unitful = "~1.11.0"
UnitfulRecipes = "~1.5.3"
"""

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

[[AbstractPlutoDingetjes]]
deps = ["Pkg"]
git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481"
uuid = "6e696c72-6542-2067-7265-42206c756150"
version = "1.1.4"

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

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

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

[[AssetRegistry]]
deps = ["Distributed", "JSON", "Pidfile", "SHA", "Test"]
git-tree-sha1 = "b25e88db7944f98789130d7b503276bc34bc098e"
uuid = "bf4720bc-e11a-5d0c-854e-bdca1663c893"
version = "0.1.0"

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

[[BinDeps]]
deps = ["Libdl", "Pkg", "SHA", "URIParser", "Unicode"]
git-tree-sha1 = "1289b57e8cf019aede076edab0587eb9644175bd"
uuid = "9e28174c-4ba2-5203-b857-d8d62c4213ee"
version = "1.0.2"

[[Blink]]
deps = ["Base64", "BinDeps", "Distributed", "JSExpr", "JSON", "Lazy", "Logging", "MacroTools", "Mustache", "Mux", "Reexport", "Sockets", "WebIO", "WebSockets"]
git-tree-sha1 = "08d0b679fd7caa49e2bca9214b131289e19808c0"
uuid = "ad839575-38b3-5650-b840-f874b8c74a25"
version = "0.12.5"

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

[[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 = "4b859a208b2397a7a623a03449e4636bdb17bcf2"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+1"

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

[[ChangesOfVariables]]
deps = ["ChainRulesCore", "LinearAlgebra", "Test"]
git-tree-sha1 = "bf98fa45a0a4cee295de98d4c1462be26345b9a1"
uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0"
version = "0.1.2"

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

[[ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "32a2b8af383f11cbb65803883837a149d10dfe8a"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.10.12"

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

[[CommonMark]]
deps = ["Crayons", "JSON", "URIs"]
git-tree-sha1 = "4cd7063c9bdebdbd55ede1af70f3c2f48fab4215"
uuid = "a80b9123-70ca-4bc0-993e-6e3bcb318db6"
version = "0.8.6"

[[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 = "96b0bc6c52df76506efc8a441c6cf1adcb1babc4"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.42.0"

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

[[ConstructionBase]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "f74e9d5388b8620b4cee35d4c5a618dd4dc547f4"
uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
version = "1.3.0"

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

[[Crayons]]
git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.1.1"

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

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

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

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

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

[[Expat_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "ae13fcbc7ab8f16b0856729b050ef0c446aa3492"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.4.4+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"

[[FileWatching]]
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"

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

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

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

[[FunctionalCollections]]
deps = ["Test"]
git-tree-sha1 = "04cb9cfaa6ba5311973994fe3496ddec19b6292a"
uuid = "de31a74c-ac4f-5751-b3fd-e18cd04993ca"
version = "0.5.0"

[[GLFW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"]
git-tree-sha1 = "51d2dfe8e590fbd74e7a842cf6d13d8a2f45dc01"
uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89"
version = "3.3.6+0"

[[GR]]
deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "RelocatableFolders", "Serialization", "Sockets", "Test", "UUIDs"]
git-tree-sha1 = "9f836fb62492f4b0f0d3b06f55983f2704ed0883"
uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
version = "0.64.0"

[[GR_jll]]
deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "a6c850d77ad5118ad3be4bd188919ce97fffac47"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.64.0+0"

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

[[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 = "a32d672ac2c967f3deb8a81d828afc739c838a06"
uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
version = "2.68.3+2"

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

[[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 = "0fa77022fe4b511826b39c894c90daf5fce3334a"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.17"

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

[[Hiccup]]
deps = ["MacroTools", "Test"]
git-tree-sha1 = "6187bb2d5fcbb2007c39e7ac53308b0d371124bd"
uuid = "9fb69e20-1954-56bb-a84f-559cc56a8ff7"
version = "0.2.2"

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

[[HypertextLiteral]]
git-tree-sha1 = "2b078b5a615c6c0396c77810d92ee8c6f470d238"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.3"

[[IOCapture]]
deps = ["Logging", "Random"]
git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a"
uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
version = "0.2.2"

[[IniFile]]
git-tree-sha1 = "f550e6e32074c939295eb5ea6de31849ac2c9625"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.1"

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

[[InverseFunctions]]
deps = ["Test"]
git-tree-sha1 = "91b5dcf362c5add98049e6c29ee756910b03051d"
uuid = "3587e190-3f89-42d0-90ee-14403ec27112"
version = "0.1.3"

[[IrrationalConstants]]
git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.1.1"

[[IterTools]]
git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.4.0"

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

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

[[JSExpr]]
deps = ["JSON", "MacroTools", "Observables", "WebIO"]
git-tree-sha1 = "bd6c034156b1e7295450a219c4340e32e50b08b1"
uuid = "97c1335a-c9c5-57fe-bc5d-ec35cebe8660"
version = "0.5.3"

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

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

[[Kaleido_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "2ef87eeaa28713cb010f9fb0be288b6c1a4ecd53"
uuid = "f7e6163d-2fa5-5f23-b69c-1db539e41963"
version = "0.1.0+0"

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

[[LERC_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434"
uuid = "88015f11-f218-50d7-93a8-a6af411a945d"
version = "3.0.0+1"

[[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 = "f2355693d6778a178ade15952b7ac47a4ff97996"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.3.0"

[[Latexify]]
deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"]
git-tree-sha1 = "4f00cc36fede3c04b8acf9b2e2763decfdcecfa6"
uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
version = "0.15.13"

[[Lazy]]
deps = ["MacroTools"]
git-tree-sha1 = "1370f8202dac30758f3c345f9909b97f53d87d3f"
uuid = "50d2b5c4-7a5e-59d5-8109-a42b560f39c0"
version = "0.15.1"

[[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 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290"
uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
version = "3.2.2+1"

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

[[Libglvnd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"]
git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf"
uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29"
version = "1.3.0+3"

[[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", "LERC_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "c9551dd26e31ab17b86cbd00c2ede019c08758eb"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.3.0+1"

[[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", "libblastrampoline_jll"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[LogExpFunctions]]
deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "56ad13e26b7093472eba53b418eba15ad830d6b5"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.9"

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

[[MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.9"

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

[[MarkdownLiteral]]
deps = ["CommonMark", "HypertextLiteral"]
git-tree-sha1 = "0d3fa2dd374934b62ee16a4721fe68c418b92899"
uuid = "736d6165-7244-6769-4267-6b50796e6954"
version = "0.1.1"

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

[[Measures]]
git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f"
uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
version = "0.3.1"

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

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

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

[[Mustache]]
deps = ["Printf", "Tables"]
git-tree-sha1 = "bfbd6fb946d967794498790aa7a0e6cdf1120f41"
uuid = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70"
version = "1.0.13"

[[Mux]]
deps = ["AssetRegistry", "Base64", "HTTP", "Hiccup", "Pkg", "Sockets", "WebSockets"]
git-tree-sha1 = "82dfb2cead9895e10ee1b0ca37a01088456c4364"
uuid = "a975b10e-0019-58db-a62f-e48ff68538c9"
version = "0.7.6"

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

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

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

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

[[OpenBLAS_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"

[[OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "648107615c15d4e09f7eca16307bc821c1f718d8"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "1.1.13+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"

[[Parameters]]
deps = ["OrderedCollections", "UnPack"]
git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe"
uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
version = "0.12.3"

[[Parsers]]
deps = ["Dates"]
git-tree-sha1 = "85b5da0fa43588c75bb1ff986493443f821c70b7"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.2.3"

[[Pidfile]]
deps = ["FileWatching", "Test"]
git-tree-sha1 = "2d8aaf8ee10df53d0dfb9b8ee44ae7c04ced2b03"
uuid = "fa939f87-e72e-5be4-a000-7fc836dbe307"
version = "1.3.0"

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

[[PlotThemes]]
deps = ["PlotUtils", "Requires", "Statistics"]
git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d"
uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
version = "2.0.1"

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

[[PlotlyBase]]
deps = ["ColorSchemes", "Dates", "DelimitedFiles", "DocStringExtensions", "JSON", "LaTeXStrings", "Logging", "Parameters", "Pkg", "REPL", "Requires", "Statistics", "UUIDs"]
git-tree-sha1 = "180d744848ba316a3d0fdf4dbd34b77c7242963a"
uuid = "a03496cd-edff-5a9b-9e67-9cda94a718b5"
version = "0.8.18"

[[PlotlyJS]]
deps = ["Base64", "Blink", "DelimitedFiles", "JSExpr", "JSON", "Kaleido_jll", "Markdown", "Pkg", "PlotlyBase", "REPL", "Reexport", "Requires", "WebIO"]
git-tree-sha1 = "53d6325e14d3bdb85fd387a085075f36082f35a3"
uuid = "f0f68f2c-4968-5e81-91da-67840de0976a"
version = "0.18.8"

[[Plots]]
deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "Unzip"]
git-tree-sha1 = "9213b4c18b57b7020ee20f33a4ba49eb7bef85e0"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
version = "1.27.0"

[[PlutoUI]]
deps = ["AbstractPlutoDingetjes", "Base64", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"]
git-tree-sha1 = "5152abbdab6488d5eec6a01029ca6697dff4ec8f"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.23"

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

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

[[Qt5Base_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"]
git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8"
uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1"
version = "5.15.3+0"

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

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

[[RecipesBase]]
git-tree-sha1 = "6bf3f380ff52ce0832ddd3a2a7b9538ed1bcca7d"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.2.1"

[[RecipesPipeline]]
deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"]
git-tree-sha1 = "995a812c6f7edea7527bb570f0ac39d0fb15663c"
uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c"
version = "0.5.1"

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

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

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.3.0"

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

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

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

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

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

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "74fb527333e72ada2dd9ef77d98e4991fb185f04"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.4.1"

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

[[StatsAPI]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "c3d8ba7f3fa0625b062b82853a7d5229cb728b6b"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.2.1"

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

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

[[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", "OrderedCollections", "TableTraits", "Test"]
git-tree-sha1 = "5ce79ce186cc678bbb5c5681ca3379d1ddae11a1"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.7.0"

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

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

[[URIParser]]
deps = ["Unicode"]
git-tree-sha1 = "53a9f49546b8d2dd2e688d216421d050c9a31d0d"
uuid = "30578b45-9adc-5946-b283-645ec420af67"
version = "0.4.1"

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

[[UnPack]]
git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
version = "1.0.2"

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

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

[[Unitful]]
deps = ["ConstructionBase", "Dates", "LinearAlgebra", "Random"]
git-tree-sha1 = "b649200e887a487468b71821e2644382699f1b0f"
uuid = "1986cc42-f94f-5a68-af5c-568840ba703d"
version = "1.11.0"

[[UnitfulRecipes]]
deps = ["RecipesBase", "Unitful"]
git-tree-sha1 = "2f61bddb66a5a563b5e67c336577f1af1e650f7b"
uuid = "42071c24-d89e-48dd-8a24-8a12d9b8861f"
version = "1.5.3"

[[Unzip]]
git-tree-sha1 = "34db80951901073501137bdbc3d5a8e7bbd06670"
uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d"
version = "0.1.2"

[[Wayland_jll]]
deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23"
uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89"
version = "1.19.0+0"

[[Wayland_protocols_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4528479aa01ee1b3b4cd0e6faef0e04cf16466da"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.25.0+0"

[[WebIO]]
deps = ["AssetRegistry", "Base64", "Distributed", "FunctionalCollections", "JSON", "Logging", "Observables", "Pkg", "Random", "Requires", "Sockets", "UUIDs", "WebSockets", "Widgets"]
git-tree-sha1 = "c9529be473e97fa0b3b2642cdafcd0896b4c9494"
uuid = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29"
version = "0.8.17"

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

[[Widgets]]
deps = ["Colors", "Dates", "Observables", "OrderedCollections"]
git-tree-sha1 = "505c31f585405fc375d99d02588f6ceaba791241"
uuid = "cc8bc4a8-27d6-5769-a93b-9d913e69aa62"
version = "0.6.5"

[[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_libXcursor_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd"
uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724"
version = "1.2.0+4"

[[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_libXfixes_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4"
uuid = "d091e8ba-531a-589c-9de9-94069b037ed8"
version = "5.0.3+4"

[[Xorg_libXi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"]
git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246"
uuid = "a51aa0fd-4e3c-5386-b890-e753decda492"
version = "1.7.10+4"

[[Xorg_libXinerama_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"]
git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123"
uuid = "d1454406-59df-5ea1-beac-c340f2130bc3"
version = "1.1.4+4"

[[Xorg_libXrandr_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631"
uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484"
version = "1.5.2+4"

[[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_libxkbfile_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2"
uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a"
version = "1.1.0+4"

[[Xorg_xcb_util_image_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97"
uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b"
version = "0.4.0+1"

[[Xorg_xcb_util_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"]
git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1"
uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5"
version = "0.4.0+1"

[[Xorg_xcb_util_keysyms_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00"
uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7"
version = "0.4.0+1"

[[Xorg_xcb_util_renderutil_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e"
uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e"
version = "0.3.9+1"

[[Xorg_xcb_util_wm_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67"
uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361"
version = "0.4.1+1"

[[Xorg_xkbcomp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"]
git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b"
uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4"
version = "1.4.2+4"

[[Xorg_xkeyboard_config_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"]
git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d"
uuid = "33bec58e-1273-512f-9401-5d533626f822"
version = "2.27.0+4"

[[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 = "e45044cd873ded54b6a5bac0eb5c971392cf1927"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.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"

[[libblastrampoline_jll]]
deps = ["Artifacts", "Libdl", "OpenBLAS_jll"]
uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"

[[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 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c"
uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
version = "1.3.7+1"

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

[[xkbcommon_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"]
git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6"
uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd"
version = "0.9.1+5"
"""

# ╔═╡ Cell order:
# ╟─9da8b652-11d5-4239-abb2-b165f89c7a51
# ╟─7291ecff-dca9-4cf1-a2b4-97e97d41c98f
# ╟─d94ce667-2f71-4bcc-ad32-e7b03beaec6a
# ╟─420ac294-a186-4277-bd56-9c6334c8b9f8
# ╟─acc997cf-8244-4001-9caa-37f33ce947c3
# ╟─cb438563-e0b4-480d-ab58-c8162717a886
# ╠═57b9638f-cd2e-4687-a85d-f7fb32dea1d0
# ╠═26ba1d81-a7a5-46e1-bbab-892a659eb18d
# ╠═76529ec7-c678-4569-b121-8391b22b43a1
# ╠═491f71f3-1dc9-48d6-852b-a09b1663e658
# ╟─fc33d878-71a7-443f-9157-f905ccded4c7
# ╠═65dded8b-1197-432e-93ea-d02f9d6c775a
# ╠═74975d87-9999-4ef9-bf62-a0294d60c511
# ╠═58bb2681-9699-477a-8fb2-fdf4208d48f7
# ╟─5bffc527-b8f7-4fbf-bbff-b5ae8a5a4178
# ╟─5104846f-0dc1-4711-b948-77c69a9db2df
# ╟─ba11c481-bd6c-449b-aaf3-b0609582e371
# ╟─f9a5c3f0-5e05-45da-acfc-e03e81a7b36d
# ╟─a225f838-bd6e-425d-b531-d7adf7f3768d
# ╟─52866331-2bdb-4e0d-b8f6-5cfcdff56057
# ╟─12524387-5a27-499b-9933-8c4f0522b425
# ╟─e748ed86-7bbc-4d30-b6de-283b680f60bb
# ╟─b1449db0-c818-4fb5-9d72-78936db99cbe
# ╟─6c9eaa0e-d1b5-4442-993e-d1b6ae15a27d
# ╟─6b26235d-d148-4dd5-a1ad-13acea9a878a
# ╠═8e4c40f3-26f0-4fb4-b7ae-5c47e7de1cd3
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


# This file is pat of RLinearAlgebra.jl
# 1. Specifies type
# 2. Implements sample function
# 3. Exports Type

# using Random

"""
    LinSysVecRowOneRandCyclic <: LinSysVecRowSelect

A mutable structure with a field to store a cycling order. Randomly specifies a cycling
order over the equations of a linear system. Once this ordering is specified, the ordering
is kept fixed.

# Fields
- `order::Union{Vector{Int64},Nothing}`

Calling `LinSysVecRowOneRandCyclic()` defaults to setting `order` to `nothing`. The `sample`
function will handle the re-initialization of the fields once the system is provided.
"""
mutable struct LinSysVecRowOneRandCyclic <: LinSysVecRowSelect
    order::Union{Vector{Int64},Nothing}
end
LinSysVecRowOneRandCyclic() = LinSysVecRowOneRandCyclic(nothing)

# Common sample interface for linear systems
function sample(
    type::LinSysVecRowOneRandCyclic,
    A::AbstractArray,
    b::AbstractVector,
    x::AbstractVector,
    iter::Int64
)
    if iter == 1
        type.order = randperm(length(b))
    end

    eqn_ind = type.order[mod(iter, 1:length(b))]
    return A[eqn_ind, :], b[eqn_ind]
end

#export LinSysVecRowOneRandCyclic


# general.jl

export create_froms, count_trans_L, transTens_MLE, forecDist,
    deepcopyFields, timemod!, etr;

function create_froms(K::UInt16, L::UInt16)
  x = UInt16(1):K
  xx = collect(Iterators.product(Iterators.repeated(x,Int(L))...))
  (vec(xx), length(xx))
end
function create_froms(K::Int, L::Int)
  x = 1:K
  xx = collect(Iterators.product(Iterators.repeated(x,L)...))
  (vec(xx), length(xx))
end

"""
    count_trans_L(S, K, L)

Returns a tensor with counts of observed `L`th order transitions in `S`
  for a chain with `K` states. The first dimension is time now, the next
  dimension is lag 1, then lag 2, and so on.

### Example
```julia
  S = [1,2,1,1,1,2,4,1,3,1,1,3,1,2,1,1,2]
  count_trans_L(S, 4, 2)
```
"""
function count_trans_L(S::Vector{Int}, K::Int, L::Int)
    @assert minimum(S) >= 1 && maximum(S) <= K
    N = zeros(Int, fill(K,L+1)...)

    for tt in (L+1):length(S)
      Srev_now = S[range(tt, step=-1, length=(L+1))]
      N[(Srev_now)...] += 1
    end

    N
end

"""
    transTens_MLE(S, K, L)

Returns a tensor with estimated transition probabilities for `L`th order transitions in `S`
  for a chain with `K` states. The first dimension is time now, the next
  dimension is lag 1, then lag 2, and so on.

### Example
```julia
  S = [1,2,1,1,1,2,4,1,3,1,1,3,1,2,1,1,2]
  N = count_trans_L(S, 4, 2)
  transTens_MLE(S, 4, 2)
  transTens_MLD(N)
```
"""
function transTens_MLE(S::Vector{Int}, K::Int, L::Int)
    @assert minimum(S) >= 1 && maximum(S) <= K
    N = count_trans_L(S, K, L)
    N ./ sum(N, dims=1)
end
function transTens_MLE(N::Union{Array{Float64}, Array{Int64}})
    N ./ sum(N, dims=1)
end

"""
    forecDist(Slag::Vector{Int}, λ::Vector{Float64}, Q::Matrix{Float64})

Computes the forecast distribution given lagged values and parameters.

### Example
```julia
    lam = [0.6, 0.3, 0.1]
    Q = reshape([0.7, 0.3, 0.25, 0.75], (2,2))
    Slagrev = [1,1,2]
    forecDist(Slagrev, lam, Q)
```
"""
function forecDist(Slagrev::Vector{Int}, λ::Vector{Float64}, Q::Matrix{Float64})
    K = size(Q)[1]
    L = size(λ)[1]
    @assert size(Slagrev)[1] == L
    w = zeros(Float64, K)
    for k in 1:K
        for ℓ in 1:L
            w[k] += λ[ℓ] * Q[k, Slagrev[ℓ]]
        end
    end
    w
end

## from Arthur Lui
function deepcopyFields(state::T, fields::Vector{Symbol}) where T
  substate = Dict{Symbol, Any}()

  for field in fields
    substate[field] = deepcopy(getfield(state, field))
  end

  return substate
end

function postSimsInit(monitor::Union{Vector{Symbol}, Nothing}, n_keep::Int, init_state::Union{ParamsMTD, ParamsMTDg, ParamsMMTD})

    if typeof(monitor) == Vector{Symbol}
        state = deepcopyFields(init_state, monitor)
    else
        state = Dict{Symbol, Any}()
    end

    state[:llik] = 0.0

    sims = [ deepcopy(state) for i = 1:n_keep ]

    return sims
end

## MCMC timing for benchmarks
function timemod!(n::Int64, model::Union{ModMTD, ModMTDg, ModMMTD}, niter::Int, outfilename::String)
    outfile = open(outfilename, "a+")
    write(outfile, "timing for $(niter) iterations each:\n")
    for i in 1:n
        tinfo = @timed mcmc!(model, niter, save=false, report_filename=outfilename)
        write(outfile, "trial $(i), elapsed: $(tinfo[2]) seconds, allocation: $(tinfo[3]/1.0e6) Megabytes\n")
    end
    close(outfile)
end

## estimate time remaining
function etr(timestart::DateTime, n_keep::Int, thin::Int, outfilename::String)
    timeendburn = now()
    durperiter = (timeendburn - timestart).value / 1.0e5 # in milliseconds
    milsecremaining = durperiter * (n_keep * thin)
    estimatedfinish = now() + Dates.Millisecond(Int64(round(milsecremaining)))
    report_file = open(outfilename, "a+")
    write(report_file, "Completed burn-in at $(durperiter/1.0e3*1000.0) seconds per 1000 iterations \n
      $(durperiter/1.0e3/60.0*1000.0) minutes per 1000 iterations \n
      $(durperiter/1.0e3/60.0/60.0*1000.0) hours per 1000 iterations \n
      estimated completion time $(estimatedfinish)\n\n")
    close(report_file)
end


"""
    PathGraph{T<:Integer}

A path graph, with each node linked to the previous and next one.
"""
struct PathGraph{T<:Integer} <: LG.AbstractGraph{T}
    nv::T
    function PathGraph{T}(nv::T) where {T<:Integer}
        _nv = nv >= 0 ? T(nv) : zero(T)
        new{T}(_nv)
    end
end

PathGraph(nv::T) where {T<:Integer} = PathGraph{T}(nv)

LG.eltype(::PathGraph{T}) where {T} = T
LG.edgetype(::PathGraph{T}) where {T} = LG.Edge{T}
LG.is_directed(::Type{<:PathGraph}) = false
LG.nv(g::PathGraph) = g.nv
LG.ne(g::PathGraph) = max(0, Int(LG.nv(g)) - 1)
LG.vertices(g::PathGraph) = 1:LG.nv(g)

LightGraphs.edges(g::PathGraph) = [LG.Edge(i, i+1) for i in 1:LG.nv(g)-1]

LightGraphs.has_vertex(g::PathGraph, v) = 1 <= v <= LG.nv(g)

function LightGraphs.outneighbors(g::PathGraph, v)
    LG.has_vertex(g, v) || return Int[]
    nv(g) > 1 || return Int[]
    if v == 1
        return [2]
    end
    if v == nv(g)
        return [nv(g)-1]
    end
    return [v-1, v+1]
end

LightGraphs.inneighbors(g::PathGraph, v) = outneighbors(g, v)

function LightGraphs.has_edge(g::PathGraph, v1, v2)
    if !has_vertex(g, v1) || !has_vertex(g, v2)
        return false
    end
    return abs(v1-v2) == 1
end

# =======================================================
#         overrides
# =======================================================

# we use this check so that we have the same convention as in LightGraphs
LG.is_connected(g::PathGraph) = nv(g) > 0

function LG.connected_components(g::PathGraph)

    nv(g) == 0 && return typeof(vertices(g))[]
    return [vertices(g)]
end

# has_self_loops is defined in terms of this
LG.num_self_loops(::PathGraph) = 0

LG.is_bipartite(g::PathGraph) = true

function LG.squash(g::PathGraph)
    nvg = nv(g)
    for T ∈ (UInt8, UInt16, UInt32, UInt64)
        nv(g) < typemax(T) && return PathGraph(T(nvg))
    end
end

# ---- degree -----------------------------------

function LG.Δ(g::PathGraph)
    nvg = nv(g)
    return typemin(Int) * (nvg == 0) + (nvg >= 2) + (nvg >= 3)
end

LG.Δout(g::PathGraph) = Δ(g)
LG.Δin(g::PathGraph) = Δ(g)

function LG.δ(g::PathGraph)
    nvg = nv(g)
    return ifelse(nvg == 0, typemax(Int), ifelse(nvg == 1, 0, 1))
end

LG.δout(g::PathGraph) = δ(g)
LG.δin(g::PathGraph) = δ(g)

# =======================================================
#         matrices
# =======================================================

# TODO If there is a library that provides this, we could use a Toeplitz matrix instead
function LG.adjacency_matrix(g::PathGraph, T::DataType=Int; dir=:out)

    nvg = nv(g)
    dv = zeros(T, nv(g))
    ev = ones(T, max(0, Int(nv(g)) - 1))
    return SymTridiagonal(dv, ev)
end


mutable struct Cell <: AbstractAgent
    id::Int
    pos::Tuple{Int,Int}
    status::Bool
end

"""
``` julia
game_of_life(;
    rules::Tuple = (2, 3, 3, 3),
    dims = (100, 100),
    Moore = true
)
```
Same as in [Conway's game of life](@ref).
"""
function game_of_life(;
    rules::Tuple = (2, 3, 3, 3),
    dims = (100, 100),
    Moore = true
)
    space = GridSpace(dims, moore = Moore)
    properties = Dict(:rules => rules)
    model = ABM(Cell, space; properties = properties)
    node_idx = 1
    for x in 1:dims[1]
        for y in 1:dims[2]
            add_agent_pos!(Cell(node_idx, (x, y), false), model)
            node_idx += 1
        end
    end
    return model, dummystep, game_of_life_model_step!
end

function game_of_life_model_step!(model)
    new_status = fill(false, nagents(model))
    for (agid, ag) in model.agents
        nlive = nlive_neighbors(ag, model)
        if ag.status == true && (nlive ≤ model.rules[4] && nlive ≥ model.rules[1])
            new_status[agid] = true
        elseif ag.status == false && (nlive ≥ model.rules[3] && nlive ≤ model.rules[4])
            new_status[agid] = true
        end
    end

    for k in keys(model.agents)
        model.agents[k].status = new_status[k]
    end
end

function nlive_neighbors(ag, model)
    neighbors_coords = node_neighbors(ag, model)
    nlive = 0
    for nc in neighbors_coords
        nag = model.agents[Agents.coord2vertex((nc[2], nc[1]), model)]
        if nag.status == true
            nlive += 1
        end
    end
    return nlive
end


using SuperFastGraphs
using Base.Test
using LightGraphs

# g = Graph(5)

# add_edge!(g, 1, 2)
# add_edge!(g, 1, 3)
# add_edge!(g, 1, 4)
# add_edge!(g, 1, 5)
# # add_edge!(g, 1, 6)
# # add_edge!(g, 1, 7)

# add_edge!(g, 2, 3)
# add_edge!(g, 2, 4)
# # add_edge!(g, 5, 8)
# # add_edge!(g, 2, 9)
# # add_edge!(g, 4, 5)
# # add_edge!(g, 8, 9)

g = Graph(6)

add_edge!(g, 1, 2)
add_edge!(g, 1, 3)
add_edge!(g, 1, 4)
add_edge!(g, 1, 5)
add_edge!(g, 2, 3)
add_edge!(g, 3, 6)
add_edge!(g, 4, 5)

g = loadgraph("./testdata/karate.lg", "graph")

@test sampleDistance(g, 1000) == 2.408199643493761

@test iFub(g, 1) == 5
@test iFub(g) == 5

cc1 = closeness_centrality(g)[1]
cc1Sample = ccSample(g, 10, 1)
@test (cc1Sample < (cc1 + 1)) & (cc1Sample > (cc1 - 1))

@test (triangleCountingDegree(g) == triangles(g))
@test (triangleForward(g) == sum(triangles(g))/3)

## TEST PREPROCESS
gDWeakly = DiGraph(6)
add_edge!(gDWeakly, 1, 2)
add_edge!(gDWeakly, 1, 3)
add_edge!(gDWeakly, 1, 4)
add_edge!(gDWeakly, 5, 1)
add_edge!(gDWeakly, 2, 3)
add_edge!(gDWeakly, 3, 6)
add_edge!(gDWeakly, 4, 5)
@test preProcess(gDWeakly) == ([[1, 4, 5], [2], [3], [6]], [6, 3, 2, 1], [10, 4, 2, 1])

gDStrongly = DiGraph(3)
add_edge!(gDStrongly, 1, 2)
add_edge!(gDStrongly, 2, 3)
add_edge!(gDStrongly, 3, 1)
@test preProcess(gDStrongly) == ([[1, 2, 3]], [3], [3])

gNotD_NotC = Graph(6)
add_edge!(gNotD_NotC, 1, 2)
add_edge!(gNotD_NotC, 1, 3)
add_edge!(gNotD_NotC, 2, 4)
add_edge!(gNotD_NotC, 2, 5)
add_edge!(gNotD_NotC, 5, 4)
@test preProcess(gNotD_NotC) == ([[1, 2, 3, 4, 5], [6]], [5, 1], [5, 1])

## TEST FASTCLOSENESSCENTRALITY
@test ((sort!(closeness_centrality(g)))[end] == topKcc(g, 1)[1][2])
@test ((sort!(closeness_centrality(g)))[end - 5] == topKcc(g, 5)[1][2])

## TEST TRIANGLE COUNTING


# Grid test
using CommonLH, Test

function linear_test_grid(n :: Integer)
    return LinearGrid(-3.0, 4.0, n);
end

function power_spaced_test_grid(n :: Integer)
    return PowerSpacedGrid(-3.0, 4.0, n, 0.5)
end

function lin_spaced_test_grid(n :: Integer)
    return LinSpacedGrid(-3.0, 4.0, n, -0.2)
end

function general_test(g :: AbstractGrid)
    @testset "General" begin
        @test length(g) > 1
        @test minimum(g) < maximum(g)
        gridV = grid(g);
        @test length(gridV) == length(g)
        @test all(diff(gridV) .> 0)
        @test gridV[end] ≈ maximum(g)
        @test gridV[1] ≈ minimum(g)
        @test g[1] ≈ gridV[1]
        @test g[end] ≈ gridV[end]
        @test all(intervals(g) .≈ diff(gridV))
        @test sum(intervals(g)) ≈ maximum(g) - minimum(g)
        for (ig, gPoint) in enumerate(g)
            @test gPoint ≈ gridV[ig]
        end

        for ig = 1 : length(g)
            @test g[ig] ≈ gridV[ig]
        end

    end
end

function linear_test(g :: LinearGrid)
    @testset "Linear" begin
        stepV = intervals(g);
        @test all(stepV .≈ stepV[1])
    end
end

@testset "Grids" begin
    n = 5;
    for g in [linear_test_grid(n), power_spaced_test_grid(n),
        lin_spaced_test_grid(n)]

        general_test(g)
    end

    linear_test(linear_test_grid(n));
end

# ---------------


# ---
# title: 1388. Pizza With 3n Slices
# id: problem1388
# author: Tian Jun
# date: 2020-10-31
# difficulty: Hard
# categories: Dynamic Programming
# link: <https://leetcode.com/problems/pizza-with-3n-slices/description/>
# hidden: true
# ---
#
# There is a pizza with 3n slices of varying size, you and your friends will
# take slices of pizza as follows:
#
#   * You will pick **any** pizza slice.
#   * Your friend Alice will pick next slice in anti clockwise direction of your pick.
#   * Your friend Bob will pick next slice in clockwise direction of your pick.
#   * Repeat until there are no more slices of pizzas.
#
# Sizes of Pizza slices is represented by circular array `slices` in clockwise
# direction.
#
# Return the maximum possible sum of slice sizes which you can have.
#
#
#
# **Example 1:**
#
# ![](https://assets.leetcode.com/uploads/2020/02/18/sample_3_1723.png)
#
#
#
#     Input: slices = [1,2,3,4,5,6]
#     Output: 10
#     Explanation: Pick pizza slice of size 4, Alice and Bob will pick slices with size 3 and 5 respectively. Then Pick slices with size 6, finally Alice and Bob will pick slice of size 2 and 1 respectively. Total = 4 + 6.
#
#
# **Example 2:**
#
# **![](https://assets.leetcode.com/uploads/2020/02/18/sample_4_1723.png)**
#
#
#
#     Input: slices = [8,9,8,6,1,1]
#     Output: 16
#     Output: Pick pizza slice of size 8 in each turn. If you pick slice with size 9 your partners will pick slices of size 8.
#
#
# **Example 3:**
#
#
#
#     Input: slices = [4,1,2,5,8,3,1,9,7]
#     Output: 21
#
#
# **Example 4:**
#
#
#
#     Input: slices = [3,1,2]
#     Output: 3
#
#
#
#
# **Constraints:**
#
#   * `1 <= slices.length <= 500`
#   * `slices.length % 3 == 0`
#   * `1 <= slices[i] <= 1000`
#
#
## @lc code=start
using LeetCode

## add your code here:
## @lc code=end


using GAIO
using Interpolations
using QuadGK
using LinearAlgebra
using StaticArrays

# a vector field exhibiting a knotted trajectory
function knotted_v(x, tol)
    A = 2
    B = 1
    L = 0.9
    h = 2
    r = 2
    p = 3
    q = 4
    T = 2*π*A

    γ = t -> (
        cos(t) - (L*A)/(A+B) * cos((A+B)/A * t),
        sin(t) - (L*A)/(A+B) * sin((A+B)/A * t),
       -sin(B/A * t) + h * (1-2*t/T)^p
    )

    γ_t = t -> (
       -sin(t) + (L*A)/A * sin((A+B)/A * t),
        cos(t) - (L*A)/A * cos((A+B)/A * t),
       -cos(B/A * t) * B/A - h * p * (1-2*t/T)^(p-1) * 2/T
    )

    d = (x, y) -> inv(sum(abs.(x .- y) .^ q))

    σ = x -> (x[1]/(1-x[3]), x[2]/(1-x[3]))

    σ_inv = x -> (
        2*x[1]/(1 + x[1]^2 + x[2]^2),
        2*x[2]/(1 + x[1]^2 + x[2]^2),
         1 - 2/(1 + x[1]^2 + x[2]^2)
    )

    # approximate the integral with adaptive Gauss quadrature for given tolerance
    int, = quadgk(t -> begin
        γt = γ(t)
        γdt = γ_t(t)
        nγdt = norm(γdt)
        dγt = d(x, γt)
        σγ = σ(γdt ./ nγdt)
        val = nγdt .* dγt .* σγ
        return SVector(val[1], val[2], nγdt * dγt)
    end, 0, T, rtol=tol)

    nom = (int[1], int[2])
    denom1 = int[3]
    y = (r * x[1] / norm((x[1], x[2])), r * x[2] / norm((x[1], x[2])), x[3])
    denom2 = d(x, y)

    w = nom ./ (denom1 + denom2)

    return σ_inv(w)
end
# interpolate the function v on the mesh [a,b]^3 with n equidistant nodes
# using linear B-Splines
function interpolate_v(v, a, b, n, tol)
    val = Array{SVector{3,Float64},3}(undef, n, n, n)
    x = range(a, b, length = n)
    y = range(a, b, length = n)
    z = range(a, b, length = n)

    @Threads.threads for i in 1:n
        for j in 1:n
            for k in 1:n
                val[i,j,k] = SVector(v((x[i], y[j], z[k]), tol))
            end
        end
    end

    itp = interpolate(val, BSpline(Linear()))
    sitp = scale(itp, x, y, z)

    return t -> sitp(t[1], t[2], t[3])
end

vf = interpolate_v(knotted_v, -3.5, 3.5, 30, 1e-12)
f(x) = rk4_flow_map(vf, x, step_size = 0.075)

center, radius = (0,0,0), (2,2,2)
P = BoxPartition(Box(center, radius))
F = BoxMap(f, P, no_of_points = 200)

C = chain_recurrent_set(F, P[:], steps = 18)

plot(C)


@doc raw"""
`VDAE`: Variational Differential Algebraic Equation *EXPERIMENTAL*

Defines an implicit initial value problem
```math
\begin{align*}
\dot{q} (t) &= v(t) + λ(t), &
q(t_{0}) &= q_{0} , \\
\dot{p} (t) &= f(t, q(t), v(t)) + g(t, q(t), λ(t)) + \obar{g}(t, q(t), μ(t)) , &
p(t_{0}) &= p_{0} , \\
p(t) &= ϑ(t, q(t), v(t)) , \\
0 &= \phi (t, q(t), p(t)) , \\
0 &= \psi (t, q(t), p(t), \dot{q}(t), \dot{p}(t)) ,
\end{align*}
```
with vector field ``f``, the momentum defined by ``p``, initial conditions ``(q_{0}, p_{0})`` and the solution
``(q,p)`` taking values in ``\mathbb{R}^{d} \times \mathbb{R}^{d}`` and
the algebraic variables ``(v, \lambda, \mu)`` taking values in
``\mathbb{R}^{d} \times \mathbb{R}^{d} \times \mathbb{R}^{m}``.
This is a special case of a differential algebraic equation with dynamical
variables ``(q,p)`` and algebraic variables ``v``, ``\lambda`` and ``\mu``.

### Fields

* `d`: dimension of dynamical variables ``q`` and ``p`` as well as the vector fields ``f`` and ``p``
* `ϑ`: function determining the momentum
* `f`: function computing the vector field
* `g`: function determining the primary projection, usually given by ∇ϑ(q)⋅λ
* `g̅`: function determining the secondary projection, usually given by λ⋅∇ϑ(q)
* `ϕ`: primary constraints, usually given by p-ϑ(q)
* `ψ`: secondary constraints, usually given by ṗ-q̇⋅∇ϑ(q)
* `v`: function computing an initial guess for the velocity field (optional)
* `Ω`: symplectic matrix (optional)
* `∇H`: gradient of the Hamiltonian (optional)
* `t₀`: initial time (optional)
* `q₀`: initial condition for `q`
* `p₀`: initial condition for `p`
* `λ₀`: initial condition for `λ` (optional)
* `μ₀`: initial condition for `μ` (optional)

The functions `ϑ` and `f` must have the interface
```julia
    function ϑ(t, q, v, p)
        p[1] = ...
        p[2] = ...
        ...
    end
```
and
```julia
    function f(t, q, v, f)
        f[1] = ...
        f[2] = ...
        ...
    end
```
where `t` is the current time, `q` is the current solution vector, `v` is the
current velocity and `f` and `p` are the vectors which hold the result of
evaluating the functions ``f`` and ``ϑ`` on `t`, `q` and `v`.
The funtions `g` and `v` are specified by
```julia
    function g(t, q, λ, g)
        g[1] = ...
        g[2] = ...
        ...
    end
```
and
```julia
    function v(t, q, p, v)
        v[1] = ...
        v[2] = ...
        ...
    end
```
"""
struct VDAE{dType <: Number, tType <: Number, ϑType <: Function,
            fType <: Function, gType <: Function, g̅Type <: Function,
            ϕType <: Function, ψType <: Function, vType <: Function,
            ΩType <: Union{Function,Nothing}, ∇HType <: Union{Function,Nothing},
            pType <: Union{Tuple,Nothing}, N} <: AbstractEquationPDAE{dType, tType}

    d::Int
    m::Int
    n::Int
    ϑ::ϑType
    f::fType
    g::gType
    g̅::g̅Type
    ϕ::ϕType
    ψ::ψType
    v::vType
    Ω::ΩType
    ∇H::∇HType
    t₀::tType
    q₀::Array{dType, N}
    p₀::Array{dType, N}
    λ₀::Array{dType, N}
    μ₀::Array{dType, N}
    parameters::pType
    periodicity::Vector{dType}

    function VDAE(DT::DataType, N::Int, d::Int, m::Int, n::Int, ϑ::ϑType, f::fType,
                  g::gType, g̅::g̅Type, ϕ::ϕType, ψ::ψType, t₀::tType,
                  q₀::AbstractArray{dType}, p₀::AbstractArray{dType},
                  λ₀::AbstractArray{dType}, μ₀::AbstractArray{dType};
                  v::vType=nothing, Ω::ΩType=nothing, ∇H::∇HType=nothing,
                  parameters=nothing, periodicity=zeros(DT,d)) where {
                        dType <: Number, tType <: Number, ϑType <: Function,
                        fType <: Function, gType <: Function, g̅Type <: Function,
                        ϕType <: Function, ψType <: Function, vType <: Function,
                        ΩType <: Union{Function,Nothing}, ∇HType <: Union{Function,Nothing}}

        @assert d == size(q₀,1) == size(p₀,1) == size(λ₀,1)
        @assert m == size(μ₀,1)
        @assert n == size(q₀,2) == size(p₀,2)
        @assert ndims(q₀) == ndims(p₀) == N ∈ (1,2)

        new{DT, tType, ϑType, fType, gType, g̅Type, ϕType, ψType, vType, ΩType, ∇HType, typeof(parameters), N}(d, m, n, ϑ, f, g, g̅, ϕ, ψ, v, Ω, ∇H, t₀,
                convert(Array{DT}, q₀), convert(Array{DT}, p₀), convert(Array{DT}, λ₀), convert(Array{DT}, μ₀), parameters, periodicity)
    end
end

function VDAE(ϑ, f, g, g̅, ϕ, ψ, t₀::Number, q₀::AbstractArray{DT}, p₀::AbstractArray{DT}, λ₀::AbstractArray{DT}=zero(q₀), μ₀::AbstractArray{DT}=zero(q₀); kwargs...) where {DT}
    VDAE(DT, ndims(q₀), size(q₀,1), size(μ₀,1), size(q₀,2), ϑ, f, g, g̅, ϕ, ψ, t₀, q₀, p₀, λ₀, μ₀; kwargs...)
end

function VDAE(ϑ, f, g, g̅, ϕ, ψ, q₀::AbstractArray, p₀::AbstractArray, λ₀::AbstractArray=zero(q₀), μ₀::AbstractArray=zero(q₀); kwargs...)
    VDAE(ϑ, f, g, g̅, ϕ, ψ, zero(eltype(q₀)), q₀, p₀, λ₀, μ₀; kwargs...)
end

Base.hash(ode::VDAE, h::UInt) = hash(ode.d, hash(ode.m, hash(ode.n,
          hash(ode.ϑ, hash(ode.f, hash(ode.g, hash(ode.g̅, hash(ode.ϕ,
          hash(ode.ψ, hash(ode.v, hash(ode.Ω, hash(ode.∇H,
          hash(ode.t₀, hash(ode.q₀, hash(ode.p₀, hash(ode.λ₀, hash(ode.μ₀,
          hash(ode.parameters, hash(ode.periodicity, h)))))))))))))))))))

Base.:(==)(ode1::VDAE, ode2::VDAE) = (
                                ode1.d == ode2.d
                             && ode1.m == ode2.m
                             && ode1.n == ode2.n
                             && ode1.ϑ == ode2.ϑ
                             && ode1.f == ode2.f
                             && ode1.g == ode2.g
                             && ode1.g̅ == ode2.g̅
                             && ode1.ϕ == ode2.ϕ
                             && ode1.ψ == ode2.ψ
                             && ode1.v == ode2.v
                             && ode1.Ω == ode2.Ω
                             && ode1.∇H == ode2.∇H
                             && ode1.t₀ == ode2.t₀
                             && ode1.q₀ == ode2.q₀
                             && ode1.p₀ == ode2.p₀
                             && ode1.λ₀ == ode2.λ₀
                             && ode1.μ₀ == ode2.μ₀
                             && ode1.parameters == ode2.parameters
                             && ode1.periodicity == ode2.periodicity)

function Base.similar(ode::VDAE, q₀, p₀, λ₀=get_λ₀(q₀, ode.λ₀), μ₀=get_λ₀(q₀, ode.μ₀); kwargs...)
    similar(ode, ode.t₀, q₀, p₀, λ₀, μ₀; kwargs...)
end

function Base.similar(ode::VDAE, t₀::TT, q₀::AbstractArray{DT}, p₀::AbstractArray{DT},
                      λ₀::AbstractArray{DT}=get_λ₀(q₀, ode.λ₀), μ₀=get_λ₀(q₀, ode.μ₀);
                      parameters=ode.parameters, periodicity=ode.periodicity) where {DT  <: Number, TT <: Number}
    @assert ode.d == size(q₀,1) == size(p₀,1) == size(λ₀,1)
    VDAE(ode.ϑ, ode.f, ode.g, ode.g̅, ode.ϕ, ode.ψ, t₀, q₀, p₀, λ₀, μ₀;
         v=ode.v, Ω=ode.Ω, ∇H=ode.∇H, parameters=parameters, periodicity=periodicity)
end

@inline Base.ndims(ode::VDAE) = ode.d

@inline periodicity(equation::VDAE) = equation.periodicity


##### weighted least squares
 struct SemWLS{Vt <: Union{AbstractArray, UniformScaling{Bool}},
        St <: AbstractArray} <: LossFunction
    V::Vt
    s::St
end

### Constructor
function SemWLS(observed::T, objective, grad; V = nothing) where {T <: SemObs}
    ind = CartesianIndices(observed.obs_cov)
    ind = filter(x -> (x[1] >= x[2]), ind)
    s = observed.obs_cov[ind]
    # compute V here
    if isnothing(V)
        D = duplication_matrix(observed.n_man)
        S = inv(observed.obs_cov)
        S = kron(S,S)
        V = 0.5*(D'*S*D)
    end
    return SemWLS(V, s)
end

### Loss
function (semwls::SemWLS)(par, model)
    diff = semwls.s - model.imply.imp_cov
    F = dot(diff, semwls.V, diff)
    return F
end

############## SWLS
struct SemSWLS{Vt <: Union{AbstractArray, UniformScaling{Bool}},
        St <: AbstractArray} <: LossFunction
    V::Vt
    sᵀV::St
    #s::St
end

### Constructor
function SemSWLS(observed::T, objective, grad; V = nothing) where {T <: SemObs}
    ind = CartesianIndices(observed.obs_cov)
    ind = filter(x -> (x[1] >= x[2]), ind)
    s = observed.obs_cov[ind]

    if isnothing(V)
        D = duplication_matrix(observed.n_man)
        S = inv(observed.obs_cov)
        S = kron(S,S)
        V = 0.5*(D'*S*D)
    end

    sᵀV = transpose(s)*V
    return SemSWLS(V, sᵀV)
end

### Loss
function (semswls::SemSWLS)(par, model)
    # s = semswls.s
    # V = semswls.V
    # G = model.imply.G
    outer = semswls.sᵀV*model.imply.G
    b = cholesky(Symmetric(model.imply.G'*semswls.V*model.imply.G))
    inner = b\outer'
    F = -outer*inner
    # F = transpose(s)*V*s - transpose(s)*V*G*inv(transpose(G)*V*G)*(transpose(G)*V*s)
#=     θ = inv(transpose(G)*V*G)*(transpose(G)*V*s)
    σ = G*θ
    diff = s - σ
    F = dot(diff, V, diff) =#
    return F
end


using GLMakie, JLD2, FFTW, Statistics
using FourierCore, FourierCore.Grid, FourierCore.Domain, Printf
# jld_name = "high_res_tracer_"
# jld_name = "high_order_timestep_spatial_tracer_"
# jld_name = "delete_me_later"
# jld_name = "high_order_timestep_tracer_"
jld_name = "tracer_"
# WARNING!!!! due to bug need to multiply all θ̅a by 5/4
Ω = S¹(4π)^2
N = 2^8 # number of gridpoints
κ = 2 / 2^8 # fixed diffusivity # in general should load from file
grid = FourierGrid(N, Ω, arraytype = Array)
nodes, wavenumbers = grid.nodes, grid.wavenumbers
# in the future load from file
x = nodes[1]
y = nodes[2]
kˣ = wavenumbers[1]
kʸ = wavenumbers[2]

if jld_name == "tracer_"
    bugfix = 5 / 4
    extrapolate = true # only works if zeroth mode is included
else
    bugfix = 1
    extrapolate = false # only works if zeroth mode is included
end

effective_diffusivity = Float64[]
index_choices = 2:40
for index_choice in index_choices
    println("on index ", index_choice)
    jlfile = jldopen(jld_name * string(index_choice) * ".jld2", "a+")
    ψ_save = jlfile["ψ_save"]
    θ_save = jlfile["θ_save"]
    if jld_name == "tracer_"
        κ = 2 / 2^8
        kˣ = wavenumbers[1]
    else
        κ = jlfile["κ"]
        xa = jlfile["xnodes"]
        ya = jlfile["ynodes"]
        kˣ = jlfile["kˣ_wavenumbers"]
    end
    θ̅a = mean(jlfile["θ̅a"], dims = 2)[:] * bugfix # messed up for tracer_ okay for others

    # calculate effective diffusivity
    # factor of 2 comes from the fact that the domain is 4π (as opposed to 2π)
    # will need to renormalize by length(θ̅a)/2 to take inverse transform
    if index_choice > 1
        𝒦ᵉᶠᶠ = ((length(θ̅a) / maximum(real.(fft(θ̅a)))) / 2) / (kˣ[index_choice]^2) - κ
    else
        𝒦ᵉᶠᶠ = abs(mean(θ̅a))
    end
    push!(effective_diffusivity, 𝒦ᵉᶠᶠ)
    close(jlfile)
end

fig = Figure()
ax = Axis(fig[1, 1]; xlabel = "wavenumber", ylabel = "𝒦(k)", title = "Effective Diffusivity")
scatter!(ax, Array(kˣ[index_choices]), effective_diffusivity)

ylims!(ax, (0.0, 0.4))
xlims!(ax, (-0.1, kˣ[index_choices[end]+1]))
display(fig)

for i in eachindex(effective_diffusivity)
    txtstring = @sprintf "%1.3f" effective_diffusivity[i]
    if i == 1
        print("[", txtstring, ", ")

    elseif i == length(effective_diffusivity)
        print(txtstring, "]")
    else
        print(txtstring, ", ")
    end
end
##
if extrapolate
    # only works if zeroth mode is included
    # fit model for effective diffusivity by picking out the pattern in the tail
    tail_index = length(effective_diffusivity) - 1 # 19 was good
    k₀ = kˣ[tail_index+1]
    a = 1 / effective_diffusivity[tail_index]
    c = (1 / effective_diffusivity[tail_index+1] - a) / (kˣ[tail_index+2]^2 - kˣ[tail_index+1]^2)
    # model_𝒦ᵉᶠᶠ(k) = 1 / (a + c * (k^2 - k₀^2))
    slope_index = index_choices[end] - 4
    logk = log.(kˣ[2:length(effective_diffusivity)+1])
    slope = (log.(effective_diffusivity[slope_index]) - log.(effective_diffusivity[slope_index-10])) / (logk[slope_index] - logk[slope_index-10])
    fit_function(x) = slope * (x - logk[slope_index]) + log(effective_diffusivity[slope_index])

    model_𝒦ᵉᶠᶠ(k) = abs(k) ≥ eps(100.0) ? exp(fit_function(log(abs(k)))) : 0.0 # just to handle zero well

    lines!(ax, Array(kˣ[index_choices[2:end]]), model_𝒦ᵉᶠᶠ.(Array(kˣ[index_choices[2:end]])), color = :red)

    ##
    hr_N = 1024 * 2
    hr_grid = FourierGrid(hr_N, Ω, arraytype = Array)
    hr_x = hr_grid.nodes[1]
    hr_kˣ = hr_grid.wavenumbers[1]

    fft_scaling = length(hr_x) / 2
    wavenumberspace = model_𝒦ᵉᶠᶠ.(hr_kˣ[:]) * fft_scaling # copy(x[:]) .* 0.0
    wavenumberspace[1] = effective_diffusivity[1] * fft_scaling
    wavenumberspace[div(length(hr_x), 2)+1] = 0.0 # need this because of redefinition of kˣ

    effective_diffusivity_mod = copy(effective_diffusivity[2:end])
    NKeff = length(effective_diffusivity_mod)
    wavenumberspace[2:1+NKeff] .= effective_diffusivity_mod * fft_scaling
    wavenumberspace[length(hr_x)-NKeff+1:end] .= reverse(effective_diffusivity_mod) * fft_scaling
    realspace = real.(ifft(wavenumberspace))

    # realspace = real.(ifft([0.0, effective_diffusivity..., reverse(effective_diffusivity)...]))
    index_shift = div(length(hr_x), 2) # div(length(realspace) - 1, 2) # div(length(x),2)
    realspace_shifted = circshift(realspace, index_shift) # .- minimum(realspace)
    println("zero'th mode is chosen to be ", minimum(realspace))
    fig_kernel = Figure()
    ax_kernel = Axis(fig_kernel[1, 1]; xlabel = "x-x'", ylabel = "𝒦(x-x')", title = "Effective Diffusivity")
    lines!(ax_kernel, hr_x[:], realspace_shifted)
end

##
#=
fig = Figure()
ax = Axis(fig[1, 1])
logk = log.(kˣ[2:length(effective_diffusivity)+1])
scatter!(logk, log.(effective_diffusivity))
slope_index = index_choices[end] - 4
slope = (log.(effective_diffusivity[slope_index]) - log.(effective_diffusivity[slope_index-10]))/(logk[slope_index] - logk[slope_index-10] )
fit_function(x) = slope*(x - logk[slope_index]) + log(effective_diffusivity[slope_index])
lines!(logk, fit_function.(logk), color = :red, linewidth = 3)

fig = Figure()
ax = Axis(fig[1, 1])
logk = log.(kˣ[2:length(effective_diffusivity)+1])
scatter!(kˣ[2:length(effective_diffusivity)+1], effective_diffusivity)
fit_function(x) = -(x - 3) - 4
lines!(kˣ[2:length(effective_diffusivity)+1], exp.(fit_function.(logk)), color = :red, linewidth = 3)
=#


#!/usr/bin/env julia

# Calculates some limits of the problem just using the dataset and parameters in the config file.
# * the largest baseline in u and v, separately.
# * the mean velocity of the dataset.
# * the physical scale of the image, and whether it fully encapsulates the model grid for
#   all of the possible distances to explore.

using ArgParse

s = ArgParseSettings()
@add_arg_table s begin
    "--config"
    help = "a YAML configuration file"
    default = "config.yaml"
end

# Load the file
parsed_args = parse_args(ARGS, s)

import YAML
config = YAML.load(open(parsed_args["config"]))

using DiskJockey.visibilities
using DiskJockey.constants
using DiskJockey.model

species = config["species"]
transition = config["transition"]
lam0 = lam0s[species*transition]
grid = Grid(config["grid"])

function wl_to_vel{T}(wl::T)
    return c_kms * (wl - lam0)/lam0
end

function vel_to_wl{T}(vel::T)
    beta = vel/c_kms # relativistic Doppler formula
    return lam0 * sqrt((1. - beta) / (1. + beta)) # [microns]
end

dvarr = DataVis(config["data_file"])

lam_start = dvarr[1].lam
lam_end = dvarr[end].lam

vmin = wl_to_vel(lam_start)
vmax = wl_to_vel(lam_end)
println("Dataset channels are velocities from $vmin to $vmax and span ", vmax - vmin, " km/s.")
println("Midpoint is ", (vmax + vmin)/2, " km/s.")

max_base = max_baseline(dvarr)

println("Max baseline ", max_base, " kilolambda")

# Given the size of the image in arcseconds and the number of pixels, figure out the nyquist
# sampling and whether or not this is sufficiently higher than our largest baseline
dRA = config["size_arcsec"] / config["npix"] # [arcsec/pix]

# Convert this to dRA or dDEC
dRA_max = 1/(nyquist_factor * max_base * 1e3) / arcsec # [arcsec / pix]

@assert dRA < dRA_max "Nyquist sampling not satisfied: Either increase the number of pixels in your image, or decrease the angular size of your image. dRA ($dRA [arcsec/pix]) is greater than dRA_max ($dRA_max [arcsec/pix]), which is determined from the maximum baseline of your dataset."

println("Nyquist sampling satisfied. dRA: $dRA [arcsec/pix] ; dRA_max: $dRA_max [arcsec/pix]")

# Given the angular size of the image, calculate what the physical size of the image would be
# at the closest source distance, and make sure that this is still larger than outer radius of
# the model grid.

mu_d = config["dpc_prior"]["mu"]
sig_d = config["dpc_prior"]["sig"]

dlow = mu_d - 3. * sig_d # [AU]

# Calculate the physical size of the image at the closer distance, and make sure it's still larger
# than 110% of the outer grid radius
sizeau = 0.5 * config["size_arcsec"] * dlow # [AU]
outer_radius = 1.1 * config["grid"]["r_out"]
@assert sizeau > outer_radius "The angular size of your image is too small to fully encapsulate the model grid at the closest distances to the source. Increase the angular size of your image via `size_arcsec` or decrease the outer radius of your model grid. Size at the closest distances $sizeau [AU]; outer radius of the grid + 10% $outer_radius [AU]"

println("Image size satisfied. Half-Image size at the closest distances: $sizeau [AU]; outer radius of the grid + 10%: $outer_radius [AU]")


module ChanceConstraintTest

using Test
using ForneyLab
using ForneyLab: outboundType, isApplicable
using ForneyLab: SPChanceConstraintOutG, truncatedGaussianMoments

#--------
# Helpers
#--------

@testset "truncatedGaussianMoments" begin
    @test truncatedGaussianMoments(0.0, 1.0, 0.0, Inf) == (0.5, 0.7978845608028654, 0.3633802276324186)
    @test truncatedGaussianMoments(0.0, 1.0, -Inf, 0.0) == (0.5, -0.7978845608028654, 0.3633802276324186)
    @test truncatedGaussianMoments(0.0, 1.0, -Inf, Inf) == (1.0, 0.0, 1.0)
    @test truncatedGaussianMoments(0.0, 1.0, 0.0, 0.0) == (0.0, 0.0, 0.0) # Improper truncation
end

#-------------
# Update rules
#-------------

@testset "SPChanceConstraintOutG" begin
    @test SPChanceConstraintOutG <: SumProductRule{ChanceConstraint}
    @test outboundType(SPChanceConstraintOutG) == Message{GaussianWeightedMeanPrecision}
    @test isApplicable(SPChanceConstraintOutG, [Nothing])

    @test ruleSPChanceConstraintOutG(Message(Univariate, GaussianMeanVariance, m=0.0, v=1.0), (0.0, Inf), 0.05) == Message(Univariate, GaussianWeightedMeanPrecision, xi=2.9470311004635064, w=2.2101933871827293)
    @test ruleSPChanceConstraintOutG(Message(Univariate, GaussianMeanVariance, m=0.0, v=1.0), (-Inf, Inf), 0.05) == Message(Univariate, GaussianWeightedMeanPrecision, xi=0.0, w=tiny)
end

@testset "averageEnergy" begin
    @test averageEnergy(ChanceConstraint, ProbabilityDistribution(GaussianMeanVariance, m=0.0, v=1.0)) == 0.0
end

#------------
# Integration
#------------

@testset "ChanceConstraint integration" begin
    fg = FactorGraph()
    @RV x ~ GaussianMeanVariance(0.0, 1.0)
    ChanceConstraint(x; G=(0.0, Inf), epsilon=0.05)

    pfz = PosteriorFactorization(fg)
    algo = messagePassingAlgorithm(x)
    algo_code = algorithmSourceCode(algo)

    @test occursin("ruleSPChanceConstraintOutG(messages[1], (0.0, Inf), 0.05)", algo_code)
end

end # module