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

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

# ╔═╡ 0b9abd74-d199-4720-803e-eb7861b86572
begin
	using PlutoUI # user-interface do Pluto.jl
	using Plots   # Julia package para gráficos
end

# ╔═╡ c4d275c8-36d5-454f-bf1f-ddbc06beeae0
html"<button onclick='present()'>present</button>"

# ╔═╡ d2a788ef-5292-4229-a1d1-3fd15db67c51
md"""
# Máquina síncrona trifásica

## Motor síncrono de pólos salientes (Ex.8)
Máquinas síncronas trifásicas, exercício 8:
"""

# ╔═╡ 17bc7f80-c13c-11eb-227f-b125d84c8b40
md"""
**Uma máquina síncrona 3~ de pólos salientes, 50MVA, 11kV, 60Hz, enrolamentos do
estator em Y, apresenta as reatâncias: $$X_d=0.8\mathrm pu$$ e $$X_q=0.4\mathrm pu$$.
Como motor síncrono é colocado à plena carga com fator de potência 0,8 indutivo.
As perdas mecânicas representam são 0,15pu.
Despreze as perdas na resistência do induzido.**
"""

# ╔═╡ 20ed504e-08d1-45b9-8494-c42170182898
(Sₙ, Uₙ, f, Xd, Xq, cosφₙ, pᵣₒₜ)=(50e6, 11e3, 60, 0.8, 0.4, 0.8, 0.15)

# ╔═╡ 25f9aa0c-efa0-4c8a-bbfb-c5648bf2f8a2
md"""
## a) Determine $$X_d$$ e $$X_q$$ em Ω;
"""

# ╔═╡ 0545e797-9d40-48c4-ab96-195959331560
md"""
A utilização de *valores por unidade*, $$\mathrm {pu}$$,  apresenta diversas vantagens:
 - permite uma melhor comparação relativa entre máquinas de diferentes potências;
 - torna as grandezas adimensionais, facilitando a observação das mesmas face aos valores nominais de funcionamento;
 - simplifica a utilização do factor $$\sqrt3$$ em sistemas trifásicos.

Definindo a potência de base, $$S_b$$, e a tensão de base, $$U_b$$:

$$S_b=S_n\quad;\quad U_b=U_n$$

como: $$\quad S_b=U_bI_b\quad \Leftrightarrow \quad S_b=\frac{U_b^2}{Z_b}\quad \Rightarrow\quad Z_b=\frac{U_b^2}{S_b}$$

sendo $$Z_b$$ a impedância de base. Assim:

$$\begin{cases}X_d(\Omega) = X_d(\mathrm{pu}).Z_b\\X_q(\Omega) = X_q(\mathrm{pu}).Z_b \end{cases}$$
"""

# ╔═╡ 342aacbe-df8e-42b9-a7a2-8538476f2a80
begin
	Sb=Sₙ
	Ub=Uₙ
	Zb=Ub^2/Sb
	Xd_Ω=Xd*Zb
	Xq_Ω=Xq*Zb
	Xd_Ω, Xq_Ω
end

# ╔═╡ 65dd0a07-ff99-4887-8a86-142248705131
md"""
## b) Determine a fem em pu;
"""

# ╔═╡ 8b677658-96a8-40cb-b4cf-1638703dda22
md"""
A força contra-electromotriz (fcem) de vazio, $$E'_0$$, do motor síncrono de pólos salientes vem dada pela equação vectorial:

$$\overline{E'}_0=\overline{U}-(R+jX_q)\overline{I}-j(X_d-X_q)\overline{I}_d$$

com: $$\quad\overline{E'}=\overline{U}-(R+jX_q)\overline{I}$$

A determinação do vector fcem efectiva, $$\overline{E'}$$, (cálculo intermédio de $$\overline{E'}_0$$) permite definir a posição espacial dos eixos directo (linha dos pólos) e de quadratura (posicão das fcem), uma vez que se obtém o ângulo de carga, $$\delta$$.
"""

# ╔═╡ 3ec74057-fcbb-4d79-8aca-719289c2299e
md"""
O cálculo de $$\overline I_d$$ é obtido a partir da relação trigonométrica com o vector da corrente, $$\overline I$$, observado o diagrama vectorial de tensões:

Assim, no caso concreto:

$$\overline I_d=I\sin(|\varphi|-|\delta|)\angle (\delta-90°)$$
"""

# ╔═╡ 49053499-f759-4043-a9b8-48f42e45589a
md"""
### Diagrama vectorial de tensões do motor síncrono de pólos salientes
"""

# ╔═╡ 19c628e8-60c9-46d0-9ab8-78e70b8bfa6f
md"""
## c) $$P_d^{fcem}(pu)$$; $$P_d^{rel}(pu)$$

**Determine a potências desenvolvidas (em pu) devido à fem de excitação e devido ao
efeito de relutância do rotor;**
"""

# ╔═╡ 2cd26842-6c40-4dc0-9979-da4685630aa1
md"""
As parcelas da potência desenvolvida em *valores por unidade* são determinadas pelas expressões:

$$P_d^{fcem}(pu)=\frac{UE'_0}{X_d}\sin \delta$$
$$P_d^{rel}(pu)=\frac{U^2(X_d-Xq)}{2X_dX_q}\sin(2\delta)$$

O que resulta:
"""

# ╔═╡ 6bc18d01-7285-4b7b-9769-3a7d52baae75
md"""
## d) Limite de estabilidade
**Se a corrente de excitação for reduzida a zero, a máquina continua em sincronismo?
Justifique;**
"""

# ╔═╡ 60f80e79-eeb8-4b60-801f-98caa28b4dfd
md"""
Por conseguinte, como: $$|P_d^{rel}(max)|< |P_d|$$, conclui-se que o motor perderia o sincronismo nesta situação $$(\space I_{exc}=0\space\mathrm {pu})$$, passando a um funcionamento instável.
"""

# ╔═╡ dd7d16e4-7b01-4aa0-a1ba-ecc7881900fb
md"""
## e) Funcionamento em vazio, sem $$I_{exc}$$

**e) Se a carga ao veio for retirada e a corrente de excitação reduzida a zero, determine o valor da corrente do estator (em pu) e o fator de potência. Desenhe o diagrama vectorial da máquina para esta situação.**
"""

# ╔═╡ 61609aa9-9feb-4a63-b4e9-2fd9a88f8106
md"""
Sem carga ao veio, $$\quad P_u=0\mathrm W\quad \Rightarrow \quad P_d=p_{rot}=0.15\mathrm{pu}$$.

Por outro lado, $$\quad I_{exc}=0\mathrm A\quad \Rightarrow \quad E'_0\simeq 0\mathrm V \quad \Rightarrow \quad P_d^{fcem}\simeq 0\mathrm W$$.

Por conseguinte, $$\quad P_d^{rel}=p_{rot}=0.15\mathrm{pu}\quad$$ com $$\quad P_d^{rel}$$:

$$P_d^{rel}(pu)=\frac{U^2(X_d-X_q)}{2X_dX_q}\sin(2\delta_0)$$
"""

# ╔═╡ 28da7f3c-97fd-4a80-ad21-eeb201dcc881
md"""
Do diagrama vectorial de tensões deste motor síncrono, retiram-se as seguintes relações para as componentes da corrente, $$I$$, nos eixos directo e de quadratura, em função do ângulo de carga, δ:

$$\begin{cases}I_q=\frac{U}{X_q}\sin(|\delta|) \\I_d=\frac{U}{X_d}\cos(\delta)-\frac{E'_0}{X_d}\end{cases}$$

Vectorialmente as componentes da corrente nos eixos directo e de quadratura ficam representadas por:

$$\begin{cases}\overline I_q=I_q\angle \delta\\ \overline I_d= I_d\angle (\delta-90°)\end{cases}$$

Assim, o vector de corrente, $$\overline I$$ é obtido por:

$$\overline I=\overline I_d+\overline I_q$$
"""

# ╔═╡ 311eecf2-4bd6-44bc-8c67-a680f4fd5d33
md"""
### Diagrama vectorial de tensões 💻
"""

# ╔═╡ b47b956c-8880-4c22-aeea-d9a55c518b6a
md"""
Para se perceber o efeito das reduções da carga ao veio e da corrente de excitação, criou-se um segundo diagrama vectorial de tensões/correntes, mas dependente da posição de 2 cursores (*sliders*) associados à variação de cada um dos parâmetros $$(\delta$$ e $$I_{exc})$$, permitindo observar os seus efeitos sucessivos, no desenho do diagrama vectorial:
"""

# ╔═╡ 78a2ef93-5ed1-44f8-8aa9-7e7d8d80a2df
md"""
Repare-se para qualquer valor do ângulo de carga, $$\delta$$, quando a corrente de excitação se torna nula, a fcem de vazio, $$\overline {E'}_0$$, torna-se também nula e o diagrama vectorial de tensões pode ser representado apenas pelo triângulo rectângulo formado pelos vectores: $$\quad\overline U$$, $$\space\space-jX_q\overline I_q\quad$$ e $$\quad-jX_d\overline I_d$$.

Ou seja: $$\quad\overline {E'}_0=\overline U -jX_q\overline I_q -jX_d\overline I_d\quad$$ com $$\quad\overline {E'}_0=0 \space\mathrm{pu}$$.
"""

# ╔═╡ c5cc14a5-73c6-4f10-bc3e-bd7b68eddafa
md"""
!!! nota
	Os resultados da **alínea e)** são corretamente apresentados apenas quandos os cursores se encontrem nas posições:

	$$\delta=\delta_0 \quad \mathrm e \quad I_{exc}=0 \space\mathrm {pu}$$
"""

# ╔═╡ d58c2390-6aaa-4e73-b360-9f0e9d20b37e
md"""
# Setup
"""

# ╔═╡ 7f123aae-2f4d-4cf5-825f-7fe3a8f69c0c
md"""
## Notação polar $$\angle$$. $$\quad$$ Operador $$j$$ $$\quad$$ 📌
"""

# ╔═╡ db949a4e-261c-4374-a806-6279370b287e
begin
	∠(x) = cis(deg2rad(x))
	j(x) = (x)*im
end;

# ╔═╡ d5d4554e-428a-457a-8fdb-47dc977f9d01
begin
	φₙ=-acos(cosφₙ)
	φₙ=rad2deg(φₙ)
	I=1 				# 1pu
	U=1 				# 1pu
	I_=(I)∠(φₙ)			# vector da corrente em pu
	U_=(U)∠(0)			# vector da tensão em pu

	# Cálculo de E':
	E_=U_-j(Xq)*I_
	E=abs(E_)
	E=round(E, digits=3)
	δ=angle(E_)
	δ=rad2deg(δ)
	δ=round(δ, digits=2)
	E, δ
end;

# ╔═╡ 4dd894c8-9b9b-474d-9a98-d805328b609e
md"""
Assim, obtém-se $$\overline{E'}=$$ $E ∠ $δ ° $$\space\mathrm {pu}$$.
"""

# ╔═╡ 45b5c9d8-93ce-4b64-8c81-431dcbc6531f
begin
	Pdʳᵉˡmax=-U^2*(Xd-Xq)/(2*Xd*Xq)
	Pdʳᵉˡmax=round(Pdʳᵉˡmax, digits=2)
