text:
### 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

max_stars_repo_name: mdAshford/youCANdoThermodynamics

max_issues_repo_name: mdAshford/youCANdoThermodynamics

max_forks_repo_name: mdAshford/youCANdoThermodynamics


text:
function solve()
    n = parse(Int, readline())
    set = Set{String}()
    for _ in 1:n
        push!(set, readline())
    end
    length(set)
end

println(solve())

ext: jl

max_stars_repo_name: aishikawa/atcoder-julia

max_issues_repo_name: aishikawa/atcoder-julia

max_forks_repo_name: aishikawa/atcoder-julia


text:
#Run the tests

include("helper_parallel.jl")

println("Parallel HPL: Tuning step on one kernel")
#        1234567890123456789012345678901234567890123456
println("    k | Problem size (n) | Run time (sec.) | Gigaflops")

ks = collect(128*(1:5))
topt = Inf
kopt = 0
for k in ks
    @printf("%5d | ", k)
    n = 1000
    @printf("%16d | ", n)
    t = runhplp(n, k, k)
    if t < topt
        topt = t
        kopt = k
    end
    @printf("%15.6f | %15.9f\n", t, 1e-9*(2n^3/3 + 3n^2/2)/t)
end

info("Setting block size to k = $kopt for HPL")

for np in [1,2,4,8,16,32,64]#1:64#Sys.CPU_CORES
    ps = addprocs(min(np-nworkers(), 1))

#Broadcast function definitions to all workers
z = [@spawnat p include("helper_parallel.jl") for p in ps]
[fetch(w) for w in z]

println("Parallel HPL")
#        1234567890123456789012345678901234567890123456
println("Cores | Problem size (n) | Run time (sec.) | Gigaflops")
for e in 3:0.2:3.8
    @printf("%5d | ", nworkers())
    n = round(Int, 10^e)
    @printf("%16d | ", n)
    t = runhplp(n, kopt, kopt)
    @printf("%15.6f | %15.9f\n", t, 1e-9*(2n^3/3 + 3n^2/2)/t)
end

println("\n\n\nParallel random update")
#        12345678901234567890123456789012345678901234567890123
println("Cores | Problem size (m) | Run time (sec.) | Gigaupdates/sec.")
for e in 10:12#18:24
    @printf("%5d | ", nworkers())
    m = 2^e
    @printf("%16d | ", m)
    t = runrandomupdatep(m)
    @printf("%15.6f | %15.9f\n", t, m*1e-9/t)
end

println("\n\n\nParallel STREAM triad")
#        123456789012345678901234567890123456789012345678901
println("Cores | Problem size (m) | Run time (sec.) | Gigabytes/sec.")
for e in 6.5:0.5:8.0
    @printf("%5d | ", nworkers())
    m = round(Int, 10^e)
    @printf("%16d | ", m)
    t = runstreamtriadp(m)
    @printf("%15.6f | %15.9f\n", t, 1e-9*24*m/t)
end

#Not implemented
#println("\n\n\nParallel FFT")
##        123456789012345678901234567890123456789012345678901
#println("Cores | Problem size (m) | Run time (sec.) | Gigaflops")
#for e in 6:0.5:7
#    @printf("%5d | ", nworkers())
#    m = round(Int, 10^e)
#    @printf("%16d | ", m)
#    t = runfftp(m)
#    @printf("%15.6f | %15.9f\n", t, 5e-9*m*log2(m)/t)
#end

end #addprocs


text:
const USE_GPU = false  # Use GPU? If this is set false, then no GPU needs to be available
using ParallelStencil
using ParallelStencil.FiniteDifferences2D
@static if USE_GPU
    @init_parallel_stencil(CUDA, Float64, 2)
else
    @init_parallel_stencil(Threads, Float64, 2)
end
using Plots, Printf, Statistics, LinearAlgebra

@parallel function assign!(A::Data.Array, B::Data.Array)
    @all(A) = @all(B)
    return
end

@parallel function compute_error!(Err_A::Data.Array, A::Data.Array)
    @all(Err_A) = @all(Err_A) - @all(A)
    return
end

@parallel function compute_1!(RogT::Data.Array, Eta::Data.Array, ∇V::Data.Array, Pt::Data.Array, τxx::Data.Array, τyy::Data.Array, σxy::Data.Array, T::Data.Array, Vx::Data.Array, Vy::Data.Array, dτPt::Data.Array, ρ0gα::Data.Number, η0::Data.Number, dη_dT::Data.Number, ΔT::Data.Number, dτ_iter::Data.Number, β::Data.Number, dx::Data.Number, dy::Data.Number)
    @all(RogT) = ρ0gα*@all(T)
    @all(Eta)  = η0*(1.0 - dη_dT*(@all(T) + ΔT/2.0))
    @all(∇V)   = @d_xa(Vx)/dx + @d_ya(Vy)/dy
    @all(Pt)   = @all(Pt) - dτ_iter/β*@all(∇V)
    @all(τxx)  = 2.0*@all(Eta)*(@d_xa(Vx)/dx  - 1.0/3.0*@all(∇V))
    @all(τyy)  = 2.0*@all(Eta)*(@d_ya(Vy)/dy  - 1.0/3.0*@all(∇V))
    @all(σxy)  = 2.0*@av(Eta)*(0.5*(@d_yi(Vx)/dy + @d_xi(Vy)/dx))
    return
end

@parallel function compute_2!(Rx::Data.Array, Ry::Data.Array, dVxdτ::Data.Array, dVydτ::Data.Array, Pt::Data.Array, RogT::Data.Array, τxx::Data.Array, τyy::Data.Array, σxy::Data.Array, ρ::Data.Number, dampX::Data.Number, dampY::Data.Number, dτ_iter::Data.Number, dx::Data.Number, dy::Data.Number)
    @all(Rx)    = 1.0/ρ *(@d_xi(τxx)/dx + @d_ya(σxy)/dy - @d_xi(Pt)/dx               )
    @all(Ry)    = 1.0/ρ *(@d_yi(τyy)/dy + @d_xa(σxy)/dx - @d_yi(Pt)/dy + @av_yi(RogT))
    @all(dVxdτ) = dampX*@all(dVxdτ) + @all(Rx)*dτ_iter
    @all(dVydτ) = dampY*@all(dVydτ) + @all(Ry)*dτ_iter
    return