end;

# ╔═╡ 892b1d19-c88a-4add-ac18-70e799e01092
begin
	δ₀=-0.5*asin(pᵣₒₜ*2*Xd*Xq/(U^2*(Xd-Xq)))
	δ₀=rad2deg(δ₀)
	δ₀=round(δ₀, digits=2)
end;

# ╔═╡ 33d13e0f-80c5-478c-99e5-e9de64a8d39a
md"""
De onde resulta o valor de $$\delta_0=$$ $δ₀ °.
"""

# ╔═╡ 1ea9ab83-10c8-4d5f-8489-e9a4754e7b1b
begin
	H1=("redução de carga, δ -> δ₀", @bind δ₂ PlutoUI.Slider(δ:0.01:δ₀, default=δ,show_value=true))
	H2=("redução de Iₑₓ, pu", @bind K₂ PlutoUI.Slider(0:0.1:1, default=1, show_value=true))
	H1, H2
end

# ╔═╡ 67b54cd9-af1a-4bb7-9a44-c66179adfbcb
begin
	φ₁=abs(φₙ*π/180)
	δ₁=abs(δ*π/180)
	Id_=(I*sin(φ₁-δ₁))∠(δ-90)
	Iq_=(I*cos(φ₁-δ₁))∠(δ)
	Id=abs(Id_)
	Id=round(Id, digits=3)
	Id, δ-90
end;

# ╔═╡ a2aac898-7c8a-42c6-a7ef-a3ff736d1ab6
md"""
O que permite obter: $$\quad \overline I_d=$$ $Id ∠ $(δ-90)° $$\space\mathrm {pu}$$.
"""

# ╔═╡ cde832b5-50ea-44d8-ae4e-f1907d7e31dc
begin
	relut_=j(Xd-Xq)*Id_
	E₀_=E_-relut_
	E₀=abs(E₀_)
	E₀=round(E₀, digits=3)
end;

# ╔═╡ 33a4d731-3f65-460d-a74e-609250fa6292
md"""
O vector da fcem de vazio, $$\overline{E'}_0$$, vem então dado por:

$$\overline{E'}_0=\overline{E'}-j(X_d-X_q)\overline{I}_d$$

Assim, obtém-se: $$\quad\overline{E'}_0=$$ $E₀ ∠ $δ ° $$\space\mathrm {pu}$$.
"""

# ╔═╡ 73b14af8-f204-4070-bab9-180b660a9029
begin
	# Pot. desenvolvida devido à fcem, pu:
	Pdᶠᵉᵐₚᵤ=(U*E₀/Xd)*sin(δ*π/180)
	Pdᶠᵉᵐₚᵤ=round(Pdᶠᵉᵐₚᵤ, digits=2)

	# Pot. desenvolvida devido ao efeito de relutância, pu:
	Pdʳᵉˡₚᵤ=(U^2*(Xd-Xq)/(2*Xd*Xq))*sin(2*δ*π/180)
	Pdʳᵉˡₚᵤ=round(Pdʳᵉˡₚᵤ, digits=2)

	# Resultados
	Pdᶠᵉᵐₚᵤ, Pdʳᵉˡₚᵤ
end

# ╔═╡ a97592ef-28ef-4d83-b979-9e5550045cd0
Pdₚᵤ=Pdᶠᵉᵐₚᵤ + Pdʳᵉˡₚᵤ  ;

# ╔═╡ 2635c31e-8a91-45b0-8e4a-b4b6f6e59ae0
md"""
Com: $$\quad I_{exc}=0\space\mathrm {pu}\quad\Rightarrow\quad E'_0\simeq 0\space\mathrm {pu}\quad \Rightarrow\quad P_d^{fcem}\simeq 0\space\mathrm {pu}$$

Por outro lado, o ponto de funcionamento, $$P_d(\delta)$$, em regime nominal é dado por: $$P_d=P_d^{fcem}+P_d^{rel}=$$ ( $Pdᶠᵉᵐₚᵤ ) + ( $Pdʳᵉˡₚᵤ ) = $Pdₚᵤ pu.
"""

# ╔═╡ f736b324-d6d9-4d8f-93d0-d520b79d4002
md"""
Assim, sem corrente de excitação, a potência desenvolvida devido ao efeito de relutância, $$P_d^{rel}$$,tem de suprir os $Pdₚᵤ pu, do ponto funcionamento.

O valor máximo da potência desenvolvida devido ao efeito de relutância, $$P_d^{rel}(max)$$, verifica-se para $$\delta=-45°$$, que permite obter:
$$P_d^{rel}(max)=\frac{U^2(X_d-Xq)}{2X_dX_q}=$$ $Pdʳᵉˡmax pu
"""

# ╔═╡ c79f1fef-c2f1-45b0-af35-f3e69e6ec77e
begin
	# eixos  d, q:
	plot([0+j(0), (1.3*cos(δ*π/180))+j(1.3*sin(δ*π/180))],
		label="eixo de quadratura", arrow=:head, linecolor=:black,
		linestyle=:dashdot,	linewidth=2)
	plot!([0+j(0), (0.5*cos(δ*π/180+π/2))+j(0.5*sin(δ*π/180+π/2))],
		label="eixo directo", arrow=:head, linecolor=:black, linewidth=2)

	# E':
	K=0.5 # factor de escala da corrente
	_jXqI_=(Xq*I)∠(φₙ-90)
	plot!([0, U_], arrow=:closed, legend=:topright, label="U∠0°", linewidth=2)
	plot!([0, K*I_], arrow=:closed, label="I∠φ", linewidth=2)
	plot!([U_, U_+_jXqI_], arrow=:closed, label="XqI∠-90°", linewidth=2)
	plot!([0,E_], arrow=:closed, minorticks=5, label="E'∠δ",
		linewidth=2, linecolor=:blue, ylims=(-0.75,0.75),
		xlims=(-0.25,1.25), size=(600,600))

	# Id_, Iq_:
	plot!([0, K*Id_],arrow=:closed, label="Id∠(δ-90°)")
	plot!([0, K*Iq_],arrow=:closed, label="Iq∠(δ)")

	#E´₀:
	plot!([U_+_jXqI_,U_+_jXqI_-relut_], arrow=:closed,
		label="(Xd-Xq)Id∠(δ)", linewidth=2)
	plot!([0,E₀_], arrow=:closed, label="E'₀∠δ", linewidth=3)
end

# ╔═╡ 5861683f-db8a-4d43-9822-f2f47431c191
begin
	# vector Iq:
	Iq₂=(U/Xq)*sin(abs(δ₂*π/180))
	Iq₂_=(Iq₂)∠(δ₂)
	# vector Id:
	E₀₂=E₀*K₂
	Id₂=(U/Xd)*cos(δ₂*π/180)-E₀₂/Xd
	Id₂_=(Id₂)∠(δ₂-90)
	# vector I, cosφ:
	I₂_=Id₂_+Iq₂_
	I₂=abs(I₂_)
	I₂=round(I₂, digits=2)
	φ₂=angle(I₂_)
	fdp=cos(φ₂)			# factor de potência (motor subexcitado -> indutivo)
	φ₂=rad2deg(φ₂)
	fdp=round(fdp, digits=3)
	I₂, fdp, δ₂, E₀₂ 	# RESULTADOS
end

# ╔═╡ 9e141f07-ad66-41f4-a53b-b6c25e4afbb2
begin
	# eixos  d, q:
	plot([0+j(0), (1.2*cos(δ₂*π/180))+j(1.2*sin(δ₂*π/180))],
		label="eixo de quadratura", arrow=:head, linecolor=:black, linestyle=:dashdot,			linewidth=2)
	plot!([0+j(0), (0.35*cos(δ₂*π/180+π/2))+j(0.35*sin(δ₂*π/180+π/2))],
		label="eixo directo", arrow=:head, linecolor=:black, linewidth=2,
		ylims=(-0.75,0.75), xlims=(-0.25,1.25), size=(600,600))

	# parte idêntica a polos lisos:
	_jXqI₂_=(Xq*I₂)∠(φ₂-90)
	plot!([0, U_], arrow=:closed, legend=:topright, label="U∠0°", linewidth=2)
	plot!([0, K*I₂_], arrow=:closed, label="I∠φ", linewidth=2)
	plot!([U_, U_+_jXqI₂_], arrow=:closed, label="XqI∠-90°", linewidth=2)
	E₂_=U_-j(Xq)*I₂_
	plot!([0,E₂_], arrow=:closed, minorticks=5, label="E'∠δ", linewidth=2)

	# Id_, Iq_:
	plot!([0, K*Id₂_],arrow=:closed, label="Id∠(δ-90°)", linewidth=1)
	plot!([0, K*Iq₂_],arrow=:closed, label="Iq∠(δ)", linewidth=1)

	#E´₀:
	relut₂_=j(Xd-Xq)*Id₂_
	E₀₂_=E₂_-relut₂_
	plot!([U_+_jXqI₂_,U_+_jXqI₂_-relut₂_], arrow=:closed, label="(Xd-Xq)Id∠(δ)", linewidth=2)
	plot!([0,E₀₂_], arrow=:closed, label="E'₀∠δ", linewidth=3)

	#-jXqIq_ e -jXdId_
	vectorXqIq=-j(Xq)*Iq₂_
	vectorXdId=-j(Xd)*Id₂_
	plot!([U_, U_+vectorXqIq],arrow=:closed, label="XqIq∠(δ-90°)",linewidth=3)
	plot!([U_+vectorXqIq, U_+vectorXqIq+vectorXdId],arrow=:closed, label="XdId∠(δ-180°)", linewidth=3)
end

# ╔═╡ 54f98ff2-02ae-418f-8c87-0e31f70352a0
md"""
## Índice
"""

# ╔═╡ b4aea351-3195-4dc2-8cfa-b423a029b840
TableOfContents(title="Índice")

# ╔═╡ ea2e1c0e-241a-4c37-9420-3f882d78a47f
md"""
!!! info
	No índice deste *notebook*, os tópicos assinalados com "💻" permitem interacção com o utilizador.

	O tópico assinado com "📌" deve ser analisado previamente para melhor compreensão dos códigos em linguagem de programação científica *Julia* apresentados no *notebook*.
"""

# ╔═╡ 520bfd7b-ad1f-44a8-a1ee-503a22923adc
md"""
## _Julia packages_
*Links to package help*: [Plots](http://docs.juliaplots.org/latest/), [PlutoUI](https://juliahub.com/docs/PlutoUI/abXFp/0.7.6/)
"""

# ╔═╡ cd9e2120-93fb-499a-8091-0dd6890d90e1
version=VERSION;

# ╔═╡ cd703dc2-6b7a-49b1-91e1-84ee712a7a9c
md"""
## _Notebook_

*Notebook* realizado em linguagem de programação *Julia* versão $(version) para a unidade curricular de Máquinas Elétricas 2 (ISEL\LEE).

Tempo de cálculo do *notebook* (1ª execução): até cerca de 4 min.

**Ricardo Luís** (Professor Adjunto, ISEL\DEEEA\GDME) \
ISEL, 13/Dez/2021
"""

# ╔═╡ 021642cb-8edd-4349-833f-41ca4144ee58
md"""
Este conteúdo possui licença [![](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](http://creativecommons.org/licenses/by-sa/4.0/).
"""

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"

[compat]
Plots = "~1.25.2"
PlutoUI = "~0.7.23"
"""

# ╔═╡ 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 = "abb72771fd8895a7ebd83d5632dc4b989b022b5b"
uuid = "6e696c72-6542-2067-7265-42206c756150"
version = "1.1.2"

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

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

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

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

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

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

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

[[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 = "a851fec56cb73cfdf43762999ec72eff5b86882a"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.15.0"

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

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

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

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

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

[[DataAPI]]
git-tree-sha1 = "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 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.2.10+0"

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

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

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

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

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

[[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 = "fd75fa3a2080109a2c0ec9864a6e14c60cca3866"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.62.0+0"

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

[[Gettext_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046"
uuid = "78b55507-aeef-58d4-861c-77aaff3498b1"
version = "0.21.0+0"

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

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

[[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]]
deps = ["Test"]
git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.0"

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

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

[[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 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

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

[[JpegTurbo_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943"
uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
version = "2.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"

[[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 = "a8f4f279b6fa3c3c4f1adadd78a621b13a506bce"
uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
version = "0.15.9"

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

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

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

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

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

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

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

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

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

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

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

[[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 = "8fb515c5a2c8941cef957e75afb99a2c24b753f3"
uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
version = "1.1.0"

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

[[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 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"

[[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 = ["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 = "7ad0dfa8d03b7bcf8c597f59f5292801730c55b8"
uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c"
version = "0.4.1"

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

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "8f82019e525f4d5c669692772a6f4b0a58b06a6a"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.2.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 = "3c76dde64d03699e074ac02eb2e8ba8254d428da"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.13"

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

[[StatsAPI]]
git-tree-sha1 = "0f2aa8e32d511f758a2ce49208181f7733a0936a"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.1.0"

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

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

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

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

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

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

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

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

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

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

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

[[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 = "66d72dc6fcc86352f01676e8f0f698562e60510f"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.23.0+0"

[[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 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.0+0"

[[libass_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47"
uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
version = "0.15.1+0"

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

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

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

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

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

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

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

[[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:
# ╟─c4d275c8-36d5-454f-bf1f-ddbc06beeae0
# ╟─d2a788ef-5292-4229-a1d1-3fd15db67c51
# ╟─17bc7f80-c13c-11eb-227f-b125d84c8b40
# ╠═20ed504e-08d1-45b9-8494-c42170182898
# ╟─25f9aa0c-efa0-4c8a-bbfb-c5648bf2f8a2
# ╟─0545e797-9d40-48c4-ab96-195959331560
# ╠═342aacbe-df8e-42b9-a7a2-8538476f2a80
# ╟─65dd0a07-ff99-4887-8a86-142248705131
# ╟─8b677658-96a8-40cb-b4cf-1638703dda22
# ╟─4dd894c8-9b9b-474d-9a98-d805328b609e
# ╠═d5d4554e-428a-457a-8fdb-47dc977f9d01
# ╟─3ec74057-fcbb-4d79-8aca-719289c2299e
# ╟─a2aac898-7c8a-42c6-a7ef-a3ff736d1ab6
# ╠═67b54cd9-af1a-4bb7-9a44-c66179adfbcb
# ╟─33a4d731-3f65-460d-a74e-609250fa6292
# ╠═cde832b5-50ea-44d8-ae4e-f1907d7e31dc
# ╟─49053499-f759-4043-a9b8-48f42e45589a
# ╠═c79f1fef-c2f1-45b0-af35-f3e69e6ec77e
# ╟─19c628e8-60c9-46d0-9ab8-78e70b8bfa6f
# ╟─2cd26842-6c40-4dc0-9979-da4685630aa1
# ╠═73b14af8-f204-4070-bab9-180b660a9029
# ╟─6bc18d01-7285-4b7b-9769-3a7d52baae75
# ╟─2635c31e-8a91-45b0-8e4a-b4b6f6e59ae0
# ╠═a97592ef-28ef-4d83-b979-9e5550045cd0
# ╟─f736b324-d6d9-4d8f-93d0-d520b79d4002
# ╠═45b5c9d8-93ce-4b64-8c81-431dcbc6531f
# ╟─60f80e79-eeb8-4b60-801f-98caa28b4dfd
# ╟─dd7d16e4-7b01-4aa0-a1ba-ecc7881900fb
# ╟─61609aa9-9feb-4a63-b4e9-2fd9a88f8106
# ╟─33d13e0f-80c5-478c-99e5-e9de64a8d39a
# ╠═892b1d19-c88a-4add-ac18-70e799e01092
# ╟─28da7f3c-97fd-4a80-ad21-eeb201dcc881
# ╠═5861683f-db8a-4d43-9822-f2f47431c191
# ╟─311eecf2-4bd6-44bc-8c67-a680f4fd5d33
# ╟─b47b956c-8880-4c22-aeea-d9a55c518b6a
# ╟─1ea9ab83-10c8-4d5f-8489-e9a4754e7b1b
# ╟─9e141f07-ad66-41f4-a53b-b6c25e4afbb2
# ╟─78a2ef93-5ed1-44f8-8aa9-7e7d8d80a2df
# ╟─c5cc14a5-73c6-4f10-bc3e-bd7b68eddafa
# ╟─d58c2390-6aaa-4e73-b360-9f0e9d20b37e
# ╟─7f123aae-2f4d-4cf5-825f-7fe3a8f69c0c
# ╠═db949a4e-261c-4374-a806-6279370b287e
# ╟─54f98ff2-02ae-418f-8c87-0e31f70352a0
# ╠═b4aea351-3195-4dc2-8cfa-b423a029b840
# ╟─ea2e1c0e-241a-4c37-9420-3f882d78a47f
# ╟─520bfd7b-ad1f-44a8-a1ee-503a22923adc
# ╠═0b9abd74-d199-4720-803e-eb7861b86572
# ╟─cd703dc2-6b7a-49b1-91e1-84ee712a7a9c
# ╟─cd9e2120-93fb-499a-8091-0dd6890d90e1
# ╟─021642cb-8edd-4349-833f-41ca4144ee58
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002

max_stars_repo_name: Ricardo-Luis/notebooks

max_issues_repo_name: Ricardo-Luis/notebooks

max_forks_repo_name: Ricardo-Luis/notebooks


text:
using HTTP, Sockets, JSON3, Dates

mutable struct ToDo                      # 1
  id::Int64
  description::String
  completed::Bool
  created::Date
  priority::Int8
end

const ToDos = Dict{Int, ToDo}()          # 2

function initToDos()                     # 3
    todo1 = ToDo(1, "Getting groceries", false, Date("2022-04-01", "yyyy-mm-dd"), 5)
    todo2 = ToDo(2, "Visiting my therapist", false, Date("2022-04-02", "yyyy-mm-dd"), 4)
    todo3 = ToDo(3, "Getting a haircut", true, Date("2022-03-28", "yyyy-mm-dd"), 6)
    todo4 = ToDo(4, "Paying the energy bill", false, Date("2022-04-04", "yyyy-mm-dd"), 8)
    todo5 = ToDo(5, "Blog about workspace management", true, Date("2022-03-29", "yyyy-mm-dd"), 4)
    todo6 = ToDo(6, "Book a flight to Israel", false, Date("2022-04-04", "yyyy-mm-dd"), 3)
    todo7 = ToDo(7, "Conquer the world", true, Date("2022-03-29", "yyyy-mm-dd"), 1)
    ToDos[1] = todo1
    ToDos[2] = todo2
    ToDos[3] = todo3
    ToDos[4] = todo4
    ToDos[5] = todo5
    ToDos[6] = todo6
    ToDos[7] = todo7
end

function getToDo(req::HTTP.Request)                     # 4
    todoId = HTTP.URIs.splitpath(req.target)[3]         # 4A
    todoId = parse(Int64, todoId)
    # println(todoId)
    # println(haskey(ToDos, todoId))
    if haskey(ToDos, todoId)                            # 4B
        todo = ToDos[todoId]                            # 4C
        return HTTP.Response(200, JSON3.write(todo))    # 4D
    else
        return HTTP.Response(200, JSON3.write("No ToDo with that key exists."))
    end
end

function deleteToDo(req::HTTP.Request)                  # 5
    todoId = HTTP.URIs.splitpath(req.target)[3]
    todo = ToDos[parse(Int64, todoId)]
    delete!(ToDos, todo.id)                             # 5A
    return HTTP.Response(200)                           # 5B
end

function createToDo(req::HTTP.Request)                      # 6
    todo = JSON3.read(IOBuffer(HTTP.payload(req)), ToDo)    # 6A
    println(todo)
    todo.id = maximum(collect(keys(ToDos))) + 1             # 6B
    ToDos[todo.id] = todo                                   # 6C
    println(ToDos)
    return HTTP.Response(200, JSON3.write(todo))            # 6D
end

function updateToDo(req::HTTP.Request)                       # 7
    todo = JSON3.read(IOBuffer(HTTP.payload(req)), ToDo)
    ToDos[todo.id] = todo                                    # 7A
    return HTTP.Response(200, JSON3.write(todo))             # 7B
end

JSON3.StructType(::Type{<:ToDo}) = JSON3.Struct() # - needed to be able to work with JSON3
initToDos()
# println(ToDos)

const HOST = "127.0.0.1"
const PORT = 8080
const ROUTER = HTTP.Router()
HTTP.@register(ROUTER, "POST", "/api/todos", createToDo)        # 8A
HTTP.@register(ROUTER, "GET", "/api/todos/*", getToDo)          # 8B
HTTP.@register(ROUTER, "PUT", "/api/todos", updateToDo)         # 8C
HTTP.@register(ROUTER, "DELETE", "/api/todos/*", deleteToDo)    # 8D

HTTP.serve(ROUTER, HOST, PORT)

# tests:
# using HTTP, Dates, JSON
# GET
# r = HTTP.get("http://localhost:8080/api/todos/3")
# HTTP.Messages.Response:
# """
# HTTP/1.1 200 OK
# Transfer-Encoding: chunked

# {"id":3,"description":"Getting a haircut","completed":true,"created":"2022-03-28","priority":6}"""

# DELETE
# julia> HTTP.delete("http://localhost:8080/api/todos/3")
# HTTP.Messages.Response:
# """
# HTTP/1.1 200 OK
# Transfer-Encoding: chunked

# """
# julia> HTTP.get("http://localhost:8080/api/todos/3")
# HTTP.Messages.Response:
# """
# HTTP/1.1 200 OK
# Transfer-Encoding: chunked

# "No ToDo with that key exists.""""

# CREATE
# julia> JSON.json(ToDo(8, "Listening music", false, Date("2022-04-07", "yyyy-mm-dd"), 7))
# "{\"id\":8,\"description\":\"Listening music\",\"completed\":false,\"created\":\"2022-04-07\",\"priority\":7}"