end

@parallel function update_V!(Vx::Data.Array, Vy::Data.Array, dVxdτ::Data.Array, dVydτ::Data.Array, dτ_iter::Data.Number)
    @inn(Vx) = @inn(Vx) + @all(dVxdτ)*dτ_iter
    @inn(Vy) = @inn(Vy) + @all(dVydτ)*dτ_iter
    return
end

@parallel function compute_qT!(qTx::Data.Array, qTy::Data.Array, T::Data.Array, DcT::Data.Number, dx::Data.Number, dy::Data.Number)
    @all(qTx) = -DcT*@d_xi(T)/dx
    @all(qTy) = -DcT*@d_yi(T)/dy
    return
end

@parallel_indices (ix,iy) function advect_T!(dT_dt::Data.Array, qTx::Data.Array, qTy::Data.Array, T::Data.Array, Vx::Data.Array, Vy::Data.Array, dx::Data.Number, dy::Data.Number)
    if (ix<=size(dT_dt, 1) && iy<=size(dT_dt, 2)) dT_dt[ix,iy] = -((qTx[ix+1,iy]-qTx[ix,iy])/dx + (qTy[ix,iy+1]-qTy[ix,iy])/dy) -
                                                                  (Vx[ix+1,iy+1]>0)*Vx[ix+1,iy+1]*(T[ix+1,iy+1]-T[ix  ,iy+1])/dx -
                                                                  (Vx[ix+2,iy+1]<0)*Vx[ix+2,iy+1]*(T[ix+2,iy+1]-T[ix+1,iy+1])/dx -
                                                                  (Vy[ix+1,iy+1]>0)*Vy[ix+1,iy+1]*(T[ix+1,iy+1]-T[ix+1,iy  ])/dy -
                                                                  (Vy[ix+1,iy+2]<0)*Vy[ix+1,iy+2]*(T[ix+1,iy+2]-T[ix+1,iy+1])/dy   end
    return
end

@parallel function update_T!(T::Data.Array, T_old::Data.Array, dT_dt::Data.Array, dt::Data.Number)
    @inn(T) = @inn(T_old) + @all(dT_dt)*dt
    return
end

@parallel_indices (ix,iy) function no_fluxY_T!(T::Data.Array)
    if (ix==size(T, 1) && iy<=size(T ,2)) T[ix,iy] = T[ix-1,iy] end
    if (ix==1          && iy<=size(T ,2)) T[ix,iy] = T[ix+1,iy] end
    return
end

@parallel_indices (ix,iy) function bc_x!(A::Data.Array)
    A[1  , iy] = A[2    , iy]
    A[end, iy] = A[end-1, iy]
    return
end

@parallel_indices (ix,iy) function bc_y!(A::Data.Array)
    A[ix, 1  ] = A[ix, 2    ]
    A[ix, end] = A[ix, end-1]
    return
end