# HTTP.post("http://localhost:8080/api/todos", [], "{\"id\":8,\"description\":\"Listening music\",\"completed\":false,\"created\":\"2022-04-07\",\"priority\":7}")

# HTTP.Messages.Response:
# """
# HTTP/1.1 200 OK
# Transfer-Encoding: chunked

# {"id":8,"description":"Listening music","completed":false,"created":"2022-04-07","priority":7}"""

# Response from webserver:
# D:\Julia_Docs\Julia-Web-Development-with-Genie\Chapter2>julia webserver_json3.jl
# ToDo(8, "Listening music", false, Date("2022-04-07"), 7)
# Dict{Int64, ToDo}(
# 5 => ToDo(5, "Blog about workspace management", true, Date("2022-03-29"), 4),
# 4 => ToDo(4, "Paying the energy bill", false, Date("2022-04-04"), 8),
# 6 => ToDo(6, "Book a flight to Israel", false, Date("2022-04-04"), 3),
# 7 => ToDo(7, "Conquer the world", true, Date("2022-03-29"), 1),
# 2 => ToDo(2, "Visiting my therapist", false, Date("2022-04-02"), 4),
# 8 => ToDo(8, "Listening music", false, Date("2022-04-07"), 7),
# 3 => ToDo(3, "Getting a haircut", true, Date("2022-03-28"), 6),
# 1 => ToDo(1, "Getting groceries", false, Date("2022-04-01"), 5)

# test with curl , postman

ext: jl


text:
"""
    Point2D{T<:Real} <: FieldVector{2,T}

Representation of a point in two-dimensional Euclidean space.
"""
struct Point2D{T<:Real} <: FieldVector{2,T}
    x::T
    y::T
end
Point2D(x, y) = Point2D(promote(x, y)...)

StaticArrays.similar_type(::Type{<:Point2D}, ::Type{T}, ::Size{(2,)}) where {T} = Point2D{T}
Base.convert(::Type{<:Point2D{T}}, arg::VectorValue{D}) where {D,T} = Point2D{T}(Tuple(arg))

@inline advance_step(x::Point2D, step::Real, ϕ::Real) = x + step * Point2D(cos(ϕ), sin(ϕ))


text:
# This file is part of Kpax3. License is MIT.

function save(ofile::String,
              x::KData)
  # create directory if it does not exist
  dirpath = dirname(ofile)
  if !isdir(dirpath)
    mkpath(dirpath)
  end

  fpo = FileIO.File(FileIO.@format_str("JLD2"), ofile)
  obj = Dict(
    "data" => x.data,
      "id" => x.id,
     "ref" => x.ref,
     "val" => x.val,
     "key" => x.key
  )

  FileIO.save(fpo, obj)

  nothing
end

function loadnt(ifile::String)
  # open ifile for reading and immediately close it. We do this to throw a
  # proper Julia standard exception if something is wrong
  f = open(ifile, "r")
  close(f)

  fpo = FileIO.File(FileIO.@format_str("JLD2"), ifile)
  (d, id, ref, val, key) = FileIO.load(fpo, "data", "id", "ref", "val", "key")

  NucleotideData(d, id, ref, val, key)
end

function loadaa(ifile::String)
  # open ifile for reading and immediately close it. We do this to throw a
  # proper Julia standard exception if something is wrong
  f = open(ifile, "r")
  close(f)

  fpo = FileIO.File(FileIO.@format_str("JLD2"), ifile)
  (d, id, ref, val, key) = FileIO.load(fpo, "data", "id", "ref", "val", "key")

  AminoAcidData(d, id, ref, val, key)
end


text:
using X86Assembly
using Base.Test

simplef = [
  0x55,                     # push   %rbp
  0x48, 0x89, 0xe5,         # mov    %rsp,%rbp
  0x89, 0x7d, 0xfc,         # mov    %edi,-0x4(%rbp)
  0x48, 0x89, 0x75, 0xf0,   # mov    %rsi,-0x10(%rbp)
  0x8b, 0x45, 0xfc,         # mov    -0x4(%rbp),%eax
  0x5d,                     # pop    %rbp
  0xc3,                     # retq
]
X86Assembly.parseAllOpc(simplef)

#=
misc = [
  0x6A, 0x01
]
X86Assembly.parseAllOpc(misc)
=#

avx = [
  0xf3,0x0f,0x58,0xed, 	    # addss	  %xmm5, %xmm5
  0xc5,0xca,0x58,0xd4,      # vaddss  %xmm4, %xmm6, %xmm2
  0xc4,0x41,0x32,0x58,0xd0,  # vaddss  %xmm8, %xmm9, %xmm10
  0x62,0x01,0x56,0x00,0x58,0xfc,  # vaddss %xmm28, %xmm21, %xmm31
  0x62,0x01,0x56,0x81,0x58,0xfc,  # vaddss %xmm28, %xmm21, %xmm31 {%k1} {z}
  0x62,0x01,0x56,0x30,0x58,0xfc  # vaddss {rd-sae}, %xmm28, %xmm21, %xmm31
]
X86Assembly.parseAllOpc(avx)

funky_prefixes = [
  0xf2,0xf3,0x0f,0x58,0xed, 	              # extra f2 prefix
  0xf2,0xf2,0xf3,0x0f,0x58,0xed, 	          # two extra f2 prefixes
  0xf2,0xf2,0xf3,0xf3,0x0f,0x58,0xed, 	    # extra f2 and f3 prefixes
  0xf2,0xf3,0xf2,0xf3,0x0f,0x58,0xed, 	    # same, but different order
  0xf3,0x66,0x0f,0x58,0xed, 	              # extraneous 66 prefix
]
X86Assembly.parseAllOpc(funky_prefixes)


text:
module TranspositionM

export scytale

using Main.UtilsM: removeExtras

# Scytale Cipher
function scytale(text::String, rails::Integer)

    # Assumes that the text is already clean
    # Since this is a permutation cipher it doesn't need an alphabet

    eachrail = Dict()
    for i = 1:rails
        eachrail[i] = join([
            text[x]
            for x in range(1, length = length(text)) if
            x % rails - i == 0 || x % rails - i == -rails
        ])
    end
    # println(eachrail)

    return join([eachrail[i] for i = 1:rails])

end # function

# println(scytale("WOEEVEAEARRTEEODDNIFCSLEC", 3))

end # module

max_stars_repo_name: Squalm/Cipher-Tools

max_issues_repo_name: Squalm/Cipher-Tools

max_forks_repo_name: Squalm/Cipher-Tools


text:
export extractor, extractreshape

function convert_to_diagonal_matrix end
function convert_to_vector  end

function (sim::Simulation)(::typeof(convert_to_diagonal_matrix),symbol::Symbol)

    fx  =   spdiagm(sim(symbol,x̂)[:])
    fy  =   spdiagm(sim(symbol,ŷ)[:])
    fz  =   spdiagm(sim(symbol,ẑ)[:])
    O = spzeros(ncells(sim.grid),ncells(sim.grid));

             [  fx     O      O;
                O     fy      O;
                O      O      fz
             ]
end

function (sim::Simulation)(::typeof(convert_to_vector),symbol::Symbol)

    fx  =   sim(symbol,x̂)[:]
    fy  =   sim(symbol,ŷ)[:]
    fz  =   sim(symbol,ẑ)[:]
    [fx ; fy ; fz]

end

function Base.kron(∂::SparseMatrixCSC, dir::Direction, g::Grid{1})
    return ∂
end

function Base.kron(∂::SparseMatrixCSC, dir::Direction, g::Grid{2})
    if dir == x̂
       Iy =  I(size(g,2))
       return kron(Iy , ∂)
    elseif dir == ŷ
       Ix =  I(size(g,1))
       return  kron(∂ , Ix)
    end
end

function Base.kron(∂::SparseMatrixCSC, dir::Direction, g::Grid{3})
    nx,ny,nz = size(g)
    Iz =  I(nz) ; Iy =  I(ny) ; Ix = I(nx)
    if dir == x̂
    return kron(Iz , Iy , ∂)
    end
    if dir == ŷ
    return  kron(Iz ,∂ , Ix)
    end
    if dir == ẑ
    return   kron(∂ ,Iy , Ix)
    end
end

function extractor end
function extractreshape end

function (sim::Simulation)(::typeof(extractor), F::AbstractVector, dir::Direction{ND}) where ND
    g = sim.grid
    Nw = ncells(g);
    f =  F[((ND-1)*Nw +1) : (ND*Nw)];
end

function (sim::Simulation)(::typeof(extractreshape), F::AbstractVector, dir::Direction)
    f = sim(extractor,F,dir)
        sim(reshape,f)
end

function (sim::Simulation)(::typeof(reshape), F::AbstractVector)
    g = sim.grid
    F = reshape(F,size(g));
    return F
end


text:
"""
    TypeW()

Lorem ipsum dolor sit amet.
"""
struct TypeW

end


text:
# Users of this module should first read the document
# https://alan-turing-institute.github.io/MLJ.jl/dev/adding_models_for_general_use/

module MLJBase

export MLJType, Model, Supervised, Unsupervised, Deterministic, Probabilistic
export DeterministicNetwork, ProbabilisticNetwork
export fit, update, clean!
export predict, predict_mean, predict_mode, fitted_params
export transform, inverse_transform, se, evaluate, best
export load_path, package_url, package_name, package_uuid
export input_scitype_union, input_is_multivariate
export target_scitype_union, target_quantity
export is_pure_julia, is_wrapper

export params                                        # parameters.jl
export reconstruct, int, decoder, classes            # data.jl
export selectrows, selectcols, select, nrows, schema # data.jl
export table, levels_seen, matrix, container_type    # data.jl
export partition,StratifiedKFold                     # utilities.jl
export Found, Continuous, Finite, Infinite           # scitypes.jl
export OrderedFactor, Unknown                        # scitypes.jl
export Count, Multiclass, Binary                     # scitypes.jl
export scitype, scitype_union, scitypes              # scitypes.jl
export HANDLE_GIVEN_ID, @more, @constant             # show.jl
export color_on, color_off                           # show.jl
export UnivariateFinite, average                    # distributions.jl
export SupervisedTask, UnsupervisedTask, MLJTask     # tasks.jl
export X_and_y, X_, y_, nrows, nfeatures             # tasks.jl
export load_boston, load_ames, load_iris             # datasets.jl
export load_reduced_ames                             # datasets.jl
export load_crabs, datanow                           # datasets.jl
export info                                          # info.jl

# methods from other packages to be rexported:
export pdf, mean, mode

import Base.==

using Tables
import Distributions
import Distributions: pdf, mode
using CategoricalArrays
import CategoricalArrays
import CSV

# to be extended:
import StatsBase: fit, predict, fit!

# from Standard Library:
using Statistics
using Random
using InteractiveUtils
using SparseArrays

## CONSTANTS

# the directory containing this file:
const srcdir = dirname(@__FILE__)
# horizontal space for field names in `MLJType` object display:
const COLUMN_WIDTH = 24
# how deep to display fields of `MLJType` objects:
const DEFAULT_SHOW_DEPTH = 0

include("utilities.jl")
include("scitypes.jl")

## ABSTRACT TYPES

# overarching MLJ type:
abstract type MLJType end

# for storing hyperparameters:
abstract type Model <: MLJType end

abstract type Supervised <: Model end
abstract type Unsupervised <: Model end

# supervised models that `predict` probability distributions are of:
abstract type Probabilistic <: Supervised end

# supervised models that `predict` point-values are of:
abstract type Deterministic <: Supervised end

# for models that are "exported" learning networks (return a Node as
# their fit-result; see MLJ/networks.jl):
abstract type ProbabilisticNetwork <: Probabilistic end
abstract type DeterministicNetwork <: Deterministic end

# by default, MLJType objects are `==` if: (i) they have a common
# supertype AND (ii) they have the same set of defined fields AND
# (iii) their defined field values are `==`:
function ==(m1::M1, m2::M2) where {M1<:MLJType,M2<:MLJType}
    if M1 != M1
        return false
    end
    defined1 = filter(fieldnames(M1)|>collect) do fld
        isdefined(m1, fld)
    end
    defined2 = filter(fieldnames(M1)|>collect) do fld
        isdefined(m2, fld)
    end
    if defined1 != defined2
        return false
    end
    same_values = true
    for fld in defined1
        same_values = same_values && getfield(m1, fld) == getfield(m2, fld)
    end
    return same_values
end

## THE MODEL INTERFACE

# every model interface must implement a `fit` method of the form
# `fit(model, verbosity, X, y) -> fitresult, cache, report` or
# `fit(model, verbosity, X, ys...) -> fitresult, cache, report` (multivariate case)
# or, one the simplified versions
# `fit(model, X, y) -> fitresult`
# `fit(model, X, ys...) -> fitresult`
fit(model::Model, verbosity::Int, args...) = fit(model, args...), nothing, nothing

# each model interface may optionally overload the following refitting
# method:
update(model::Model, verbosity, fitresult, cache, args...) =
    fit(model, verbosity, args...)

# methods dispatched on a model and fit-result are called
# *operations*.  supervised models must implement a `predict`
# operation (extending the `predict` method of StatsBase).

# unsupervised methods must implement this operation:
function transform end

# unsupervised methods may implement this operation:
function inverse_transform end

# this operation can be optionally overloaded to provide access to
# fitted parameters (eg, coeficients of linear model):
fitted_params(::Model, fitresult) = (fitresult=fitresult,)

# operations implemented by some meta-models:
function se end
function evaluate end
function best end

# a model wishing invalid hyperparameters to be corrected with a
# warning should overload this method (return value is the warning
# message):
clean!(model::Model) = ""

# fallback trait declarations:
target_scitype_union(::Type{<:Supervised}) = Union{Found,NTuple{<:Found}}  # a Tuple type in multivariate case
output_scitype_union(::Type{<:Unsupervised}) = Union{Missing,Found} # never a Tuple type
output_is_multivariate(::Type{<:Unsupervised}) = true
input_scitype_union(::Type{<:Model}) = Union{Missing,Found}
input_is_multivariate(::Type{<:Model}) = true
is_pure_julia(::Type{<:Model}) = false
package_name(::Type{<:Model}) = "unknown"
load_path(M::Type{<:Model}) = "unknown"
package_uuid(::Type{<:Model}) = "unknown"
package_url(::Type{<:Model}) = "unknown"
is_wrapper(::Type{<:Model}) = false
is_wrapper(m::Model) = is_wrapper(typeof(m))

target_scitype_union(model::Model) = target_scitype_union(typeof(model))
input_scitype_union(model::Model) = input_scitype_union(typeof(model))
input_is_multivariate(model::Model) = input_is_multivariate(typeof(model))
is_pure_julia(model::Model) = is_pure_julia(typeof(model))
package_name(model::Model) = package_name(typeof(model))
load_path(model::Model) = load_path(typeof(model))
package_uuid(model::Model) = package_uuid(typeof(model))
package_url(model::Model) = package_url(typeof(model))

# probabilistic supervised models may also overload one or more of
# `predict_mode`, `predict_median` and `predict_mean` defined below.

# mode:
predict_mode(model::Probabilistic, fitresult, Xnew) =
    mode.(predict(model, fitresult, Xnew))

# mean:
predict_mean(model::Probabilistic, fitresult, Xnew) =
    mean.(predict(model, fitresult, Xnew))

# median:
predict_median(model::Probabilistic, fitresult, Xnew) =
    median.(predict(model, fitresult, Xnew))

# for unpacking the fields of MLJ objects:
include("parameters.jl")

# for displaying objects of `MLJType`:
include("show.jl")

# convenience methods for manipulating categorical and tabular data
include("data.jl")

# probability distributions and methods not provided by
# Distributions.jl package:
include("distributions.jl")

include("info.jl")
include("tasks.jl")
include("datasets.jl")

end # module


text:
include("random_policy.jl")
include("weighted_ramdom_policy.jl")
include("V_based_policy.jl")
include("Q_based_policy.jl")
include("off_policy.jl")


text:
using LambdaFn
using Test

@testset "LambdaFn" begin
    @test @λ(_ + _)(1,2) == 3
    @test @λ(_a + _b*_a)(3,2) == 9
    @test @λ(_1 - _2)(10,5) == 5
    @test @λ(_2 - _1)(10,5) == -5
    @test @λ(_a - _b)(10,5) == 5
    @test @λ(_b - _a)(10,5) == 5
    @test @λ(_1 - _3)(5,1,5) == 0
    @test @λ(2*3)() == 6
    @test @lf(_ + 1)(1) == 2
    @test 1:10 |> @λ(filter(@λ(_ > 3),_)) == 4:10
    # @test @λ(_)
    @test_throws Exception @eval(@λ(_ + _1))
    @test_throws Exception @eval(@λ(_ + _a))
    @test_throws Exception @eval(@λ(_1 + _a))
    @test_throws Exception @eval(@λ(_0 + 1))
end


text:
function compute_v(params, α, n, x, bc = compute_bc(params, α, n))
    @unpack r, D, dim = params

    x = [x;]

    m = length(D)
    v = ones(size(x))
    dv = zeros(size(x))
    if α > 0
        r₁ = [0; r[1:m]]
        r₁[1] -= 1e-8
        r₁[m+1] += 1e-8
        for i = 1:m
            inds = r₁[i] .< x .≤ r₁[i+1]
            J, Y, dJ, dY = compute_JY(α * x[inds] / √D[i], n, dim)
            if abs(bc[i, 2]) > 1e-12
                v[inds] = bc[i, 1] * J + bc[i, 2] * Y
                dv[inds] = α / √D[i] * (bc[i, 1] * dJ + bc[i, 2] * dY)
            else
                v[inds] = bc[i, 1] * J
                dv[inds] = α / √D[i] * bc[i, 1] * dJ
            end
        end
    end

    v, dv
end


text:
function print_2Ddecision(lda::Lda, data::Matrix, labels = nothing)

    #
    # Output result
    #
    n = size(data, 2)

    projection = process(lda, data, 2)

    y = reshape(projection[2, :], n)
    x = reshape(projection[1, :], n)

    if labels == nothing
        println(plot(x = x, y = y, kind = :scatter))
    else
        println(plot(x = x, y = y, group = labels, kind = :scatter))
    end
end


text:
@inline Credential() = Credential(Base.SecretBuffer())

@inline function Credential(value::AbstractString)
    cred = Credential()
    cred[] = value
    return cred
end

@inline function Base.shred!(cred::Credential)
    Base.shred!(cred.buf)
    return nothing
end

@inline function Base.shred!(config::Config)
    Base.shred!(config.github_token)
    return nothing
end

@inline function Base.setindex!(cred::Credential, value::String)
    Base.shred!(cred.buf)
    seekstart(cred.buf)
    write(cred.buf, value)
    return nothing
end

@inline function Base.getindex(cred::Credential)
    seekstart(cred.buf)
    value = read(cred.buf, String)::String
    return value
end


text:
using BayesianDataFusion
using Base.Test

rows = Int32[ 1:200; 151:350 ]
cols = Int32[ 151:350; 1:2:399 ]

######## SparseBinMatrixCSR ###########
csr = SparseBinMatrixCSR(rows, cols)

y = zeros(Float64, size(csr, 1))
x = rand(Float64,  size(csr, 2))

A_mul_B!(y, csr, x)

######### SparseBinMatrix  ############
bin = SparseBinMatrix(rows, cols)
y2 = zeros(Float64, size(bin, 1))
A_mul_B!(y2, bin, x)

A = sparse(rows, cols, 1.0)

@test_approx_eq y  A*x
@test_approx_eq y2 A*x

######### Parallel CSR ###########


text:
#!/usr/bin/env julia

using ArgParse.ArgParseSettings
using ArgParse.@add_arg_table
using ArgParse.parse_args
using BioAlignments
using DataStructures
using CSV
using DataFrames
using StatsBase
using GenomicFeatures

include("./CustomJuliaModules/WriteDataFrame.jl")
using WriteDataFrame

function isinregion(pos::Int64,chr::String,
    exclude_reg::Dict{String,Array{String,1}})::Bool

    if haskey(exclude_reg,chr)
        fr = parse(Int64,split(exclude_reg[chr][1],":")[1])
        lr = parse(Int64,split(exclude_reg[chr][end],":")[2])
        if pos >= fr && pos <= lr
            for intv in exclude_reg[chr]
                pos_ex = split(intv,":")

                if pos > parse(Int64,pos_ex[1]) && pos < parse(Int64,pos_ex[2])
                    return true
                end
            end
        end
    end
    return false
end