##################################################
@views function ThermalConvection2D()
    # Physics - dimentionally independent scales
    ly        = 1.0                # domain extend, m
    η0        = 1.0                # viscosity, Pa*s
    DcT       = 1.0                # heat diffusivity, m^2/s
    ΔT        = 1.0                # initial temperature perturbation K
    # Physics - nondim numbers
    Ra        = 1e7                # Raleigh number = ρ0*g*α*ΔT*ly^3/η0/DcT
    Pra       = 1e3                # Prandtl number = η0/ρ0/DcT
    ar        = 3                  # aspect ratio
    # Physics - dimentionally dependent parameters
    lx        = ar*ly              # domain extend, m
    w         = 1e-2*ly            # initial perturbation standard deviation, m
    ρ0gα      = Ra*η0*DcT/ΔT/ly^3  # thermal expansion
    dη_dT     = 1e-10/ΔT           # viscosity's temperature dependence
    # Numerics
    nx, ny    = 96*ar-1, 96-1      # numerical grid resolutions; should be a mulitple of 32-1 for optimal GPU perf
    iterMax   = 5*10^4             # maximal number of pseudo-transient iterations
    nt        = 3000               # total number of timesteps
    nout      = 10                 # frequency of plotting
    nerr      = 100                # frequency of error checking
    ε         = 1e-4               # nonlinear absolute tolerence
    dmp       = 2                  # damping paramter
    st        = 5                  # quiver plotting spatial step
    # Derived numerics
    dx, dy    = lx/(nx-1), ly/(ny-1)          # cell size
    ρ         = 1.0/Pra*η0/DcT                # density
    dt_diff   = 1.0/4.1*min(dx,dy)^2/DcT      # diffusive CFL timestep limiter
    dτ_iter   = 1.0/6.1*min(dx,dy)/sqrt(η0/ρ) # iterative CFL pseudo-timestep limiter
    β         = 6.1*dτ_iter^2/min(dx,dy)^2/ρ  # numerical bulk compressibility
    dampX     = 1.0-dmp/nx                    # damping term for the x-momentum equation
    dampY     = 1.0-dmp/ny                    # damping term for the y-momentum equation
    # Array allocations
    T         = @zeros(nx  ,ny  )
    T        .= Data.Array([ΔT*exp(-(((ix-1)*dx-0.5*lx)/w)^2 -(((iy-1)*dy-0.5*ly)/w)^2) for ix=1:size(T,1), iy=1:size(T,2)])
    T[:,1  ] .=  ΔT/2.0
    T[:,end] .= -ΔT/2.0
    T_old     = @zeros(nx  ,ny  )
    Pt        = @zeros(nx  ,ny  )
    dτPt      = @zeros(nx  ,ny  )
    ∇V        = @zeros(nx  ,ny  )
    Vx        = @zeros(nx+1,ny  )
    Vy        = @zeros(nx  ,ny+1)
    RogT      = @zeros(nx  ,ny  )
    Eta       = @zeros(nx  ,ny  )
    τxx       = @zeros(nx  ,ny  )
    τyy       = @zeros(nx  ,ny  )
    σxy       = @zeros(nx-1,ny-1)
    Rx        = @zeros(nx-1,ny-2)
    Ry        = @zeros(nx-2,ny-1)
    dVxdτ     = @zeros(nx-1,ny-2)
    dVydτ     = @zeros(nx-2,ny-1)
    dτVx      = @zeros(nx-1,ny-2)
    dτVy      = @zeros(nx-2,ny-1)
    qTx       = @zeros(nx-1,ny-2)
    qTy       = @zeros(nx-2,ny-1)
    dT_dt     = @zeros(nx-2,ny-2)
    ErrP      = @zeros(nx  ,ny  )
    ErrV      = @zeros(nx  ,ny+1)
    # Preparation of visualisation
    ENV["GKSwstype"]="nul"; if isdir("viz2D_out")==false mkdir("viz2D_out") end; loadpath = "./viz2D_out/"; anim = Animation(loadpath,String[])
    println("Animation directory: $(anim.dir)")
    X, Y   = -lx/2:dx:lx/2, -ly/2:dy:ly/2
    Xc, Yc = [x for x=X, y=Y], [y for x=X,y=Y]
    Xp, Yp = Xc[1:st:end,1:st:end], Yc[1:st:end,1:st:end]
    # Time loop
    err_evo1=[]; err_evo2=[]
    for it = 1:nt
        @parallel assign!(T_old, T)
        errV, errP = 2*ε, 2*ε; iter=1; niter=0
        while (errV > ε || errP > ε) && iter <= iterMax
            @parallel assign!(ErrV, Vy)
            @parallel assign!(ErrP, Pt)
            @parallel compute_1!(RogT, Eta, ∇V, Pt, τxx, τyy, σxy, T, Vx, Vy, dτPt, ρ0gα, η0, dη_dT, ΔT, dτ_iter, β, dx, dy)
            @parallel compute_2!(Rx, Ry, dVxdτ, dVydτ, Pt, RogT, τxx, τyy, σxy, ρ, dampX, dampY, dτ_iter, dx, dy)
            @parallel update_V!(Vx, Vy, dVxdτ, dVydτ, dτ_iter)
            @parallel (1:size(Vx,1), 1:size(Vx,2)) bc_y!(Vx)
            @parallel (1:size(Vy,1), 1:size(Vy,2)) bc_x!(Vy)
            @parallel compute_error!(ErrV, Vy)
            @parallel compute_error!(ErrP, Pt)
            if mod(iter,nerr) == 0
                errV = maximum(abs.(Array(ErrV)))/(1e-12 + maximum(abs.(Array(Vy))))
                errP = maximum(abs.(Array(ErrP)))/(1e-12 + maximum(abs.(Array(Pt))))
                push!(err_evo1, max(errV, errP)); push!(err_evo2,iter)
                # @printf("Total steps = %d, errV=%1.3e, errP=%1.3e \n", iter, errV, errP)
            end
            iter+=1; niter+=1
        end
        # Thermal solver
        @parallel compute_qT!(qTx, qTy, T, DcT, dx, dy)
        @parallel advect_T!(dT_dt, qTx, qTy, T, Vx, Vy, dx, dy)
        dt_adv = min(dx/maximum(abs.(Array(Vx))), dy/maximum(abs.(Array(Vy))))/2.1
        dt     = min(dt_diff, dt_adv)
        @parallel update_T!(T, T_old, dT_dt, dt)
        @parallel no_fluxY_T!(T)
        @printf("it = %d (iter = %d), errV=%1.3e, errP=%1.3e \n", it, niter, errV, errP)
        # Visualization
        if mod(it,nout)==0
            heatmap(X, Y, Array(T)', aspect_ratio=1, xlims=(X[1], X[end]), ylims=(Y[1], Y[end]), c=:inferno, clims=(-0.1,0.1), title="T° (it = $it of $nt)")
            Vxp = 0.5*(Vx[1:st:end-1,1:st:end  ]+Vx[2:st:end,1:st:end])
            Vyp = 0.5*(Vy[1:st:end  ,1:st:end-1]+Vy[1:st:end,2:st:end])
            Vscale = 1/maximum(sqrt.(Vxp.^2 + Vyp.^2)) * dx*(st-1)
            quiver!(Xp[:], Yp[:], quiver=(Vxp[:]*Vscale, Vyp[:]*Vscale), lw=0.1, c=:blue); frame(anim)
            # display( quiver!(Xp[:], Yp[:], quiver=(Vxp[:]*Vscale, Vyp[:]*Vscale), lw=0.1, c=:blue) )
        end
    end
    gif(anim, "ThermalConvect2D.gif", fps = 15)
    return
end

ThermalConvection2D()


text:
export TabularLearner

"""
    TabularLearner{S, T}

Use a `Dict{S,Vector{T}}` to store action probabilities.
"""
struct TabularLearner{S,T} <: AbstractLearner
    table::Dict{S,Vector{T}}
end

TabularLearner() = TabularLearner{Int,Float32}()
TabularLearner{S}() where {S} = TabularLearner{S,Float32}()
TabularLearner{S,T}() where {S,T} = TabularLearner(Dict{S,Vector{T}}())

function (p::TabularLearner)(env::AbstractEnv)
    s = get_state(env)
    if haskey(p.table, s)
        p.table[s]
    elseif ActionStyle(env) === FULL_ACTION_SET
        mask = get_legal_actions_mask(env)
        prob = mask ./ sum(mask)
        p.table[s] = prob
        prob
    elseif ActionStyle(env) === MINIMAL_ACTION_SET
        n = length(get_actions(env))
        prob = fill(1 / n, n)
        p.table[s] = prob
        prob
    end
end

RLBase.update!(p::TabularLearner, experience::Pair) =
    p.table[first(experience)] = last(experience)


text:
V=Vandermonde([1:5])
@test V[4,5] == 256


text:
module Schrodinger
using Compat
using Compat.LinearAlgebra, Compat.SparseArrays, Compat.Printf
using Base: tail, front, product, promote_eltype
using OrdinaryDiffEq, Optim
using OrdinaryDiffEq.DiffEqBase: AbstractParameterizedFunction

export Operator, Ket, Bra,
    data, dims, isnormalized, dimsmatch, dense, braket, isapproxhermitian,
    isunitary, isapproxunitary, isdensityop, checkdensityop,
    hermitian, symmetric,
    tensor, ptrace, expect, levelprobs, findstate,
    purity, fidelity, fidelity2, entanglement_fidelity, gate_fidelity,
    fock, basis, coherent, thermal, maxentangled, maxmixed, ket, @qb_str,
    qzero, qeye, create, destroy, numberop, projectorop,
    displacementop, squeezeop,
    rand_unitary,
    Liouvillian, SchrodingerEvo, LindbladEvo,
    Propagator, SchrodingerProp, LindbladProp,
    sesolve, mesolve, lsolve, psolve, psteady,
    grape, NormPSU, CoherentSubspaces,
    expim, gaussian, inner, scale, scale!, full,
    eigen

# VERSION-conditional definitions
if VERSION < v"2.0.0-"
    include("basepatch/v1.0.jl")
end
if VERSION < v"0.7.0-"
    include("basepatch/v0.6.jl")
end
if VERSION > v"0.7.0-"
    import Base: BitSet, print_array, sum
    import LinearAlgebra: adjoint, exp, exp!, tr, eigen
    import Arpack: eigs
    import SpecialFunctions: erf
    export eigs, eigvals, trace, normalize, normalize!
    trace(A::AbstractMatrix) = tr(A)
    sum(A::AbstractArray,i::Integer) = Base._sum(A,i)
    parseb2(s::AbstractString) = Base.tryparse_internal(Int,s,firstindex(s),lastindex(s),2,true)
    const luf = lu
end

include("quobj/types.jl")
include("quobj/basicmethods.jl")
include("math/basemath.jl")
include("math/eigen.jl")
include("math/special.jl")
include("math/superoperators.jl")
include("math/norms.jl")
include("math/ptrace.jl")
include("dynamics/liouvillian.jl")
include("dynamics/propagator.jl")
include("dynamics/constructors.jl")
include("dynamics/interface.jl")
include("control/grape.jl")
include("control/normpsu.jl")
include("control/coherentsubspaces.jl")
include("control/amplitudelimiter.jl")
include("tomography/statetomo.jl")
include("tomography/processtomo.jl")
include("misc/utils.jl")
include("misc/indexing.jl")
include("misc/tupletools.jl")
include("misc/inner.jl")
include("misc/kron.jl")
include("misc/sparsevec.jl")
include("misc/checks.jl")
include("misc/hermfact.jl")
include("library/operators.jl")
include("library/states.jl")
include("library/random.jl")
include("library/drivefuns.jl")
include("library/constants.jl")

end


text:
######################################################################
# Signals UTs
# -----
# Licensed under Apache License 2.0
module TestSignals
using Test
using Pia.Signals

@testset "Signals" begin
    @testset "basic" begin
        let signal = Signal()
            @test !isset(signal)
            @test set(signal) === nothing
            @test isset(signal)
            @test clear(signal) === nothing
            @test !isset(signal)
        end
    end

    @testset "sync" begin
        let signal = Signal()
            success_wait = false
            t0 = time()
            @sync begin
                @async begin; wait(signal); success_wait = true; end
                @async begin; sleep(0.2); set(signal); end
            end
            @test success_wait
            @test time()-t0 > 0.2
        end
    end
end

end # module TestSignals


text:
#This needs to be reconsidered
if !isdefined(:self)
    const self = init([""])
    replay(self, "wh:\e/\e") #ugly hack but it works
end

function attach(b::Buffer)
    term = Base.REPL.Terminals.TTYTerminal(get(ENV, "TERM", "dumb"), STDIN, STDOUT, STDERR)
    Base.REPL.raw!(term, true)
    b.state[:running] = "true"
    move_sys_cursor(1,1)
    render(b)
    move_sys_cursor(1,1)
    onattach()
    while b.state[:running]=="true"
        Base.invokelatest(run, b)
    end
    finalize(b)
    b
end
function finalize(b::Buffer)
    clear_screen()
    move_sys_cursor(1,1)
    term = Base.REPL.Terminals.TTYTerminal(get(ENV, "TERM", "dumb"), STDIN, STDOUT, STDERR)
    Base.REPL.raw!(term, false)
end

#It would be nice if we had a macro so that all functions that take ::Buffer as argument
#were defined without buffer as argument using the global self variable

function open(st::String)
    self.state[:filename] = st
    try
        settext(self, readlines(st))
    catch
        settext(self, [""])
    end
    #Change later
    self.state[:top] = "1"
    self.state[:bottom] = "20"
    onopen()
    if self.state[:running] == "false"
        attach(self)
    end
    self
end

function open(b::Buffer, st)
    b.state[:filename] = st
    settext(b, readlines(st))
end

function save(b::Buffer, st::String)
    self.state[:filename] = st
    write(st, join(b.text, "\n"))
end
function save(b::Buffer)
    if in(:filename, keys(b.state)) && b.state[:filename]!=""
        save(b, b.state[:filename])
    else
        "No file name"
    end
end
save(st::String) = save(self, st)
save() = save(self)

function quit()
    quit(self)
end

#Just for vi muscle memory
struct Save
end
Base.show(io::IO, s::Save) = save()
(s::Save)() = save()

struct Quit
end
Base.show(io::IO, q::Quit) = quit()
(q::Quit)() = quit()

w = Save();
q = Quit();
wq = (w,q)
1


text:
using Waterfall

include(joinpath(WATERFALL_DIR,"src","includes.jl"))
include(joinpath(WATERFALL_DIR,"bin","io.jl"))

# RETURNS HEIGHT.
function _cumulative_spread(cascade::Cascade{Data}; kwargs...)
    data = collect_data(cascade)
    vstart, vstop = cumulative_v!(cascade; kwargs...)  # DOES it update cascade????

    vrange = hcat(vstart,vstop)
    vmax = Statistics.maximum(vrange; dims=2)
    vmin = Statistics.minimum(vrange; dims=2)

    sgn = [vmax[ii] in vstart[ii,:] ? -1 : 1 for ii in 1:length(vmax)]

    return sgn .* (vmax.-vmin)
end

function _cumulative_spread(df; nperm, kwargs...)
    ROW = size(df,1)-2

    perms = random_permutation(1:ROW, min(factorial(ROW), nperm))
    !(1:ROW in perms) && append!(deleteat!(perms,nperm), [collect(1:ROW)])

    result = zeros(ROW+2,nperm)

    for ii in 1:nperm
        cascade = define_from(Cascade{Data}, df; permutation=perms[ii], kwargs...)
        #     ncor=ncor,
        #     nsample=nsample,
        #     kwargs...,
        # )

        height = _cumulative_spread(cascade)
        result[collect_permutation(perms[ii]),[ii]] .= height
    end

    return result
end

# function cumulative_spread!(cascade::Cascade{Data})
#     data = collect_data(cascade)
#     vstart, vstop = cumulative_v!(cascade; kwargs...)  # DOES it update cascade????

#     vrange = hcat(vstart,vstop)
#     vmax = Statistics.maximum(vrange; dims=2)
#     vmin = Statistics.minimum(vrange; dims=2)

#     sgn = [vmax[ii] in vstart[ii,:] ? -1 : 1 for ii in 1:length(vmax)]
#     height = sgn .* (vmax.-vmin)

#     # set_value!(data, height)
#     # return cascade
# end

# cascades = Dict()

function cumulative_spread(df; nperm=100, kwargs...)
    cascade = define_from(Cascade{Data}, df; kwargs...)

    v = _cumulative_spread(df; nperm=nperm, kwargs...)
    data = collect_data(cascade)
    set_value!(data,v)

    return cascade
end

nsample=10
ncor=1000
nperm=3
cspread = cumulative_spread(df; nperm=nperm, nsample=nsample, ncor=ncor, kwargs...)

# IF max comes from start, it's going down. Otherwise it's going up.

# sgn = sign.(vstop.-vstart)


text:
using DrWatson
@quickactivate
using ArgParse
using BSON
using Flux
using PyCall
using GenerativeAD
using StatsBase: fit!, predict, sample
using OrderedCollections

s = ArgParseSettings()
@add_arg_table! s begin
	"max_seed"
		default = 1
		arg_type = Int
		help = "maximum number of seeds to run through"
	"dataset"
		default = "iris"
		arg_type = String
		help = "dataset"
	"sampling"
		default = "random"
		arg_type = String
		help = "sampling of hyperparameters"
	"contamination"
		arg_type = Float64
		help = "contamination rate of training data"
		default = 0.0
end
parsed_args = parse_args(ARGS, s)
@unpack dataset, max_seed, sampling, contamination = parsed_args

modelname = "sptn"

function sample_params()
	parameter_rng = (
		firstdense = [true, false],
		batchsize = 2 .^ (5:7),
		ncomp = 2 .^ (1:4),
		nlayers = 1:3,
		activation = [identity],
		unitary = [:butterfly],
		sharing = [:dense, :all, :none],
		init_seed = 1:Int(1e8),
	)

	return (;zip(keys(parameter_rng), map(x->sample(x, 1)[1], parameter_rng))...)
end

function create_space()
	pyReal = pyimport("skopt.space")["Real"]
	pyInt = pyimport("skopt.space")["Integer"]
	pyCat = pyimport("skopt.space")["Categorical"]

	(;
		firstdense  = pyCat(categories=[true, false], 				name="firstdense"),
		batchsize 	= pyInt(5, 7, 									name="log2_batchsize"),
		ncomp 		= pyInt(1, 4, 									name="log2_ncomp"),
		nlayers		= pyInt(1, 3, 									name="nlayers"),
		activation 	= pyCat(categories=["identity"], 				name="fun_activation"),
		unitary 	= pyCat(categories=["butterfly"], 				name="sym_unitary"),
		sharing 	= pyCat(categories=["dense", "all", "none"], 	name="sym_sharing")
	)
end

function fit(data, parameters)
	model = GenerativeAD.Models.SPTN(;idim=size(data[1][1],1), parameters...)

	try
		global info, fit_t, _, _, _ = @timed fit!(model, data; max_train_time=82800/max_seed,
			patience=20, check_interval=10, parameters...)
	catch e
		# return an empty array if fit fails so nothing is computed
		@info "Failed training due to \n$e"
		return (fit_t = NaN, history=nothing, npars=nothing, model=nothing), []
	end

	# construct return information - put e.g. the model structure here for generative models
	training_info = (
		fit_t = fit_t,
		history = info.history,
		npars = info.npars,
		model = info.model
		)

	# now return the different scoring functions
	training_info, [(x -> predict(info.model, x), parameters)]
end

try_counter = 0
max_tries = 10*max_seed
cont_string = (contamination == 0.0) ? "" : "_contamination-$contamination"
sampling_string = sampling == "bayes" ? "_bayes" : ""
prefix = "experiments$(sampling_string)/tabular$(cont_string)"
dataset_folder = datadir("$(prefix)/$(modelname)/$(dataset)")
while try_counter < max_tries
	if sampling == "bayes"
		parameters = GenerativeAD.bayes_params(
								create_space(),
								dataset_folder,
								sample_params; add_model_seed=true)
	else
		parameters = sample_params()
	end

	for seed in 1:max_seed
		savepath = joinpath(dataset_folder, "seed=$(seed)")
		mkpath(savepath)

		# get data
		data = GenerativeAD.load_data(dataset, seed=seed, contamination=contamination)
		edited_parameters = sampling == "bayes" ? parameters : GenerativeAD.edit_params(data, parameters)

		# check if a combination of parameters and seed alread exists
		if GenerativeAD.check_params(savepath, edited_parameters)
			@info "Started training $(modelname)$(edited_parameters) on $(dataset):$(seed)"
			@info "Train/valdiation/test splits: $(size(data[1][1], 2)) | $(size(data[2][1], 2)) | $(size(data[2][1], 2))"
			@info "Number of features: $(size(data[1][1], 1))"

			training_info, results = fit(data, edited_parameters)

			if training_info.model !== nothing
				tagsave(joinpath(savepath, savename("model", edited_parameters, "bson", digits=5)),
						Dict("model"=>training_info.model,
							"fit_t"=>training_info.fit_t,
							"history"=>training_info.history,
							"parameters"=>edited_parameters
							), safe = true)
				training_info = merge(training_info, (model = nothing,))
			end
			# here define what additional info should be saved together with parameters, scores, labels and predict times
			save_entries = merge(training_info, (modelname = modelname, seed = seed, dataset = dataset, contamination = contamination))

			# now loop over all anomaly score funs
			all_scores = [GenerativeAD.experiment(result..., data, savepath; save_entries...) for result in results]
			if sampling == "bayes" && length(all_scores) > 0
				@info("Updating cache with $(length(all_scores)) results.")
				GenerativeAD.update_bayes_cache(dataset_folder,
						all_scores; ignore=Set([:init_seed]))
			end
			global try_counter = max_tries + 1
		else
			@info "Model already present, trying new hyperparameters..."
			global try_counter += 1
		end
	end
end
(try_counter == max_tries) ? (@info "Reached $(max_tries) tries, giving up.") : nothing


text:
using ITensors
using Printf
using Random

Random.seed!(1234)

let
  N = 100

  # Create N spin-one degrees of freedom
  sites = siteinds("S=1", N)
  # Alternatively can make spin-half sites instead
  #sites = siteinds("S=1/2",N)

  # Input operator terms which define a Hamiltonian
  ampo = AutoMPO()
  for j in 1:(N - 1)
    ampo += "Sz", j, "Sz", j + 1
    ampo += 0.5, "S+", j, "S-", j + 1
    ampo += 0.5, "S-", j, "S+", j + 1
  end
  # Convert these terms to an MPO tensor network
  H = MPO(ampo, sites)

  # Create an initial random matrix product state
  psi0 = randomMPS(sites, 10)

  # Plan to do 5 DMRG sweeps:
  sweeps = Sweeps(5)
  # Set maximum MPS bond dimensions for each sweep
  setmaxdim!(sweeps, 10, 20, 100, 100, 200)
  # Set maximum truncation error allowed when adapting bond dimensions
  setcutoff!(sweeps, 1E-11)
  @show sweeps

  # Run the DMRG algorithm, returning energy and optimized MPS
  energy, psi = dmrg(H, psi0, sweeps)
  @printf("Final energy = %.12f\n", energy)
end


text:
using Impute
using Tables
using Test
using AxisArrays
using DataFrames
using Dates
using RDatasets
using Statistics
using StatsBase
using Random

import Impute:
    Drop,
    DropObs,
    DropVars,
    Interpolate,
    Fill,
    LOCF,
    NOCB,
    SRS,
    Context,
    WeightedContext,
    ImputeError

@testset "Impute" begin
    # Defining our missing datasets
    a = allowmissing(1.0:1.0:20.0)
    a[[2, 3, 7]] .= missing
    mask = map(!ismissing, a)
    ctx = Context(; limit=0.2)

    # We call collect to not have a wrapper type that references the same data.
    m = collect(reshape(a, 5, 4))

    aa = AxisArray(
        deepcopy(m),
        Axis{:time}(DateTime(2017, 6, 5, 5):Hour(1):DateTime(2017, 6, 5, 9)),
        Axis{:id}(1:4)
    )

    table = DataFrame(
        :sin => allowmissing(sin.(1.0:1.0:20.0)),
        :cos => allowmissing(sin.(1.0:1.0:20.0)),
    )

    table.sin[[2, 3, 7, 12, 19]] .= missing

    @testset "Equality" begin
        @testset "$T" for T in (DropObs, DropVars, Interpolate, Fill, LOCF, NOCB, SRS)
            @test T() == T()
        end
    end

    @testset "Drop" begin
        @testset "DropObs" begin
            @testset "Vector" begin
                result = impute(a, DropObs(; context=ctx))
                expected = deleteat!(deepcopy(a), [2, 3, 7])

                @test result == expected
                @test result == Impute.dropobs(a; context=ctx)

                a2 = deepcopy(a)
                Impute.dropobs!(a2; context=ctx)
                @test a2 == expected
            end

            @testset "Matrix" begin
                # Because we're removing 2 of our 5 rows we need to change the limit.
                ctx = Context(; limit=0.4)
                result = impute(m, DropObs(; context=ctx))
                expected = m[[1, 4, 5], :]

                @test isequal(result, expected)
                @test isequal(result, Impute.dropobs(m; context=ctx))
                @test isequal(collect(result'), Impute.dropobs(collect(m'); dims=2, context=ctx))

                m_ = Impute.dropobs!(m; context=ctx)
                # The mutating test is broken because we need to making a copy of
                # the original matrix
                @test_broken isequal(m, expected)
                @test isequal(m_, expected)
            end

            @testset "Tables" begin
                ctx = Context(; limit=0.4)
                @testset "DataFrame" begin
                    df = deepcopy(table)
                    result = impute(df, DropObs(; context=ctx))
                    expected = dropmissing(df)

                    @test isequal(result, expected)
                    @test isequal(result, Impute.dropobs(df; context=ctx))

                    df_ = Impute.dropobs!(df; context=ctx)
                    # The mutating test is broken because we need to making a copy of
                    # the original table
                    @test_broken isequal(df, expected)
                    @test isequal(df_, expected)
                end

                @testset "Column Table" begin
                    coltab = Tables.columntable(table)

                    result = impute(coltab, DropObs(; context=ctx))
                    expected = Tables.columntable(dropmissing(table))

                    @test isequal(result, expected)
                    @test isequal(result, Impute.dropobs(coltab; context=ctx))

                    coltab_ = Impute.dropobs!(coltab; context=ctx)
                    # The mutating test is broken because we need to making a copy of
                    # the original table
                    @test_broken isequal(coltab, expected)
                    @test isequal(coltab_, expected)
                end

                @testset "Row Table" begin
                    rowtab = Tables.rowtable(table)
                    result = impute(rowtab, DropObs(; context=ctx))
                    expected = Tables.rowtable(dropmissing(table))

                    @test isequal(result, expected)
                    @test isequal(result, Impute.dropobs(rowtab; context=ctx))

                    rowtab_ = Impute.dropobs!(rowtab; context=ctx)
                    # The mutating test is broken because we need to making a copy of
                    # the original table
                    # @test_broken isequal(rowtab, expected)
                    @test isequal(rowtab_, expected)
                end
            end

            @testset "AxisArray" begin
                # Because we're removing 2 of our 5 rows we need to change the limit.
                ctx = Context(; limit=0.4)
                result = impute(aa, DropObs(; context=ctx))
                expected = aa[[1, 4, 5], :]

                @test isequal(result, expected)
                @test isequal(result, Impute.dropobs(aa; context=ctx))

                aa_ = Impute.dropobs!(aa; context=ctx)
                # The mutating test is broken because we need to making a copy of
                # the original matrix
                @test_broken isequal(aa, expected)
                @test isequal(aa_, expected)
            end
        end

        @testset "DropVars" begin
            @testset "Vector" begin
                @test_throws MethodError Impute.dropvars(a)
            end

            @testset "Matrix" begin
                ctx = Context(; limit=0.5)
                result = impute(m, DropVars(; context=ctx))
                expected = copy(m)[:, 3:4]

                @test isequal(result, expected)
                @test isequal(result, Impute.dropvars(m; context=ctx))
                @test isequal(collect(result'), Impute.dropvars(collect(m'); dims=2, context=ctx))

                m_ = Impute.dropvars!(m; context=ctx)
                # The mutating test is broken because we need to making a copy of
                # the original matrix
                @test_broken isequal(m, expected)
                @test isequal(m_, expected)
            end

            @testset "Tables" begin
                @testset "DataFrame" begin
                    df = deepcopy(table)
                    result = impute(df, DropVars(; context=ctx))
                    expected = select(df, :cos)

                    @test isequal(result, expected)
                    @test isequal(result, Impute.dropvars(df; context=ctx))

                    Impute.dropvars!(df; context=ctx)
                    # The mutating test is broken because we need to making a copy of
                    # the original table
                    @test_broken isequal(df, expected)
                end

                @testset "Column Table" begin
                    coltab = Tables.columntable(table)

                    result = impute(coltab, DropVars(; context=ctx))
                    expected = Tables.columntable(Tables.select(coltab, :cos))

                    @test isequal(result, expected)
                    @test isequal(result, Impute.dropvars(coltab; context=ctx))

                    Impute.dropvars!(coltab; context=ctx)
                    # The mutating test is broken because we need to making a copy of
                    # the original table
                    @test_broken isequal(coltab, expected)
                end

                @testset "Row Table" begin
                    rowtab = Tables.rowtable(table)
                    result = impute(rowtab, DropVars(; context=ctx))
                    expected = Tables.rowtable(Tables.select(rowtab, :cos))

                    @test isequal(result, expected)
                    @test isequal(result, Impute.dropvars(rowtab; context=ctx))

                    Impute.dropvars!(rowtab; context=ctx)
                    # The mutating test is broken because we need to making a copy of
                    # the original table
                    @test_broken isequal(rowtab, expected)
                end
            end
            @testset "AxisArray" begin
                ctx = Context(; limit=0.5)
                result = impute(aa, DropVars(; context=ctx))
                expected = copy(aa)[:, 3:4]

                @test isequal(result, expected)
                @test isequal(result, Impute.dropvars(aa; context=ctx))

                aa_ = Impute.dropvars!(aa; context=ctx)
                # The mutating test is broken because we need to making a copy of
                # the original matrix
                @test_broken isequal(aa, expected)
                @test isequal(aa_, expected)
            end
        end
    end

    @testset "Interpolate" begin
        result = impute(a, Interpolate(; context=ctx))
        @test result == collect(1.0:1.0:20)
        @test result == interp(a; context=ctx)

        # Test in-place method
        a2 = copy(a)
        Impute.interp!(a2; context=ctx)
        @test a2 == result

        # Test interpolation between identical points
        b = ones(Union{Float64, Missing}, 20)
        b[[2, 3, 7]] .= missing
        @test interp(b; context=ctx) == ones(Union{Float64, Missing}, 20)

        # Test interpolation at endpoints
        b = ones(Union{Float64, Missing}, 20)
        b[[1, 3, 20]] .= missing
        result = interp(b; context=ctx)
        @test ismissing(result[1])
        @test ismissing(result[20])
    end

    @testset "Fill" begin
        @testset "Value" begin
            fill_val = -1.0
            result = impute(a, Fill(; value=fill_val, context=ctx))
            expected = copy(a)
            expected[[2, 3, 7]] .= fill_val

            @test result == expected
            @test result == Impute.fill(a; value=fill_val, context=ctx)
        end

        @testset "Mean" begin
            result = impute(a, Fill(; value=mean, context=ctx))
            expected = copy(a)
            expected[[2, 3, 7]] .= mean(a[mask])

            @test result == expected
            @test result == Impute.fill(a; value=mean, context=ctx)

            a2 = copy(a)
            Impute.fill!(a2; context=ctx)
            @test a2 == result
        end

        @testset "Matrix" begin
            ctx = Context(; limit=1.0)
            expected = Matrix(Impute.dropobs(dataset("boot", "neuro"); context=ctx))
            data = Matrix(dataset("boot", "neuro"))

            result = impute(data, Fill(; value=0.0, context=ctx))
            @test size(result) == size(data)
            @test result == Impute.fill(data; value=0.0, context=ctx)

            data2 = copy(data)
            Impute.fill!(data2; value=0.0, context=ctx)
            @test data2 == result
        end
    end

    @testset "LOCF" begin
        result = impute(a, LOCF(; context=ctx))
        expected = copy(a)
        expected[2] = 1.0
        expected[3] = 1.0
        expected[7] = 6.0

        @test result == expected
        @test result == Impute.locf(a; context=ctx)

        a2 = copy(a)
        Impute.locf!(a2; context=ctx)
        @test a2 == result
    end

    @testset "NOCB" begin
        result = impute(a, NOCB(; context=ctx))
        expected = copy(a)
        expected[2] = 4.0
        expected[3] = 4.0
        expected[7] = 8.0

        @test result == expected
        @test result == Impute.nocb(a; context=ctx)

        a2 = copy(a)
        Impute.nocb!(a2; context=ctx)
        @test a2 == result
    end

    @testset "SRS" begin
        result = impute(a, SRS(; rng=MersenneTwister(137), context=ctx))
        expected = copy(a)
        expected[2] = 9.0
        expected[3] = 16.0
        expected[7] = 17.0

        @test result == expected

        @test result == Impute.srs(a; rng=MersenneTwister(137), context=ctx)

        a2 = copy(a)

        Impute.srs!(a2; rng=MersenneTwister(137), context=ctx)
        @test a2 == result
    end

    @testset "Not enough data" begin
        ctx = Context(; limit=0.1)
        @test_throws ImputeError impute(a, DropObs(; context=ctx))
        @test_throws ImputeError Impute.dropobs(a; context=ctx)
    end

    @testset "Chain" begin
        orig = dataset("boot", "neuro")
        ctx = Context(; limit=1.0)

        @testset "DataFrame" begin
            result = Impute.interp(orig; context=ctx) |> Impute.locf!() |> Impute.nocb!()

            @test size(result) == size(orig)
            # Confirm that we don't have any more missing values
            @test all(!ismissing, Matrix(result))

            # We can also use the Chain type with explicit Imputor types
            result2 = impute(
                orig,
                Impute.Chain(
                    Impute.Interpolate(; context=ctx),
                    Impute.LOCF(),
                    Impute.NOCB()
                ),
            )

            # Test creating a Chain via Imputor composition
            imp = Impute.Interpolate(; context=ctx) ∘ Impute.LOCF() ∘ Impute.NOCB()
            result3 = impute(orig, imp)
            @test result == result2
            @test result == result3

            @testset "GroupedDataFrame" begin
                hod = repeat(1:24, 12 * 10)
                obj = repeat(1:12, 24 * 10)
                n = length(hod)

                df = DataFrame(
                    :hod => hod,
                    :obj => obj,
                    :val => allowmissing(
                        [sin(x) * cos(y) for (x, y) in zip(hod, obj)]
                    ),
                )

                df.val[rand(1:n, 20)] .= missing
                gdf1 = groupby(deepcopy(df), [:hod, :obj])
                gdf2 = groupby(df, [:hod, :obj])

                f1 = Impute.interp(; context=ctx) ∘ Impute.locf!() ∘ Impute.nocb!()
                f2 = Impute.interp!(; context=ctx) ∘ Impute.locf!() ∘ Impute.nocb!()

                result = mapreduce(f1, vcat, gdf1)
                @test df != result
                @test size(result) == (24 * 12 * 10, 3)
                @test all(!ismissing, Tables.matrix(result))

                # Test that we can also mutate the dataframe directly
                map(f2, gdf2)
                @test result == sort(df, (:hod, :obj))
            end
        end

        @testset "Column Table" begin
            result = Tables.columntable(orig) |>
                Impute.interp!(; context=ctx) |>
                Impute.locf!() |>
                Impute.nocb!() |>
                Tables.matrix

            @test size(result) == size(orig)
            # Confirm that we don't have any more missing values
            @test all(!ismissing, result)
        end

        @testset "Row Table" begin
            result = Tables.rowtable(orig) |>
                Impute.interp!(; context=ctx) |>
                Impute.locf!() |>
                Impute.nocb!() |>
                Tables.matrix

            @test size(result) == size(orig)
            # Confirm that we don't have any more missing values
            @test all(!ismissing, result)
        end

        @testset "Matrix" begin
            data = Matrix(orig)
            result = Impute.interp(data; context=ctx) |> Impute.locf!() |> Impute.nocb!()

            @test size(result) == size(data)
            # Confirm that we don't have any more missing values
            @test all(!ismissing, result)
        end

        @testset "AxisArray" begin
            data = AxisArray(
                Matrix(orig),
                Axis{:row}(1:size(orig, 1)),
                Axis{:V}(names(orig)),
            )
            result = Impute.interp(data; context=ctx) |> Impute.locf!() |> Impute.nocb!()

            @test size(result) == size(data)
            # Confirm that we don't have any more missing values
            @test all(!ismissing, result)
        end
    end

    @testset "Alternate missing functions" begin
        ctx1 = Context(; limit=1.0)
        ctx2 = Context(; limit=1.0, is_missing=isnan)
        data1 = dataset("boot", "neuro")                    # Missing values with `missing`
        data2 = Impute.fill(data1; value=NaN, context=ctx1)  # Missing values with `NaN`

        @test Impute.dropobs(data1; context=ctx1) == dropmissing(data1)

        result1 = Impute.interp(data1; context=ctx1) |> Impute.dropobs()
        result2 = Impute.interp(data2; context=ctx2) |> Impute.dropobs(; context=ctx2)

        @test result1 == result2
    end

    @testset "Contexts" begin
        @testset "Base" begin
            ctx = Context(; limit=0.1)
            @test_throws ImputeError Impute.dropobs(a; context=ctx)
            @test_throws ImputeError impute(a, DropObs(; context=ctx))
        end

        @testset "Weighted" begin
            # If we use an exponentially weighted context then we won't pass the limit
            # because missing earlier observations is less important than later ones.
            ctx = WeightedContext(eweights(20, 0.3); limit=0.1)
            @test isa(ctx, WeightedContext)
            result = impute(a, DropObs(; context=ctx))
            expected = copy(a)
            deleteat!(expected, [2, 3, 7])
            @test result == expected

            # If we reverse the weights such that earlier observations are more important
            # then our previous limit of 0.2 won't be enough to succeed.
            ctx = WeightedContext(reverse!(eweights(20, 0.3)); limit=0.2)
            @test_throws ImputeError impute(a, DropObs(; context=ctx))
        end
    end

    @testset "Utils" begin
        M = [1.0 2.0 3.0 4.0 5.0; 1.1 2.2 3.3 4.4 5.5]

        @testset "obswise" begin
            @test map(sum, Impute.obswise(M; dims=2)) == [2.1, 4.2, 6.3, 8.4, 10.5]
            @test map(sum, Impute.obswise(M; dims=1)) == [15, 16.5]
        end

        @testset "varwise" begin
            @test map(sum, Impute.varwise(M; dims=2)) == [15, 16.5]
            @test map(sum, Impute.varwise(M; dims=1)) == [2.1, 4.2, 6.3, 8.4, 10.5]
        end

        @testset "filterobs" begin
            @test Impute.filterobs(x -> sum(x) > 5.0, M; dims=2) == M[:, 3:5]
            @test Impute.filterobs(x -> sum(x) > 15.0, M; dims=1) == M[[false, true], :]
        end

        @testset "filtervars" begin
            @test Impute.filtervars(x -> sum(x) > 15.0, M; dims=2) == M[[false, true], :]
            @test Impute.filtervars(x -> sum(x) > 5.0, M; dims=1) == M[:, 3:5]
        end
    end

    include("deprecated.jl")
end