function bamcounter(bam::String, win::Int64, bed::Any, is_se::Bool)
    data = DataFrame(Sample=String[], TotalReads=Int64[], PrimerAlignedBases=Int64[],
                     OtherBases=Int64[], IsMapped=Int64[], MutAndInDel=Int64[],
                     IsPrimary=Int64[], MapQ0=Int64[], MapQ1=Int64[], MapQ5=Int64[],
                     MapQ10=Int64[], MapQ20=Int64[], MapQ40=Int64[], MapQup40=Int64[],
                     HardClip=Int64[], SoftClip=Int64[], CIGARXID=Int64[],
                     PairedReads=Int64[], MappedProperPairs=Int64[],
                     UnmappedReads=Int64[], MatesUnmapped=Int64[],
                     PCROrOpticalDuplicates=Int64[], SuplementaryAlignment=Int64[],
                     SecondaryAlignment=Int64[])
    starts_data = DataFrame()

    reader = open(BAM.Reader, bam)
    record = BAM.Record()
    prime_aligned_bases = Int64(0)
    other_bases = Int64(0)
    ct = Int64(0)
    ismampped_ct = Int64(0)
    mut_and_indels_ct = Int64(0)
    isprimarry_ct = Int64(0)
    map_q0_ct = Int64(0)
    map_q1_ct = Int64(0)
    map_q5_ct = Int64(0)
    map_q10_ct = Int64(0)
    map_q20_ct = Int64(0)
    map_q40_ct = Int64(0)
    map_up40_ct = Int64(0)
    cigar_hard_clip_ct = Int64(0)
    cigar_soft_clip_ct = Int64(0)
    cigar_seq_mismatch_ct = Int64(0)
    paired_reads_ct = Int64(0)
    proper_pairs_mapped_ct = Int64(0)
    unmapped_reads_ct = Int64(0)
    mates_unmapped_ct = Int64(0)
    read_PCR_or_optical_duplicate_ct = Int64(0)
    suplementary_alignment_ct = Int64(0)
    secondary_alignment_ct = Int64(0)
    mate1 = false
    mate2 = false
    posr = Int64(0)
    posl = Int64(0)
    totalPairedLen = Int64(0)
    totalOverlap = Int64(0)
    overlapPer = Float64(0)
    treads = 0
    wreads = 0
    m2posr = 0
    m1posl = 0
    mate2tmp = ""
    start_bias = Dict{String,Int64}()
    win_nr = Int64(0)
    bed_f = false
    exclude_reg = Dict{String,Array{String,1}}()

    ## Reads excluded regions bed file, if exist.

    if bed != nothing
        bed_f = true
        reader_bed = open(BED.Reader, bed)

        for br in reader_bed
            chr_n = seqname(br)
            intv = string(leftposition(br)) * ":" * string(rightposition(br))

            if haskey(exclude_reg,chr_n)
                push!(exclude_reg[chr_n],intv)
            else
                exclude_reg[chr_n]=[intv]
            end
        end
        close(reader_bed)
    end

    while !eof(reader)
        read!(reader, record)
        flag = BAM.flag(record)
        cigar = BAM.cigar(record)
        ismapped = BAM.ismapped(record)

        ## Overlap calculations
        if ismapped
            cigar = BAM.cigar(record)
            insdel = contains(cigar, "I") || contains(cigar, "D")

            ## Check for first in pair, primary, paired read
            if flag&900 == 0 && flag&3 == 3 && !insdel
                posr = BAM.rightposition(record)
                m1posl = BAM.position(record)
                name = BAM.tempname(record)
                mate1 = true
                mate1tmp = BAM.tempname(record)
                mate1len = posr - m1posl

                if mate2 && m1posl < posl && mate1tmp == mate2tmp
                    lenpair = mate1len + mate2len
                    overlap = posr - posl

                    if lenpair >= overlap
                        totalPairedLen += lenpair

                        if (overlap > 0)
                            totalOverlap += overlap
                        end
                        treads += 1
                    else
                        wreads += 1
                    end
                    mate1 = false
                    mate2 = false
                    posr = 0
                    posl = 0
                    mate1len = 0
                    mate2len = 0
                    m2posr = 0
                    m1posl = 0
                end
            end

            ## Check for second in pair, primary, paired read
            if flag&836 == 0 && flag&3 == 3 && !insdel
                posl = BAM.position(record)
                m2posr = BAM.rightposition(record)
                mate2 = true
                mate2len = m2posr - posl
                mate2tmp = BAM.tempname(record)

                if mate1 && m1posl < posl && mate1tmp == mate2tmp
                    lenpair = mate1len + mate2len
                    overlap = posr - posl

                    if lenpair >= overlap
                        totalPairedLen += lenpair

                        if (overlap > 0)
                            totalOverlap += overlap
                        end
                        treads += 1
                    else
                        wreads += 1
                    end
                    mate1 = false
                    mate2 = false
                    posr = 0
                    posl = 0
                    mate1len = 0
                    mate2len = 0
                    m2posr = 0
                    m1posl = 0
                end
            end
        end

        if totalPairedLen != 0
            overlapPer = round((totalOverlap / totalPairedLen) * 100,2)
        end

        if flag&1 == 1
            paired_reads_ct += 1
        end

        if flag&3 == 3
            proper_pairs_mapped_ct += 1
        end

        if flag&4 == 4
            unmapped_reads_ct += 1
        end

        if flag&9 == 9
            mates_unmapped_ct += 1
        end

        if flag&1024 == 1024
            read_PCR_or_optical_duplicate_ct += 1
        end

        if flag&2048 == 2048
            suplementary_alignment_ct += 1
        end

        if flag&256 == 256
            secondary_alignment_ct += 1
        end

        if flag&2304 == 0
            isprimarry_ct += 1
        end

        if ismapped
            ismampped_ct += 1
        end

        try md_taq = record["MD"]
            splited_MD = split(replace(record["MD"], r"[\\^]*[ACGT]+", x -> "_"*x*"_"), "_")
            if length(splited_MD) > 1
                mut_and_indels_ct += 1
            end
        end

        try mapq = UInt8((record.bin_mq_nl >> 8) & 0xff)
            if mapq == 0
                map_q0_ct += 1
            end

            if mapq in 0:1
                map_q1_ct += 1
            end

            if mapq in 1:5
                map_q5_ct += 1
            end

            if mapq in 5:10
                map_q10_ct += 1
            end

            if mapq in 10:20
                map_q20_ct += 1
            end

            if mapq in 20:40
                map_q40_ct += 1
            end

            if mapq > 40
                map_up40_ct += 1
            end
        end

        if (flag&4 == 0) && (flag&256 == 0) && (flag&2048 == 0)  # filter out only mapped and primary alignments
            prime_aligned_bases += BAM.seqlength(record)
        else
            other_bases += BAM.seqlength(record)
        end

        ## Start_bais calculation

        if (flag&4 == 0) && (flag&256 == 0) && (flag&2048 == 0)
            chr = BAM.refname(record)
            isNotChrUn = !contains(chr, "chrUn")

            if ((flag&64 == 64 && flag&3 == 3) || is_se) && isNotChrUn
                pos = BAM.position(record)
                in_reg = false

                if bed_f
                    in_reg = isinregion(pos,chr,exclude_reg)
                end

                if !in_reg
                    win_nr = floor(Int64,pos/win)
                    win_nr_k = chr * ":" * string(win_nr)

                    if haskey(start_bias, win_nr_k)
                        start_bias[win_nr_k] += 1
                    else
                        start_bias[win_nr_k] = 1
                    end
                end
            end
        end

        if (search(uppercase(cigar), 'X') > 0 ||
            search(uppercase(cigar), 'I') > 0 ||
            search(uppercase(cigar), 'D') > 0)
            cigar_seq_mismatch_ct += 1
        end

        if search(uppercase(cigar), 'S') > 0
            cigar_soft_clip_ct += 1
        end

        if search(uppercase(cigar), 'H') > 0
            cigar_hard_clip_ct += 1
        end

        ct += 1
        if mod(ct,10000) == 0
            print(STDERR, "PARSED $ct BAM records \r")
        end
    end

    push!(data, [splitext(basename(bam))[1], ct, prime_aligned_bases,
                 other_bases, ismampped_ct, mut_and_indels_ct, isprimarry_ct, map_q0_ct,
                 map_q1_ct, map_q5_ct, map_q10_ct, map_q20_ct, map_q40_ct,
                 map_up40_ct, cigar_hard_clip_ct, cigar_soft_clip_ct,
                 cigar_seq_mismatch_ct, paired_reads_ct, proper_pairs_mapped_ct,
                 unmapped_reads_ct, mates_unmapped_ct, read_PCR_or_optical_duplicate_ct,
                 suplementary_alignment_ct, secondary_alignment_ct])

    if isempty(start_bias)
        starts_data[:NrOfStarts] = 0
        starts_data[:Frequency] = 0
    else
        dataForLogs = DataFrame()
        dataForLogs[:Chr] = collect(keys(start_bias))
        dataForLogs[:NrOfStarts] = collect(values(start_bias))
        logN = replace(bam,".bam" => "_starts_bias.csv")
        CSV.write(logN, dataForLogs, delim=',')
        count_uniq = countmap(collect(values(start_bias)))
        starts_data[:NrOfStarts] = collect(keys(count_uniq))
        starts_data[:Frequency] = collect(values(count_uniq))
        sort!(starts_data)
    end
    return data, starts_data, overlapPer
end

function main(args)
    arg_parse_settings = ArgParseSettings(description="Calculates aligment metrics from bam flags")
    @add_arg_table arg_parse_settings begin
        "--bam", "-b"
            arg_type = String
            help = "Bam file."
            required = true
            dest_name = "bam"

        "--win", "-w"
            arg_type = Int64
            help = "Win size for starts bias"
            required = true
            dest_name = "win"

        "--out", "-o"
            arg_type = String
            help = "directory and file name as one string for aligment metrics."
            required = true
            dest_name = "outfile"

        "--bed", "-e"
            arg_type = String
            help = "exclude regions in bed for start bias calculaions"
            required = false
            dest_name = "bed"

        "--outstart", "-s"
            arg_type = String
            help = "directory and file name as one string for starts bias."
            required = true
            dest_name = "outstart"

        "--overlap-out", "-v"
            arg_type = String
            help = "directory and file name as one string."
            required = true
            dest_name = "overlap-out"

        "--single-end", "-g"
            arg_type = Bool
            help = "set true if single-end analysis is done."
            required = true
            dest_name = "is_se"

    end

    parsed_args = parse_args(arg_parse_settings)
    if parsed_args["bed"] == "None"
        parsed_args["bed"] = nothing
    end
    data, starts_data, overlapPer = bamcounter(parsed_args["bam"],parsed_args["win"], parsed_args["bed"], parsed_args["is_se"])
    wdframe(parsed_args["outfile"], data, ',')
    wdframe(parsed_args["outstart"], starts_data, ',')
    # Writing overlap data
    ovdata = DataFrame(Sample=String[], overlapPercent=Float64[])
    push!(ovdata, [splitext(basename(parsed_args["bam"]))[1], overlapPer])
    CSV.write(parsed_args["overlap-out"], ovdata, delim=',')

end

main(ARGS)

max_stars_repo_name: KarolisM/rnd-it-molbio-fidelity-umi

max_issues_repo_name: KarolisM/rnd-it-molbio-fidelity-umi

max_forks_repo_name: KarolisM/rnd-it-molbio-fidelity-umi


text:
module StructReinterpret

export struct_reinterpret, reinterpreted_getindex, reinterpreted_setindex!

include("utils.jl")
include("types.jl")

"""
    struct_reinterpret(::Type{StructType}, A::AbstractArray{T,N})

Returns an array of StructType's formed by contiguous values of A.
StructType must be a composite type whose fields are all of the same type of T.
The resulting array has the same values as that returned by `reinterpret`, but provides a faster `getindex` method.

# Examples
```jldoctest
julia> struct_reinterpret(NTuple{2,Int}, [1, 2, 3, 4, 5, 6])
3-element StructReinterpret.StructReinterpretArray{Tuple{Int64,Int64},1,Array{Int64,1}}:
 (1, 2)
 (3, 4)
 (5, 6)
```
"""
struct_reinterpret(T::Type,data::AbstractArray) = StructReinterpretArray(T,data)
struct_reinterpret(T::Type,data::DenseArray) = StructReinterpretDenseArray(T,data)

@generated function Base.size(a::AbstractReinterpretArray{ST,N,AT}) where {ST,N,AT}
    NF = myfieldcount(ST)
    ex = quote data = a.parent end
    t = Expr(:tuple)
    push!(t.args,:(div(size(data,1),$NF)))
    for i = 2:N
        push!(t.args,:(size(data,$i)))
    end
    push!(ex.args,t)
    return ex
end

Base.IndexStyle(::Type{<:AbstractReinterpretArray{ST,N,AT}}) where {ST,N,AT} = IndexStyle(AT)

@generated function reinterpreted_getindex(::Type{ST}, data::AbstractArray{T,N},i::Int) where {ST,T,N}
    NF = myfieldcount(ST)
    ex = Expr(:block)
    exarg = ex.args
    push!(exarg,Expr(:meta,:inline))
    push!(exarg,:(I=$NF*i))
    push!(exarg,:(@boundscheck checkbounds(data,I)))
    element = Expr(:new,ST)
    if is_tuple_wrapper(ST)
        push!(element.args,Expr(:tuple))
        struct_args = element.args[2].args
    else
        struct_args = element.args
    end
    for j in 1:(NF-1)
        push!(struct_args,:(@inbounds data[I-$(NF-j)]))
    end
    push!(struct_args,:(@inbounds data[I]))

    push!(exarg, element)
    return ex
end

@inline Base.@propagate_inbounds function Base.getindex(a::AbstractReinterpretArray{ST,N,AT}, i::Int) where {ST,N,AT}
    data = a.parent
    return reinterpreted_getindex(ST,data,i)
end

@generated function reinterpreted_getindex(::Type{ST}, data::AbstractArray{T,N},i::Vararg{Int,N}) where {ST,T,N}
    NF = myfieldcount(ST)
    ex = Expr(:block)
    exarg = ex.args
    push!(exarg,Expr(:meta,:inline))
    push!(exarg,:(I=$NF*i[1]))
    rest_of_indices = Vector{Any}()
    for j = 2:N
        push!(rest_of_indices,:(i[$j]))
    end
    push!(exarg,:(@boundscheck $(Expr(:call,:checkbounds,:data,:I,rest_of_indices...))))
    element = Expr(:new,ST)
    if is_tuple_wrapper(ST)
        push!(element.args,Expr(:tuple))
        struct_args = element.args[2].args
    else
        struct_args = element.args
    end
    for j in 1:(NF-1)
        push!(struct_args,:(@inbounds $(Expr(:call, :getindex, :data, :(I-$(NF-j)), rest_of_indices...))))
    end
    push!(struct_args,:(@inbounds $(Expr(:call, :getindex, :data, :I, rest_of_indices...))))

    push!(exarg, element)
    return ex
end

@inline Base.@propagate_inbounds function Base.getindex(a::AbstractReinterpretArray{ST,N,AT}, i::Vararg{Int,N}) where {ST,N,AT}
    data = a.parent
    return reinterpreted_getindex(ST,data,i...)
end

@generated function reinterpreted_setindex!(data::AbstractArray{T,N},::Type{ST},val,i::Int) where {ST,T,N}
    NF = myfieldcount(ST)
    ex = quote
        $(Expr(:meta,:inline))
        I=$NF*i
        @boundscheck checkbounds(data,I)
    end
    exarg = ex.args

    push!(exarg, is_tuple_wrapper(ST) ? :(val2 = getfield(convert($ST,val),1)) : :(val2 = convert($ST,val)))

    for j in 1:(NF-1)
        push!(exarg,:(@inbounds $(Expr(:call,:setindex!, :data, :(getfield(val2,$j)), :(I-$(NF-j))))))
    end
    push!(exarg,:(@inbounds $(Expr(:call,:setindex!, :data, :(getfield(val2,$NF)), :I))))

    return ex
end

@inline Base.@propagate_inbounds function Base.setindex!(a::AbstractReinterpretArray{ST,N,AT}, v,i::Int) where {ST,N,AT}
    data = a.parent
    reinterpreted_setindex!(data,ST,v,i)
    return a
end

@generated function reinterpreted_setindex!(data::AbstractArray{T,N},::Type{ST},val::VT,i::Vararg{Int,N}) where {ST,T,N,VT}
    NF = myfieldcount(ST)
    rest_of_indices = Vector{Any}()

    for j = 2:N
        push!(rest_of_indices,:(i[$j]))
    end

    ex = quote
        $(Expr(:meta,:inline))
        I=$NF*i[1]
        @boundscheck $(Expr(:call,:checkbounds,:data,:I,rest_of_indices...))
    end
    exarg = ex.args

    push!(exarg, is_tuple_wrapper(ST) ? :(val2 = getfield(convert($ST,val),1)) : :(val2 = convert($ST,val)))

    for j in 1:(NF-1)
        push!(exarg,:(@inbounds $(Expr(:call,:setindex!, :data, :(getfield(val2,$j)), :(I-$(NF-j)),rest_of_indices...))))
    end
    push!(exarg,:(@inbounds $(Expr(:call,:setindex!, :data, :(getfield(val2,$NF)), :I,rest_of_indices...))))

    return ex
end

@inline Base.@propagate_inbounds function Base.setindex!(a::AbstractReinterpretArray{ST,N,AT}, v,i::Vararg{Int,N}) where {ST,N,AT}
    data = a.parent
    reinterpreted_setindex!(data,ST,v,i...)
    return a
end

Base.unsafe_convert(::Type{Ptr{T}}, a::StructReinterpretDenseArray{T,N,A} where N) where {T,A} = Ptr{T}(pointer(a.parent))

end # module


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

using Markdown
using InteractiveUtils

# ╔═╡ b77c944b-88e4-421d-a629-0d96bf95ea70
begin
	using Pkg
	cd(joinpath(dirname(@__FILE__),".."))
    Pkg.activate(pwd())
	# Simulation packages
	using Distributions, HypothesisTests
	# Plotting packages
	using StatsPlots, LaTeXStrings, Measures
end

# ╔═╡ 86a87f27-7b57-4420-8cef-836ac531a254
# Make cells wider
html"""<style>
/*              screen size more than:                     and  less than:                     */
@media screen and (max-width: 699px) { /* Tablet */
  /* Nest everything into here */
    main { /* Same as before */
        max-width: 1200px !important; /* Same as before */
        margin-right: 100px !important; /* Same as before */
    } /* Same as before*/

}

@media screen and (min-width: 700px) and (max-width: 1199px) { /* Laptop*/
  /* Nest everything into here */
    main { /* Same as before */
        max-width: 1200px !important; /* Same as before */
        margin-right: 100px !important; /* Same as before */
    } /* Same as before*/
}

@media screen and (min-width:1000px) and (max-width: 1920px) { /* Desktop */
  /* Nest everything into here */
    main { /* Same as before */
        max-width: 1000px !important; /* Same as before */
        margin-right: 100px !important; /* Same as before */
    } /* Same as before*/
}

@media screen and (min-width:1921px) { /* Stadium */
  /* Nest everything into here */
    main { /* Same as before */
        max-width: 1200px !important; /* Same as before */
        margin-right: 100px !important; /* Same as before */
    } /* Same as before*/
}
</style>
"""

# ╔═╡ bcbed56c-0c94-11eb-0e8c-2de8d1a20f47
md"""

# Simulation - a small intro

## General approach
When a simulation is used to answer a question or to solve a problem, the following steps are involved:
* Formulate the problem and plan the study
* Collect the data and formulate the simulation model
* Check the accuracy of the simulation model (assumptions, limitations etc.)
* Construct a computer program
* Test the validity of the simulation model
* Plan the simulations to be performed
* Conduct the simulation runs and analyze the results
* Present the conclusions

During this practical session, we will run small simulations going over all these steps.

"""

# ╔═╡ 349b8586-0c96-11eb-2e7b-5b3230d1cf27
md"""
## Casino game
A casino offers a coin flipping game with the following rules:
1. Each play of the game involves repeatedly flipping an unbiased coin
2. The game stops when the difference between the number of heads tossed and the number of tails is 3
3. If you decide to play, each flip costs you € 1. You are not allowed to quit during a play of the game.
4. You receive € 8 at the end of each play of the game.

The problem at hand is to decide whether to play or not and to get an idea of the expected gains and the length of each game. We might also look into the required simulation size and into a parametric study (e.g. influence of the required difference between heads/tails and/or the default gain).

*Tip:* it can be analytically proven that the true mean of the number of flips required for a play of this game is 9.

##### Steps in the simulation process

###### Formulate the problem and plan the study:
the problem is described in a clear way (cf. suppra). Given these rules, we want to find out
1. if it is a good idea to play
2. the value of the expected profit

###### Collect the data and formulate the simulation model:
Let $X$ be the outcome of one coin flip $\Rightarrow X\sim \mathcal{Be}(1/2)$

###### Check the accuracy of the simulation model:
Our model is complete, we make no assumptions

###### Construct a computer program
"""

# ╔═╡ 3a20552e-0c97-11eb-3f0d-2586b1bb46ed
begin
	"""
		game(limit::Int=3)

	Play a game for a given limit. Returns a dict with the scores and the game length
	"""
	function game(limit::Int=3)
		d = Dict("heads"=>0, "tails"=>0, "length"=>0)
		while abs(d["heads"] - d["tails"]) < limit
			d["length"] += 1
			if rand()<=1/2
				d["heads"]+=1
			else
				d["tails"]+=1
			end
		end

		return d
	end

	"""
		sim(N::Int=1000; limit::Int=3)

	run a simulation of the game.
	"""
	function sim(N::Int=1000; limit::Int=3, gain::Real=8)
		L = Array{Int64,1}()
		G = Array{Int64,1}()
		for _ in 1:N
			g = game(limit)
			push!(L,g["length"])
			push!(G,gain - g["length"])
		end

		return L,G
	end

	nothing
end

# ╔═╡ b1bae776-0dfe-11eb-291b-53f9a87c4a41
# other method of creating a game
begin
	mutable struct Game
		heads::Int
		tails::Int
		length::Int
	end

	function play!(g::Game, limit::Int=3)
		while abs(g.heads - g.tails) < limit
			g.length += 1
			if rand()<=1/2
				g.heads += 1
			else
				g.tails += 1
			end

		end

		return g
	end

	g = Game(0,0,0)
	play!(g)
end

# ╔═╡ 65c6476c-0c98-11eb-2c7d-3bc3ba8d51e2
md"""
###### Test the validity of the simulation model
A game should stop when the difference between the amount of heads and tails equals 3
```julia
begin
	g = game()
	@assert abs(g["heads"] - g["tails"]) == 3
end
```
"""

# ╔═╡ 5b08b538-0c97-11eb-0319-877b39c4c4ed
md"""
###### Plan the simulations to be performed
We will run a certain number of simulations. At this time we do not have additional information that we can use (optimal number to be determined later).
"""

# ╔═╡ 607e4392-0c98-11eb-0a9d-ddfab6b42b26
md"""
###### Conduct the simulation runs and analyze the results
"""

# ╔═╡ 75d35828-0c99-11eb-1888-e9e7be234e89
begin
	# get data for game length and gains
	L,G = sim()
end;

# ╔═╡ fae1e448-0c98-11eb-3721-dddb169e403f
# show results
plot(histogram(L,xlabel="Game length"),histogram(G,xlabel="Gains"),
     label="",grid=false,ylabel="Frequency",size=(600,250) ,bottom_margin=5mm)

# ╔═╡ a39a3a72-0c99-11eb-00df-e92eb7a6ce07
plot([boxplot(L,ylabel="Game length", ylims=(0,maximum(L)+4)),
	  boxplot(G,ylabel="Gains")]...,
     label="",grid=false,size=(300,250),xaxis=false)

# ╔═╡ ac87cb8a-0c9a-11eb-21d5-9981e408db29
md"""
#### Simulation length
Up to now we have worked with a simulation length 1000. We have no idea about the variation of each simulation result. We investigate this in order to find out how simulation length impacts our estimate.
"""

# ╔═╡ 1aa54e8a-0c9b-11eb-3b7c-f3be005991df
begin
	# evolution of the mean in function of the sample length
	x = Array{Int,1}()
	y = Array{Float64,1}()
	ntests = 30
	for N in 10 .^(1:5)
		for _ in 1:ntests
			(L,_) = sim(N,limit=3)
			push!(x,N)
			push!(y,mean(L))
		end
	end
end

# ╔═╡ 3236977a-0c9b-11eb-3875-2304eaec0a8e
begin
	scatter(x,y,xscale=:log10,
			xlabel="Number of games per simulation",
			ylabel="Average game length",title="",label="")
	plot!(x,9*ones(size(x)),color=:red,label="")
	title!("Towards optimal simulation length\n (30 datapoints per config)")
end

# ╔═╡ 7fafde70-0c9c-11eb-0403-9bfb6e42045b
md"""
#### Parametric study
suppose we consider a range of differences [2,4] and a range of gains [4, 12] where we play 1e5 games for each config.
"""

# ╔═╡ c8b107ba-0c9d-11eb-11c7-830d112ca82f
let
	Δ = 1:5
	Γ = 0:15
	N = Int(1e5)
	res = []
	i = 1
	for d in Δ
		for g in Γ
			_,G = sim(N; limit=d, gain=g)
			push!(res, mean(G))
		end
	end
	blup = reshape(res,:,length(Δ))
	p1 = heatmap(Δ, Γ, blup, xlabel="diff", ylabel="guaranteed gain", title="mean gain")
	p2 = heatmap(Δ, Γ, blup .>= 0, xlabel="diff", ylabel="guaranteed gain", title="positive gain")
	plot(p1,p2, size=(600, 300))
end

# ╔═╡ 0bfa3ffe-0c9a-11eb-2c99-3d8e57983c4c
md"""
###### Present the conclusions
We find that on average a game takes 9 turns, which will lead you to lose on average € 1. The game could be tempting given that in six out of ten cases the player will actually win (a small amount).
"""

# ╔═╡ 8df49b7e-0c9e-11eb-0048-9368c9d7bee9
md"""
## Project management
Suppose we want to simulate a industrial process that can be presented as the table shown below:

| Activity | Predecessors | Completion time |
|----------|--------------|---------------- |
| A | - | $\sim \mathcal{N}(6,1)$ |
| B | A | $\sim \mathcal{U}(6,10)$ |
| C | A | $\sim \mathcal{U}(1.5,2.5)$ |
| D | B,C | $\sim \mathcal{U}(1.5,3)$ |
| E | D | $\sim \mathcal{U}(3,6)$ |
| F | E | $\sim \mathcal{U}(2,5)$ |
| G | E | $\sim \mathcal{U}(3,5)$ |
| H | F,G | $\sim \mathcal{U}(4,7)$ |
| I | H | $\sim \mathcal{U}(5,7)$ |
| J | H | $\le 5$ |

We want to get an idea of:
1. the mean project completion time
2. the probability that the project will be finished in less than 36 time units
3. determine the critical subprocesses with a sensitivity chart (i.e. determine the impact of changing a specific subprocess on the completion time given all the others remain the same)

"""

# ╔═╡ 7aceebea-0d1d-11eb-05fa-d7374004b881
md"""
###### Formulate the problem and plan the study
The problem and the tasks are described above

###### Collect the data and formulate the simulation Model
Data model (coming from historical data) is known. The duration can be obtained from the a vector of duration times.

###### Construct a computer program
"""

# ╔═╡ 8f99cf60-0c9e-11eb-2b6d-b5ca5ed20a65
begin
	# completion time distributions
	D = [Normal(6,1);
		Uniform(6,10);
		Uniform(1.5,2.5);
		Uniform(1.5,4);
		Uniform(3,6);
		Uniform(2,5);
		Uniform(3,5);
		Uniform(4,7);
		Uniform(5,7);
		Uniform(0,5)]

	# central positions (for sensitivity analysis)
	p = [6; 8; 2; 2.25; 4.5; 3.5; 4; 5.5; 6; 2.5]
	"""
		 duration(t::Array)

	generate a random sample from an array of distributions for the production process
	"""
	function duration(t::Array)
		t[1] + max(t[2],t[3]) + t[4] + t[5] + max(t[6], t[7]) + t[8] + max(t[9], t[10])
	end

	"""
		PM(N::Int)

	Run a Project Management simulation N times that returns a vector of duration times
	"""
	function PM(D::Array, N::Int=100)
		# Generate data
		S = [rand.(D) for _ in 1:N]
		# get durations
		return map(duration, S)
	end

	nothing;
end

# ╔═╡ 864b050c-0d1e-11eb-03d8-8ffcf23e019e
md"""
###### Check the accuracy of the simulation model (assumptions, limitations etc.)
We use a normal distribution for the first activity, so it is theoretically possible that a negative value for A occurs, which does not make sense. In a similar way, using a uniform distribution sets hard limits for task durations.

You can make testcases to assert the correctness of the result calculated by the duration function.
"""

# ╔═╡ f9562612-0d1e-11eb-1e16-bfa53760c18c
begin
	v = [0 0 1 0 0 1 0 0 0 0]
	@assert duration(v) ==  2
end

# ╔═╡ d18a68b2-0d20-11eb-0f39-150f9bc9e0e9
md"""
###### Plan the simulations to be performed
We will generate a sample of a given length an look at the experimental CDF.
"""

# ╔═╡ da7801bc-0ca0-11eb-0480-33f07e16c85b
let
	# idea mean value
	N = 1000; x = 36;
	res = PM(D,N)
	avg_D = mean(res)
	#  CDF
	p1 = StatsPlots.cdensity(res,label="Experimental CDF",legend=:bottomright)
	title!("P(X <= $(x)): $(sum(res .< x)/N)")

	plot!([avg_D; avg_D], [0; 1], line=:dash, label="mean duration $(round(avg_D,digits=2))")
	ylabel!("F_{X}(x) ")
	xlabel!("duration")
	# PDF
	p2 = StatsPlots.density(res, label="Experimental PDF")
	xlabel!("duration")
	ylabel!("f_{X}(x)")
	# total plot
	plot(p1, p2)
end

# ╔═╡ 3d5f9648-0d21-11eb-14c4-65704b349ed6
md"""
###### Conduct the simulation runs and analyze the results
We have obtained the results. We can do some additional testing such as validating the normality of our simulation data.

The sensitivity analysis can be done by changing one-factor-at-a-time (OAT), to see what effect this produces on the output. I.e. we move one input variable, keeping others at their baseline (nominal) values and repeat this for each of the other inputs in the same way.
"""

# ╔═╡ d8b821a0-0d21-11eb-08bc-f7027b1cbea1
begin
	s = PM(D,1000)
	HypothesisTests.ExactOneSampleKSTest(s,Normal(mean(s),std(s)))
end

# ╔═╡ d89eb800-0d21-11eb-29d9-c119c9347dbc
begin
	"""
		sensitivity(D, p, i::Int, N::Int=1000)

	Generate a sample where all values keep their baseline values with the exception of component i
	"""
	function sensitivity(D, p, i, N::Int=1000)
		# generate data
		data = [[p[1:i-1]; rand(D[i]); p[i+1:end]] for _ in 1:N]
		# return durations
		map(duration,data)
	end

	blup = [sensitivity(D,p, i) for i in 1:10]
	StatsPlots.boxplot(blup, label="")
	xlabel!("process step")
	ylabel!("duration boxplot")
	ylims!(30,40)
	xlims!(0,11)
	xticks!(collect(1:10))
	title!("Sensitivity analysis")
end

# ╔═╡ d148f3ea-0d21-11eb-2d67-f1f4c77248d5
md"""
###### Present the conclusions
With respect to the initial goals, we can conclude the following:
* the mean project completion time is around 37 time units
* the probability that the project will be finished in less than 36 time units is around 34%
* processes 3 and 10 do not impact the total project duration. Steps two and four account for the largest variability.
"""

# ╔═╡ Cell order:
# ╟─86a87f27-7b57-4420-8cef-836ac531a254
# ╠═b77c944b-88e4-421d-a629-0d96bf95ea70
# ╟─bcbed56c-0c94-11eb-0e8c-2de8d1a20f47
# ╟─349b8586-0c96-11eb-2e7b-5b3230d1cf27
# ╠═3a20552e-0c97-11eb-3f0d-2586b1bb46ed
# ╠═b1bae776-0dfe-11eb-291b-53f9a87c4a41
# ╟─65c6476c-0c98-11eb-2c7d-3bc3ba8d51e2
# ╟─5b08b538-0c97-11eb-0319-877b39c4c4ed
# ╟─607e4392-0c98-11eb-0a9d-ddfab6b42b26
# ╠═75d35828-0c99-11eb-1888-e9e7be234e89
# ╠═fae1e448-0c98-11eb-3721-dddb169e403f
# ╠═a39a3a72-0c99-11eb-00df-e92eb7a6ce07
# ╟─ac87cb8a-0c9a-11eb-21d5-9981e408db29
# ╠═1aa54e8a-0c9b-11eb-3b7c-f3be005991df
# ╠═3236977a-0c9b-11eb-3875-2304eaec0a8e
# ╟─7fafde70-0c9c-11eb-0403-9bfb6e42045b
# ╠═c8b107ba-0c9d-11eb-11c7-830d112ca82f
# ╟─0bfa3ffe-0c9a-11eb-2c99-3d8e57983c4c
# ╟─8df49b7e-0c9e-11eb-0048-9368c9d7bee9
# ╟─7aceebea-0d1d-11eb-05fa-d7374004b881
# ╠═8f99cf60-0c9e-11eb-2b6d-b5ca5ed20a65
# ╟─864b050c-0d1e-11eb-03d8-8ffcf23e019e
# ╠═f9562612-0d1e-11eb-1e16-bfa53760c18c
# ╟─d18a68b2-0d20-11eb-0f39-150f9bc9e0e9
# ╠═da7801bc-0ca0-11eb-0480-33f07e16c85b
# ╟─3d5f9648-0d21-11eb-14c4-65704b349ed6
# ╠═d8b821a0-0d21-11eb-08bc-f7027b1cbea1
# ╠═d89eb800-0d21-11eb-29d9-c119c9347dbc
# ╟─d148f3ea-0d21-11eb-2d67-f1f4c77248d5

max_stars_repo_path: Exercises/PS06 - Intro simulation.jl

max_issues_repo_path: Exercises/PS06 - Intro simulation.jl

max_forks_repo_path: Exercises/PS06 - Intro simulation.jl