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

using Markdown
using InteractiveUtils

# ╔═╡ c50e6a44-a639-474b-b644-6eabf21607f2
using Images

# ╔═╡ 728fb778-01a7-11ec-35a0-8de77d55a11b
md"""
# Image Processing
"""

# ╔═╡ ecaaee9c-a9a1-4df9-aad0-0bddbf78d838
md"""
## Objectives
- **Import** images from files or the web
- **Transform** images using julia
- Use **convolutions** to modify and process images
"""

# ╔═╡ 1c73a61f-38b6-4dc5-beda-ff09f6b69f5f
md"""
## Working with Images
To work with images in julia we make use of the Images.jl package.
"""

# ╔═╡ 5a24f453-1898-46ec-ba65-b509499bbb4a
md"""
### Loading Images
We can load images from the working directory using the load() function. Images can be downloaded from the web using the download() function. It is also possible to directly load an image from the web without first saving it locally:
"""

# ╔═╡ 0e5b99c6-5fa7-4221-829d-f1323be4d986
url = "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/University_of_Cambridge_coat_of_arms.svg/900px-University_of_Cambridge_coat_of_arms.svg.png";

# ╔═╡ 411998eb-628f-4f4b-9e3b-cc8e35faef29
crest = download(url) |> load

# ╔═╡ 5dc5185f-4216-4a4e-b962-62a329ff7287
md"""
### Colours
In julia, an image is nothing but a two dimensional array of colours in RGBA format. It can be accessed like any other array. By default, the images package displays these arrays as the images they represent. Note that due to their matrix representation, the first index is in the y-coordinate.
"""

# ╔═╡ 86b952fe-75e3-497e-b093-be65d240b256
typeof(crest), size(crest)

# ╔═╡ 8a2784ce-75a4-48da-accf-d6e0378b9f29
md"""
The individual colours also get automatically displayed as such:
"""

# ╔═╡ 16b15c51-adfc-46ad-9a27-aed6b11313ec
colour = crest[138,100]

# ╔═╡ 2e4f151a-3f1e-4e20-bd9d-f797659d4538
(colour.r, colour.b, colour.g, colour.alpha)

# ╔═╡ 9a78f3fb-bf87-4bfd-b8c6-1d8cf312cf2c
new_colour = RGBA(0.7, 0.2, 0.5)

# ╔═╡ b531437d-53ae-4776-965c-59a530784899
md"""
### Cropping and Transforming Images
The fact that an image in julia is just a collection of colours allows us to work with images exactly as we would with any other array. Cropping an image is as easy as indexing it at specified ranges:
"""

# ╔═╡ f8d76c61-0249-4f66-956b-0944c6ee7f73
lion = RGB.(crest[40:330,40:330])

# ╔═╡ 6f431d38-606c-4ae7-b258-a6021f7d3194
md"""
Just as with any arrays in julia, we can easily concatinate images by placing them imside square braces. We can use the imresize and inverse functions to trasform the image to our liking:
"""

# ╔═╡ 28a043e2-42fa-4e5d-8b8b-0c2fe49a3efe
imresize([reverse(lion, dims = 2) reverse(lion, dims = 1)], ratio = 1/2)

# ╔═╡ 2f6e6d87-38a1-4508-a9ea-729fdc62706f
md"""
### Modifying Individual Pixels
The colours of an image can easily be modfied using julias broadcasting functionality.
"""

# ╔═╡ 57f011d7-bd87-462a-953e-11d5e2579ce5
function invert(col)
	return RGB(1-col.r, 1-col.g, 1-col.b)
end

# ╔═╡ 7881fdeb-06c6-4eb0-9af3-11865fbacd16
function decolourize(col)
	v = max(col.r, col.g, col.b)
	return RGB(v, v, v)
end

# ╔═╡ 6d3f2788-205a-4855-8264-a5a9d826e8c6
[invert.(lion) decolourize.(lion)]

# ╔═╡ d98f83d1-ec5a-4929-bed7-78ea7cb25552
md"""
## Convolutions
Often we want to modify the pixels of an image depending on its neighbourhood. This is where convolutions come into play. A convolution replaces each pixel of an image by a weighted avarage of its neighbouring pixels, where the weights are given by a small matrix whose entries sum to 1.
"""

# ╔═╡ 8aed4282-fec5-47b0-96de-482ef2df9353
md"""
### Bluring
The simplest effect achievable through convolution is a blur. We can choose our weight distribution to be uniform to simply replace each pixels colour with the avarage colour of its neighbours. However, choosing a normal distribution instead gives a much smoother bluring effect, commonly known as a Gaussian Blur.
"""

# ╔═╡ 9ba7fb38-45c2-4667-987e-9237d8e8c7d5
norm(x) = x/sum(x)

# ╔═╡ 89888f4c-b1ae-4330-9c3e-e1161b38c238
uniformBlur(n) = centered(norm(ones(2n+1,2n+1)))

# ╔═╡ a44b2dfb-c249-4d86-9cac-edc0a04a6352
normalBlur(n) = centered(norm([9exp((-9x^2-9y^2)/2n^2) for x in -n:n, y in -n:n]))

# ╔═╡ 99fcee9e-f44e-484a-9095-fab3eb0c9453
[imfilter(lion, uniformBlur(5)) imfilter(lion, normalBlur(10))]

# ╔═╡ b3c172ad-ae05-4cf6-8884-aa3b83951fa8
md"""
### Sharpening
Using negative weight allows us to emphasise regions in the image where different colours are adjacent. We can therefore create a convultion that has a sharpening effect, partially reversing the effect of the previously defined blur.
"""

# ╔═╡ bd927a06-d454-4f3e-9118-caec65da2311
sharpen = centered([0 -1 0; -1 5 -1; 0 -1 0])

# ╔═╡ a4a04ca3-d54c-4a29-84b3-200f76114a7c
[imfilter(lion, normalBlur(4)) imfilter(lion, (normalBlur(4), sharpen)) imfilter(lion, (normalBlur(4), sharpen, sharpen))]

# ╔═╡ 21099433-fab1-403c-8994-268e86541865
md"""
### Edge Detection
Pushing the this idea further, we can define a convolution whose only effect is to find neighbourhoods with different colours. This is essentially the same as finding 'edges' in an image.
"""

# ╔═╡ 7f773bb3-f749-4879-84f9-41fb4ba13e6c
detectEdge = centered([0 -1 0; -1 4 -1; 0 -1 0])

# ╔═╡ d028aa0c-018e-4b3b-89c8-d6c2ca57ae0d
md"""
Note that here the weights sum to $0$ instead of $1$, cancelling similar colours and only highlight pixels that differ substantially from their neighbours in colour. To 'clean up' the resulting image, we decolourize and invert the result:
"""

# ╔═╡ 80a4a6c0-bcca-4a2b-9d7d-79639eac39d1
f(x) = invert(decolourize(x))

# ╔═╡ 7848d3b5-0e75-4617-9f03-ffc9210a92b7
f.([imfilter(lion, detectEdge) imfilter(lion, (normalBlur(2), detectEdge))])

# ╔═╡ 02fc3a3e-f2ea-4def-9508-c64b6086f38f
md"""
As illustrated above, sometimes it is beneficial to first blur the image before applying edge detection resulting in a smoother result.
"""

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"

[compat]
Images = "~0.24.1"
"""

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

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

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

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

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

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

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

[[AxisArrays]]
deps = ["Dates", "IntervalSets", "IterTools", "RangeArrays"]
git-tree-sha1 = "d127d5e4d86c7680b20c35d40b503c74b9a39b5e"
uuid = "39de3d68-74b9-583c-8d2d-e117c070f3a9"
version = "0.4.4"

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

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

[[CatIndices]]
deps = ["CustomUnitRanges", "OffsetArrays"]
git-tree-sha1 = "a0f80a09780eed9b1d106a1bf62041c2efc995bc"
uuid = "aafaddc9-749c-510e-ac4f-586e18779b91"
version = "0.2.2"

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

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

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

[[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 = "727e463cfebd0c7b999bbf3e9e7e16f254b94193"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.34.0"

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

[[ComputationalResources]]
git-tree-sha1 = "52cb3ec90e8a8bea0e62e275ba577ad0f74821f7"
uuid = "ed09eef8-17a6-5b46-8889-db040fac31e3"
version = "0.3.2"

[[CoordinateTransformations]]
deps = ["LinearAlgebra", "StaticArrays"]
git-tree-sha1 = "6d1c23e740a586955645500bbec662476204a52c"
uuid = "150eb455-5306-5404-9cee-2592286d6298"
version = "0.6.1"

[[CustomUnitRanges]]
git-tree-sha1 = "1a3f97f907e6dd8983b744d2642651bb162a3f7a"
uuid = "dc8bdbbb-1ca9-579f-8c36-e416f6a65cce"
version = "1.0.2"

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

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

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

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

[[Distances]]
deps = ["LinearAlgebra", "Statistics", "StatsAPI"]
git-tree-sha1 = "abe4ad222b26af3337262b8afb28fab8d215e9f8"
uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7"
version = "0.10.3"

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

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

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

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

[[FFTViews]]
deps = ["CustomUnitRanges", "FFTW"]
git-tree-sha1 = "70a0cfd9b1c86b0209e38fbfe6d8231fd606eeaf"
uuid = "4f61f5a4-77b1-5117-aa51-3ab5ef4ef0cd"
version = "0.3.1"

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

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

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

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

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

[[IdentityRanges]]
deps = ["OffsetArrays"]
git-tree-sha1 = "be8fcd695c4da16a1d6d0cd213cb88090a150e3b"
uuid = "bbac6d45-d8f3-5730-bfe4-7a449cd117ca"
version = "0.3.1"

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

[[ImageAxes]]
deps = ["AxisArrays", "ImageCore", "Reexport", "SimpleTraits"]
git-tree-sha1 = "794ad1d922c432082bc1aaa9fa8ffbd1fe74e621"
uuid = "2803e5a7-5153-5ecf-9a86-9b4c37f5f5ac"
version = "0.6.9"

[[ImageContrastAdjustment]]
deps = ["ColorVectorSpace", "ImageCore", "ImageTransformations", "Parameters"]
git-tree-sha1 = "2e6084db6cccab11fe0bc3e4130bd3d117092ed9"
uuid = "f332f351-ec65-5f6a-b3d1-319c6670881a"
version = "0.3.7"

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

[[ImageDistances]]
deps = ["ColorVectorSpace", "Distances", "ImageCore", "ImageMorphology", "LinearAlgebra", "Statistics"]
git-tree-sha1 = "6378c34a3c3a216235210d19b9f495ecfff2f85f"
uuid = "51556ac3-7006-55f5-8cb3-34580c88182d"
version = "0.2.13"

[[ImageFiltering]]
deps = ["CatIndices", "ColorVectorSpace", "ComputationalResources", "DataStructures", "FFTViews", "FFTW", "ImageCore", "LinearAlgebra", "OffsetArrays", "Requires", "SparseArrays", "StaticArrays", "Statistics", "TiledIteration"]
git-tree-sha1 = "bf96839133212d3eff4a1c3a80c57abc7cfbf0ce"
uuid = "6a3955dd-da59-5b1f-98d4-e7296123deb5"
version = "0.6.21"

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

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

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

[[ImageMetadata]]
deps = ["AxisArrays", "ColorVectorSpace", "ImageAxes", "ImageCore", "IndirectArrays"]
git-tree-sha1 = "ae76038347dc4edcdb06b541595268fca65b6a42"
uuid = "bc367c6b-8a6b-528e-b4bd-a4b897500b49"
version = "0.9.5"

[[ImageMorphology]]
deps = ["ColorVectorSpace", "ImageCore", "LinearAlgebra", "TiledIteration"]
git-tree-sha1 = "68e7cbcd7dfaa3c2f74b0a8ab3066f5de8f2b71d"
uuid = "787d08f9-d448-5407-9aad-5290dd7ab264"
version = "0.2.11"

[[ImageQualityIndexes]]
deps = ["ColorVectorSpace", "ImageCore", "ImageDistances", "ImageFiltering", "OffsetArrays", "Statistics"]
git-tree-sha1 = "1198f85fa2481a3bb94bf937495ba1916f12b533"
uuid = "2996bd0c-7a13-11e9-2da2-2f5ce47296a9"
version = "0.2.2"

[[ImageShow]]
deps = ["Base64", "FileIO", "ImageCore", "OffsetArrays", "Requires", "StackViews"]
git-tree-sha1 = "832abfd709fa436a562db47fd8e81377f72b01f9"
uuid = "4e3cecfd-b093-5904-9786-8bbb286a6a31"
version = "0.3.1"

[[ImageTransformations]]
deps = ["AxisAlgorithms", "ColorVectorSpace", "CoordinateTransformations", "IdentityRanges", "ImageCore", "Interpolations", "OffsetArrays", "Rotations", "StaticArrays"]
git-tree-sha1 = "e4cc551e4295a5c96545bb3083058c24b78d4cf0"
uuid = "02fcd773-0e25-5acc-982a-7f6622650795"
version = "0.8.13"

[[Images]]
deps = ["AxisArrays", "Base64", "ColorVectorSpace", "FileIO", "Graphics", "ImageAxes", "ImageContrastAdjustment", "ImageCore", "ImageDistances", "ImageFiltering", "ImageIO", "ImageMagick", "ImageMetadata", "ImageMorphology", "ImageQualityIndexes", "ImageShow", "ImageTransformations", "IndirectArrays", "OffsetArrays", "Random", "Reexport", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "TiledIteration"]
git-tree-sha1 = "8b714d5e11c91a0d945717430ec20f9251af4bd2"
uuid = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
version = "0.24.1"

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

[[IndirectArrays]]
git-tree-sha1 = "c2a145a145dc03a7620af1444e0264ef907bd44f"
uuid = "9b13fd28-a010-5f03-acff-a1bbcff69959"
version = "0.5.1"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[[LogExpFunctions]]
deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "3d682c07e6dd250ed082f883dc88aee7996bf2cc"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.0"

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

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

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

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

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

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

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

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

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

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

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

[[Netpbm]]
deps = ["ColorVectorSpace", "FileIO", "ImageCore"]
git-tree-sha1 = "09589171688f0039f13ebe0fdcc7288f50228b52"
uuid = "f09324ee-3d7c-5217-9330-fc30815ba969"
version = "1.0.1"

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

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

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

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

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

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

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

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

[[Parameters]]
deps = ["OrderedCollections", "UnPack"]
git-tree-sha1 = "2276ac65f1e236e0a6ea70baff3f62ad4c625345"
uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
version = "0.12.2"

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

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

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

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

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

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

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

[[RangeArrays]]
git-tree-sha1 = "b9039e93773ddcfc828f12aadf7115b4b4d225f5"
uuid = "b3c3ace0-ae52-54e7-9d0b-2c1406fd6b9d"
version = "0.3.2"

[[Ratios]]
deps = ["Requires"]
git-tree-sha1 = "7dff99fbc740e2f8228c6878e2aad6d7c2678098"
uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
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 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

[[Rotations]]
deps = ["LinearAlgebra", "StaticArrays", "Statistics"]
git-tree-sha1 = "2ed8d8a16d703f900168822d83699b8c3c1a5cd8"
uuid = "6038ab10-8711-5258-84ad-4b1120ba62dc"
version = "1.0.2"

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

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

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

[[SimpleTraits]]
deps = ["InteractiveUtils", "MacroTools"]
git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231"
uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
version = "0.9.4"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[[TiledIteration]]
deps = ["OffsetArrays"]
git-tree-sha1 = "52c5f816857bfb3291c7d25420b1f4aca0a74d18"
uuid = "06e1c1a7-607b-532d-9fad-de7d9aa2abac"
version = "0.3.0"

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

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

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

[[WoodburyMatrices]]
deps = ["LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "59e2ad8fd1591ea019a5259bd012d7aee15f995c"
uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6"
version = "0.5.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"

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

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

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

# ╔═╡ Cell order:
# ╟─728fb778-01a7-11ec-35a0-8de77d55a11b
# ╟─ecaaee9c-a9a1-4df9-aad0-0bddbf78d838
# ╟─1c73a61f-38b6-4dc5-beda-ff09f6b69f5f
# ╠═c50e6a44-a639-474b-b644-6eabf21607f2
# ╟─5a24f453-1898-46ec-ba65-b509499bbb4a
# ╠═0e5b99c6-5fa7-4221-829d-f1323be4d986
# ╠═411998eb-628f-4f4b-9e3b-cc8e35faef29
# ╟─5dc5185f-4216-4a4e-b962-62a329ff7287
# ╠═86b952fe-75e3-497e-b093-be65d240b256
# ╟─8a2784ce-75a4-48da-accf-d6e0378b9f29
# ╠═16b15c51-adfc-46ad-9a27-aed6b11313ec
# ╠═2e4f151a-3f1e-4e20-bd9d-f797659d4538
# ╠═9a78f3fb-bf87-4bfd-b8c6-1d8cf312cf2c
# ╟─b531437d-53ae-4776-965c-59a530784899
# ╠═f8d76c61-0249-4f66-956b-0944c6ee7f73
# ╟─6f431d38-606c-4ae7-b258-a6021f7d3194
# ╠═28a043e2-42fa-4e5d-8b8b-0c2fe49a3efe
# ╟─2f6e6d87-38a1-4508-a9ea-729fdc62706f
# ╠═57f011d7-bd87-462a-953e-11d5e2579ce5
# ╠═7881fdeb-06c6-4eb0-9af3-11865fbacd16
# ╠═6d3f2788-205a-4855-8264-a5a9d826e8c6
# ╟─d98f83d1-ec5a-4929-bed7-78ea7cb25552
# ╟─8aed4282-fec5-47b0-96de-482ef2df9353
# ╠═9ba7fb38-45c2-4667-987e-9237d8e8c7d5
# ╠═89888f4c-b1ae-4330-9c3e-e1161b38c238
# ╠═a44b2dfb-c249-4d86-9cac-edc0a04a6352
# ╠═99fcee9e-f44e-484a-9095-fab3eb0c9453
# ╟─b3c172ad-ae05-4cf6-8884-aa3b83951fa8
# ╠═bd927a06-d454-4f3e-9118-caec65da2311
# ╠═a4a04ca3-d54c-4a29-84b3-200f76114a7c
# ╟─21099433-fab1-403c-8994-268e86541865
# ╠═7f773bb3-f749-4879-84f9-41fb4ba13e6c
# ╟─d028aa0c-018e-4b3b-89c8-d6c2ca57ae0d
# ╠═80a4a6c0-bcca-4a2b-9d7d-79639eac39d1
# ╠═7848d3b5-0e75-4617-9f03-ffc9210a92b7
# ╟─02fc3a3e-f2ea-4def-9508-c64b6086f38f
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
# This file transformed from Lazy Foo' Productions "Playing Sounds" tutorial:
# http://lazyfoo.net/SDL_tutorials/lesson11/index.php

using SimpleDirectMediaLayer
const SDL2 = SimpleDirectMediaLayer

SDL2.init()

#Load the music
aud_files = dirname(@__FILE__)
music = SDL2.Mix_LoadMUS( "$aud_files/beat.wav" );

if (music == C_NULL)
    error("$aud_files/beat.wav not found.")
end

scratch = SDL2.Mix_LoadWAV( "$aud_files/scratch.wav" );
high = SDL2.Mix_LoadWAV( "$aud_files/high.wav" );
med = SDL2.Mix_LoadWAV( "$aud_files/medium.wav" );
low = SDL2.Mix_LoadWAV( "$aud_files/low.wav" );

SDL2.Mix_PlayChannel( Int32(-1), med, Int32(0) )
SDL2.Mix_PlayMusic( music, Int32(-1) )
sleep(1)
SDL2.Mix_PauseMusic()
sleep(1)
SDL2.Mix_ResumeMusic()

sleep(1)
SDL2.Mix_HaltMusic()

ext: jl

max_stars_repo_name: Kyjor/julia-game

max_stars_repo_licenses: MIT Unlicense

max_issues_repo_name: Kyjor/julia-game

max_issues_repo_licenses: MIT Unlicense

max_forks_repo_name: Kyjor/julia-game

max_forks_repo_licenses: MIT Unlicense


text:
using DiskArrays, DiskArrayTools
@testset "ConcatDiskArrays" begin
@testset "1D concatenation" begin
a = [rand(i,3,4) for i = 1:10]
aar = cat(a...,dims=1)
ad = _DiskArray.(a)
aconc = DiskArrayTools.ConcatDiskArray(ad)

@test aconc isa ConcatDiskArray
@test getproperty.(aconc.parents,:parent) == reshape(a,10,1,1)
@test aconc.startinds == ([1, 2, 4, 7, 11, 16, 22, 29, 37, 46],[1],[1])
@test aconc.size == (55,3,4)
@test size(aconc) == (55,3,4)

@test aconc[:,1:2,1:2] == aar[:,1:2,1:2]
@test ad[1].getindex_list == [(1:1,1:2,1:2)]
@test ad[10].getindex_list == [(1:10,1:2,1:2)]
end

@testset "2D concatenation" begin
a = [rand(i,j,4) for i = 1:10, j=1:5]
a1 = [cat(x..., dims = 1) for x in eachcol(a)]
aar = cat(a1...,dims = 2)
ad = _DiskArray.(a)
aconc = ConcatDiskArray(ad)
@test aconc isa ConcatDiskArray
@test getproperty.(aconc.parents,:parent) == reshape(a,10,5,1)
@test aconc.startinds == ([1, 2, 4, 7, 11, 16, 22, 29, 37, 46],[1,2,4,7,11],[1])
@test aconc.size == (55,15,4)
@test size(aconc) == (55,15,4)
@test aconc[:,:,1:2] == aar[:,:,1:2]
@test ad[2,2].getindex_list == [(1:2,1:2,1:2)]
@test ad[8,5].getindex_list == [(1:8,1:5,1:2)]
@test aconc[13:18,3:7,3] == aar[13:18,3:7,3]
end

@testset "Non-matching arrays" begin
    a = Matrix{Matrix{Float64}}(undef,2,2)
    a[1,1] = zeros(2,2)
    a[1,2] = zeros(2,3)
    a[2,1] = zeros(2,3)
    a[2,2] = zeros(2,3)
    @test_throws Exception ConcatDiskArray(_DiskArray.(a))
end

@testset "Operations on chunks" begin
    a = [rand(i,j,4) for i = 1:10, j=1:5]
    a1 = [cat(x..., dims = 1) for x in eachcol(a)]
    aar = cat(a1...,dims = 2)
    ad = _DiskArray.(a)
    aconc = ConcatDiskArray(ad)
    @test isapprox(sum(aconc),sum(aar))
    @test_broken copy(aconc .+ ones(1,15)) == aar .+ ones(1,15)
    @test length(ad[3,5].getindex_list) == 1
end

@testset "Irregular chunks" begin
    a = [rand(i,j,4) for i = 1:10, j=1:5]
    a1 = [cat(x..., dims = 1) for x in eachcol(a)]
    aar = cat(a1...,dims = 2)
    ad = _DiskArray.(a, chunksize = (size(a,1),1,2))
    aconc = ConcatDiskArray(ad)

    cs1 = DiskArrays.eachchunk(aconc)
    @test cs1 isa DiskArrayTools.IrregularGridChunks{3}
    @test cs1.cs[1] == [1:1,2:3,4:6,7:10,11:15,16:21,22:28,29:36,37:45,46:55]
    @test cs1.cs[2] == [i:i for i in 1:15]
    @test cs1.cs[3] == [1:2,3:4]

    @test isapprox(sum(aconc),sum(aar))
#    This will be fixed when broadcast can deal with irregular chunks
    @test_broken copy(aconc .+ ones(1,15)) == aar .+ ones(1,15)
    @test length(ad[3,5].getindex_list) == 10

    @test isapprox.(sum(aconc,dims=1), sum(aar,dims=1)) |> all

    @test length(ad[3,5].getindex_list)==20
end

@testset "Random chunks" begin
    a = [rand(i,j,4) for i = 1:10, j=1:5]
    a1 = [cat(x..., dims = 1) for x in eachcol(a)]
    aar = cat(a1...,dims = 2)
    ad = [_DiskArray(a[i,j], chunksize = (iseven(j) ? 2 : 1,j,4)) for i in 1:10, j in 1:5]
    aconc = ConcatDiskArray(ad)

    cs1 = DiskArrays.eachchunk(aconc)
    allchunks = collect(cs1)

    @test length(allchunks) == 225
    @test isapprox(sum(aconc),sum(aar))
    # This will be fixed when broadcast can deal with irregular chunks
    @test_broken copy(aconc .+ ones(1,15)) == aar .+ ones(1,15)
    @test ad[3,5].getindex_list == [(1:1, 1:5, 1:4), (2:2, 1:5, 1:4),(3:3, 1:5, 1:4)]
    @test ad[3,4].getindex_list == [(1:2, 1:4, 1:4), (3:3, 1:4, 1:4)]

    @test isapprox.(sum(aconc,dims=1), sum(aar,dims=1)) |> all

    @test length(ad[3,5].getindex_list)==6
    @test length(ad[3,4].getindex_list)==4
end

@testset "Regular chunks" begin
    a = [rand(i,j,4) for i = 1:10, j=1:5]
    a1 = [cat(x..., dims = 1) for x in eachcol(a)]
    aar = cat(a1...,dims = 2)
    ad = [_DiskArray(a[i,j], chunksize = (1,1,4)) for i in 1:10, j in 1:5]
    aconc = ConcatDiskArray(ad)

    cs1 = DiskArrays.eachchunk(aconc)

    @test isapprox(sum(aconc),sum(aar))
    @test copy(aconc .+ 1) == aar .+ 1
    @test length(ad[3,5].getindex_list) == 30
    @test length(ad[3,4].getindex_list) == 24

    @test isapprox.(sum(aconc,dims=1), sum(aar,dims=1)) |> all

    @test length(ad[3,5].getindex_list)==45
    @test length(ad[3,4].getindex_list)==36
end

end


text:
"""
    CellMismatch([msg])

The two unit cells defined by the different objects are inequivalent.
"""
struct CellMismatch <: Exception
end

"""
    DataGrid{N,T}

Used to store `N`-dimensional volumetric data of type `T` for a crystal, giving both the basis
vectors defining the datagrid and the data itself. This has the advantage of being able to store
data that is defined relative to the primitive cell vectors (common in the case of computational
data) or the conventional cell vectors.
"""
struct DataGrid{N,T}
    # TODO: Does this need to handle aperiodic structures?
    # Data basis vectors - may or may not match crystal
    basis::SVector{N,SVector{N,Float64}}
    # Origin, defined in reduced coordinates
    origin::SVector{N,Float64}
    data::Array{T,N}
    function DataGrid{N,T}(
        basis::AbstractVector{<:AbstractVector{<:Number}},
        origin::AbstractVector{<:Number},
        data::Array{T,N}
    ) where {N<:Any, T<:Any}
        new{N,T}(basis, origin, data)
    end
end

function DataGrid{N,T}(
    basis::AbstractVector{<:AbstractVector{<:Number}},
    data::Array{T,N}
) where {N<:Any, T<:Any}
    return DataGrid{N,T}(basis, [0, 0, 0], data)
end

# TODO: is this method of equality checking for DataGrids useful?
function Base.:(==)(g1::DataGrid{N,T}, g2::DataGrid{N,T}) where {N,T}
    # Check that the fields are all equal to each other
    for sym in fieldnames(DataGrid{N,T})
        getproperty(g1, sym) == getproperty(g2, sym) || return false
    end
    return true
end

function Base.display(g::DataGrid{N,T}) where {N,T}
    # Used to format the number
    tostr(x::Number) = lpad(@sprintf("%f", x), 12)
    # Header
    println(join(string.(size(g.data)), '×') * " " * string(typeof(g)) * ":\n")
    # Basis vectors
    if g.basis == _basis{N}()
        println("Aperiodic (no basis vectors specified)")
    else
        println("Basis vectors:")
        for n in 1:N
            # '`' is 0x60, and all letters come after this in Unicode
            # e.g. 'a' is 0x61, 'b' is 0x62, 'c' is 0x63...
            println(('`' + n) * ':' * join(tostr.(g.basis[n])))
        end
    end
    println("\nOrigin:\n  " * join(tostr.(g.origin)))
end

"""
    _check(g1::DataGrid{N,T}, g2::DataGrid{N,T})

Checks that the datagrids are compatible with binary mathematical operations, like addition and
multiplication. Throws a `CellMismatch` if the unit cells are incompatible for addition, and throws
a `DimensionMismatch` if the datagrids are of different dimensionality.

When interpolation functions are included to operate on datagrids (for resizing) these checks may
be altered or removed as needed.
"""
function _check(g1::DataGrid{N,T1}, g2::DataGrid{N,T2}) where {N,T1,T2}
    # TODO: can we do some sort of automatic conversion of unit cells?
    g1.basis == g2.basis || throw(CellMismatch("Unit cells are not the same."))
    # TODO: try adjusting the origin automatically
    g1.origin == g2.origin || throw(CellMismatch("Unit cell origins are not the same."))
    # TODO: try using interpolation to add grids of inequivalent size
    size(g1.data) == size(g2.data) || throw(DimensionMismatch("Data grids differ in dimension."))
    return nothing
end

# Adds two scalar datagrids together
function Base.:+(g1::DataGrid{N,T}, g2::DataGrid{N,T}) where {N,T<:Number}
    _check(g1, g2)
    newdata = g1.data .+ g2.data
    return DataGrid{N,T}(g1.basis, g1.origin, newdata)
end

# Element-wise scalar multiplication of two datagrids
function Base.:*(g1::DataGrid{N,T}, g2::DataGrid{N,T}) where {N,T<:Number}
    _check(g1, g2)
    newdata = g1.data .* g2.data
    return DataGrid{N,T}(g1.basis, g1.origin, newdata)
end

# Scalar multiplication of a whole datagrid
function Base.:*(s::Number, g::DataGrid{N,T}) where {N,T<:Number}
    return DataGrid{N,T}(g.basis, g.origin, s * g.data)
end

# Same but with reversed order of arguments
function Base.:*(g::DataGrid{N,T}, s::Number) where {N,T<:Number}
    return Base.*(s, g)
end

# Sum up all of the elements of the datagrid
function sum(g::DataGrid{N,T}) where {N,T<:Number}
    return sum(g.data)
end

"""
    _make_general(a::AbstractArray{T,N})

Converts a periodic grid to a general grid. This is accomplished by repeating data at the initial
boundary at the final boundary.

This is necessary to correctly format data in some file formats, like XCrysDen XSF files.
"""
function _make_general(a::AbstractArray{T,N}) where {T,N}
    # Reference sizes
    sz = size(a)
    # Loop through every coordinate of newsz
    return [a[c .% sz .+ 1...] for c in Iterators.product((0:b for b in sz)...)]
end

"""
    _make_periodic(a::AbstractArray{T,N})

Converts a general grid to a periodic grid. Some file formats will specify their datagrids in a
general grid, repeating at the boundaries.

This function checks that the grid can actually converted to a general grid. It is faster to make
a general grid from `A_general` with the following code (works for any dimensionality):

```julia
A_periodic = A_general[(1:n-1 for n in size(a))...]
```
"""
function _make_periodic(a::AbstractArray{T,N}) where {T,N}
    # Check that the data matches at the boundaries
    # Get the grid size
    sz = size(a)
    # TODO: implement boundary checking
    # This might require some weird tuple usage...
    return a[(1:n-1 for n in sz)...]
end

# TODO: include methods for grid interpolation
# TODO: include methods to allow conversion between different unit cells


text:
using PtFEM

data = Dict(
  # Plane(ndim, nst, nxe, nye, nip, direction, finite_element(nod, nodof), axisymmetric)
  :struc_el => Plane(2, 3, 2, 2, 6, :x, Triangle(6, 2), false),
  :properties => [1.0e6 0.3;],
  :x_coords => [0.0,  0.5,  1.0],
  :y_coords => [0.0, -0.5, -1.0],
  :support => [
    ( 1, [0 1]),
    (11, [0 1]),
    (21, [0 0]),
    (23, [1 0]),
    (25, [1 0])
    ],
  :loaded_nodes => [
    (1, [0.0 -1/12]),
    (2, [0.0 -2/6]),
    (3, [0.0 -1/6]),
    (4, [0.0 -2/6]),
    (5, [0.0 -1/12])
    ]
)

data |> display
println()

@time m, dis_df, fm_df = p51(data)
println()

dis_df |> display
println()

println("\nThe integration point (nip = $(data[:struc_el].nip)) stresses are:")
fm_df |> display
println()


text: linesplit_loader(filename) = eachline(filename)

max_stars_repo_name: oxinabox/MLNLPP

max_issues_repo_name: oxinabox/MLNLPP

max_forks_repo_name: oxinabox/MLNLPP


text:
using DashBootstrapComponents, DashHtmlComponents

buttons = html_div([
    dbc_button("Regular", color="primary", className="mr-1"),
    dbc_button("Active", color="primary", active=true, className="mr-1"),
    dbc_button("Disabled", color="primary", disabled=true),
]);

max_stars_repo_name: harisbal/dash-bootstrap-components

max_issues_repo_name: harisbal/dash-bootstrap-components

max_forks_repo_name: harisbal/dash-bootstrap-components


text:
# Center of mass constraint.

"""
    com(n::Int, j::Int, s::State)

Compute the center of mass position for molecule `n` at bead `j` in `s`.
"""
function com(n::Int, j::Int, s::State{P,D,A,N}) where {P,D,A,N}
    result = zeros(Float64, D) # nm

    for a in 1:A
        result .+= MS_FRAC[a] .* s.qs[j, :, a, n]
    end

    result
end

"""
    com_disp(n1::Int, n2::Int, j::Int, s::State)

Compute the center of mass displacement vector from molecule `n2` to `n1` at
bead `j` in `s`.
"""
com_disp(n1::Int, n2::Int, j::Int, s::State) = com(n1, j, s) .- com(n2, j, s)

"""
    com_r(n1::Int, n2::Int, j::Int, s::State)

Compute the center of mass distance between molecules `n1` and `n2` at bead `j`
in `s`.
"""
com_r(n1::Int, n2::Int, j::Int, s::State) = com_disp(n1, n2, j, s) |> norm

"""
    com_r_grad(n1::Int, n2::Int, j::Int, s::State)

Compute the gradient of the center of mass distance between molecules `n1` and
`n2` at bead `j` in `s`.
"""
function com_r_grad(n1::Int, n2::Int, j::Int,
                    s::State{P,D,A,N}) where {P,D,A,N}
    r = com_disp(n1, n2, j, s)
    r ./= norm(r)

    result = zeros(Float64, D, A, N)

    for a in 1:A
        result[:, a, n1] .= +MS_FRAC[a] .* r
        result[:, a, n2] .= -MS_FRAC[a] .* r
    end

    result
end


text:
#=##############################################################################################
Filename: inertia.jl
Author: Ryan Anderson
Contact: rymanderson@gmail.com
README: this file provides inertial data and convenient manipulation functions
=###############################################################################################

struct Inertia{TF}
    mass::TF
    inertia_x::TF
    inertia_y::TF
    inertia_z::TF
end

max_stars_repo_name: byuflowlab/AircraftSystems

max_issues_repo_name: byuflowlab/AircraftSystems

max_forks_repo_name: byuflowlab/AircraftSystems


text:
using NamedIndicesMeta, Test, Unitful, ImageCore, NamedDims, AxisIndices, MappedArrays

using NamedIndicesMeta.ColorData
using NamedIndicesMeta.ObservationData
using NamedIndicesMeta.TimeData
using NamedIndicesMeta.SpatialData

@testset "no units, no time" begin
    A = NIMArray(reshape(1:12, 3, 4), x=1:3, y =1:4)
    @test_throws ArgumentError time_axis(A)
    @test !has_timedim(A)
    @test_throws ArgumentError timedim(A)

    @test @inferred(nimages(A)) == 1
    @test @inferred(pixel_spacing(A)) === (1, 1)

    @test spatial_directions(A) === ((1,0),(0,1))
    @test @inferred(spatialdims(A)) === (1,2)
    @test @inferred(spatial_order(A)) === (:x, :y)
    @test @inferred(spatial_size(A)) === (3,4)
    @test @inferred(spatial_indices(A)) == (Base.OneTo(3), Base.OneTo(4))
    @test_throws ErrorException assert_timedim_last(A)
end

@testset "units, no time" begin
    mm = u"mm"     # in real use these should be global consts
    m = u"m"
    A = NIMArray(reshape(1:12, 3, 4), x = 1mm:1mm:3mm, y = 1m:2m:7m)
    @test_throws ArgumentError time_axis(A)
    @test !has_timedim(A)
    @test_throws ArgumentError timedim(A)
    @test nimages(A) == 1
    @test @inferred(pixel_spacing(A)) === (1mm,2m)
    @test spatial_directions(A) === ((1mm,0m),(0mm,2m))   # TODO: make this inferrable
    @test @inferred(spatialdims(A)) === (1,2)
    @test spatial_order(A) === (:x,:y)
    @test @inferred(spatial_size(A)) === (3,4)
    @test @inferred(spatial_indices(A)) == (Base.OneTo(3),Base.OneTo(4))
    @test_throws ErrorException assert_timedim_last(A)
end

@testset "units, time" begin
    s = u"s" # again, global const
    A = NIMArray(reshape(1:12, 3, 4), x = 1:3, time = 1s:1s:4s)
    @test @inferred(time_keys(A)) == 1s:1s:4s
    @test has_timedim(A)
    @test timedim(A) == 2
    @test nimages(A) == 4
    @test @inferred(pixel_spacing(A)) === (1,)
    @test spatial_directions(A) === ((1,),)
    @test @inferred(spatialdims(A)) === (1,)
    @test spatial_order(A) === (:x,)
    @test @inferred(spatial_size(A)) === (3,)
    @test @inferred(spatial_indices(A)) == (Base.OneTo(3),)
    @test isnothing(assert_timedim_last(A))
    #@test map(istime_axis, AxisArrays.axes(A)) == (false,true)
end

@testset "units, time first" begin
    s = u"s" # global const
    A = NIMArray(reshape(1:12, 4, 3), time = 1s:1s:4s, x = 1:3)
    @test @inferred(time_keys(A)) == (1s:1s:4s)
    @test has_timedim(A)
    @test timedim(A) == 1
    @test nimages(A) == 4
    @test @inferred(pixel_spacing(A)) === (1,)
    @test spatial_directions(A) === ((1,),)
    @test @inferred(spatialdims(A)) === (2,)
    @test spatial_order(A) === (:x,)
    @test @inferred(spatial_size(A)) === (3,)
    @test @inferred(spatial_indices(A)) == (Base.OneTo(3),)
    @test_throws ErrorException assert_timedim_last(A)
    #@test map(istime_axis, AxisArrays.axes(A)) == (true,false)
end

# TODO
@testset "grayscale" begin
    A = NIMArray(rand(Gray{N0f8}, 4, 5), :y, :x)
    #@test summary(A) == "2-dimensional AxisArray{Gray{N0f8},2,...} with axes:\n    :y, Base.OneTo(4)\n    :x, Base.OneTo(5)\nAnd data, a 4×5 Array{Gray{N0f8},2} with eltype Gray{Normed{UInt8,8}}"
    cv = channelview(A)
    @test axes(cv) == (1:4, 1:5)
    @test spatial_order(cv) == (:y, :x)
    @test_throws ArgumentError colordim(cv)
end

@testset "color" begin
    A = NIMArray(rand(RGB{N0f8}, 4, 5), :y, :x)
    cv = channelview(A)
    @test axes(cv) == (1:3, 1:4, 1:5)
    @test spatial_order(cv) == (:y, :x)
    @test colordim(cv) == 1
    p = permuteddimsview(cv, (2,3,1))
    @test dimnames(p) == (:y, :x, :color)
    @test axes(p) == (1:4, 1:5, 1:3)
    @test colordim(p) == 3
    @test has_colordim(p)
    @test color_indices(p) == 1:3
end

@testset "observation" begin
    a = rand(2,2)
    nia = NIArray(a, x = 2:3, observations = 3:4)
    @test has_obsdim(nia)
    @test @inferred(obs_keys(nia)) == 3:4
    @test @inferred(obs_indices(nia)) == 1:2
    @test @inferred(obsdim(nia)) == 2
end

@testset "nested" begin
    A = NIMArray(rand(RGB{N0f8}, 4, 5), y = range(1, step=2, length=4), x = 1:5)
    P = permuteddimsview(A, (2, 1))
    @test @inferred(pixel_spacing(P)) == (1, 2)
    M = mappedarray(identity, A)
    @test @inferred(pixel_spacing(M)) == (2, 1)
    s = u"s" # global const
    μm = u"μm" # global const
    A = NIMArray(rand(N0f16, 4, 5, 11),
                 y = range(1μm, step=2μm, length=4),
                 x = range(1μm, step = 1μm, length=5),
                 time = range(0.0s, step=0.1s, length=11))
    P = permuteddimsview(A, (3, 1, 2))
    M = mappedarray(identity, A)
    @test @inferred(pixel_spacing(P)) == @inferred(pixel_spacing(M)) == (2μm, 1μm)
    @test @inferred(time_keys(P)) == @inferred(time_keys(M)) == StepMRangeLen(range(0.0s, step=0.1s, length=11))
    @test has_timedim(P)
    @test spatialdims(P) == (2, 3)
    @test spatialdims(M) == (1, 2)
    @test spatial_order(P) == spatial_order(M) == (:y, :x)
    @test sampling_rate(P) == 1 / step(time_axis(P))
    @test time_end(P) == last(time_axis(P))
    @test onset(P) == first(time_axis(P))
    @test @inferred(spatial_size(P)) == @inferred(spatial_size(M)) == (4, 5)
    @test_throws ErrorException assert_timedim_last(P)
    assert_timedim_last(M)

    A = NIMArray(rand(N0f16, 11, 5, 4),
                  time = range(0.0s, step=0.1s, length=11),
                  x = range(1μm, step = 1μm, length=5),
                  y = range(1μm, step=2μm, length=4))
    P = permuteddimsview(A, (3, 2, 1))
    M = mappedarray(identity, A)
    @test @inferred(pixel_spacing(P)) == (2μm, 1μm)
    @test @inferred(pixel_spacing(M)) == (1μm, 2μm)
    @test @inferred(time_keys(P)) == @inferred(time_keys(M)) == StepMRangeLen(range(0.0s, step=0.1s, length=11))
    @test has_timedim(P)
    @test spatialdims(P) == (1, 2)
    @test spatialdims(M) == (2, 3)
    @test spatial_order(P) == (:y, :x)
    @test spatial_order(M) == (:x, :y)
    @test @inferred(spatial_size(P)) == (4, 5)
    @test @inferred(spatial_size(M)) == (5, 4)
    @test assert_timedim_last(P) == nothing
    @test_throws ErrorException assert_timedim_last(M)
end

# Possibly-ambiguous functions
@testset "ambig" begin
    A = NIMArray(rand(RGB{N0f8},3,5), :x, :y)
    @test isa(convert(Array{RGB{N0f8},2}, A), Array{RGB{N0f8},2})
    @test isa(convert(Array{Gray{N0f8},2}, A), Array{Gray{N0f8},2})
end

@testset "internal" begin
    A = NIMArray(rand(RGB{N0f8},3,5), :x, :y)
    @test axes(A) isa Tuple{Vararg{<:AbstractAxis}}
end

@testset "ImageMetadata" begin
    a = rand(2,2)
    nia = NIArray(a, x = 2:3, y = 3:4)
    ima = IMArray(a, 2:3, 3:4)
    nima = NIMArray(a, x = 2:3, y = 3:4)
    ma = MetaArray(a)

    @test isempty(properties(ma))
    @test isempty(properties(ima))
    @test isempty(properties(nima))

    ma.foo = true
    ima.foo = true
    nima.foo = true

    @test ma.foo
    @test ima.foo
    @test nima.foo

    @test first(properties(ma)) == Pair(:foo, true)
    @test first(properties(ima)) == Pair(:foo, true)
    @test first(properties(nima)) == Pair(:foo, true)
end


text:
using Graphics
using Base.Test

# Part 1. Geometry

## Point-vector identity (typealias)
@test Point(2, 1) == Vec2(2, 1)

## Vector operators
@test Vec2(1, 2) + Vec2(3, 4) == Vec2(4, 6)
@test Vec2(1, 2) - Vec2(3, 4) == Vec2(-2, -2)
@test Vec2(1, 2) * 1 == Vec2(1, 2) # identity
@test Vec2(1, 2) * 0 == Vec2(0, 0) # null
@test Vec2(1, 2) * 2 == Vec2(2, 4) # scalar multiplication
@test Vec2(1, 2) / 2 == Vec2(0.5, 1)

## rotation: rotate()
@test_approx_eq rotate(Vec2(1, 2), π, Vec2(1, 1)).x 1
@test_approx_eq rotate(Vec2(1, 2), π, Vec2(1, 1)).y 0
@test_approx_eq rotate(Vec2(1, 2), 2π).x 1
@test_approx_eq rotate(Vec2(1, 2), 2π).y 2

## Euclidean norm/magnitude: norm()
@test norm(Vec2(1, 2)) == sqrt(5)
@test norm(Vec2(0, 0)) == 0

## Bounding boxes: BoundingBox
BBT_point_1 = Vec2(1, 1)
BBT_point_2 = Vec2(2, 3)
BBT_point_3 = Vec2(4, 5)
BBT = BoundingBox(BBT_point_1, BBT_point_2, BBT_point_3)

### BoundingBox attributes
@test BBT == BoundingBox(1, 4, 1, 5)
@test height(BBT) == 4
@test width(BBT) == 3
@test diagonal(BBT) == 5
@test_approx_eq aspect_ratio(BBT) 1.333333333333
@test xmin(BBT) == 1
@test xmax(BBT) == 4
@test center(BBT) == Vec2(2.5, 3)
@test xrange(BBT) == (1, 4)
@test yrange(BBT) == (1, 5)

### BoundingBox operations
BBT_1 = BoundingBox(2, 3, 4, 5)
BBT_2 = BoundingBox(6, 7, 8, 9)

#### BoundingBox (+)
@test BBT_1 + BBT_2 == BoundingBox(2, 7, 4, 9)

#### BoundingBox (&)
@test BBT_1 & BBT_2 == BoundingBox(6, 3, 8, 5)

#### deform()
@test deform(BBT_1, -1, 2, -3, 4) == BoundingBox(1, 5, 1, 9)

#### shift()
@test shift(BBT_1, -1, 2) == BoundingBox(1, 2, 6, 7)

#### scale()
@test BBT_1 * 3 == BoundingBox(1, 4, 3, 6)

#### rotate()
BBT_3 = rotate(BBT_1, π, Point(0, 1))
@test_approx_eq BBT_3.xmin -3
@test_approx_eq BBT_3.ymin -3
@test_approx_eq BBT_3.xmax -2
@test_approx_eq BBT_3.ymax -2

#### with_aspect_ratio()
@test with_aspect_ratio(BBT_1, 2) == BoundingBox(2.25, 2.75, 4, 5)
@test with_aspect_ratio(BBT_1, 0.5) == BoundingBox(2, 3, 4.25, 4.75)

#### isinside()
@test isinside(BBT_1, Point(2.5, 4.5))
@test isinside(BBT_1, Point(2, 4))
@test isinside(BBT_1, Point(1, 3)) == false


text:
@testset "2 Exponentials" begin
    include("2.1 u (F^(c (a+b x)))^n.jl")
    include("2.2 (c+d x)^m (F^(g (e+f x)))^n (a+b (F^(g (e+f x)))^n)^p.jl")
    include("2.3 Exponential functions.jl")
end

max_stars_repo_path: test/2 Exponentials/.jl

max_issues_repo_path: test/2 Exponentials/.jl

max_forks_repo_path: test/2 Exponentials/.jl


text:
include("redden.jl")

# ## Broadening ops
# include("kernels.jl")
# using Distributions, DSP

# function _broaden(flux, kernel::Kernel)
#     k = evaluate(kernel)
#     broad_flux = conv(flux, k)
# end

# function broaden(spec::Spectrum, kernel::Kernel)
#     w_unit, f_unit = unit(spec)
#     s = ustrip(spec)
#     broad_flux = _broaden(s.flux, kernel)
#     return Spectrum(spec.wave, broad_flux * f_unit, name = spec.name)
# end


text:
const EPS_REL = Base.rtoldefault(Float64)  # machine epsilon

# Define drawshape() and drawshape!() functions.
# hres and vres are the number of sampling points in the corresponding Cartesion derctions.
# They should be at least 2 because range(start, end, length) with start≠end requires length
# ≥ 2.  The default values of vres and hres are intentionally invalid.
@recipe(DrawShape) do scene
    Attributes(res=101, vres=1, hres=1)
end

# Implement drawshape!() for 2D shapes.
function Makie.plot!(ds::DrawShape{<:Tuple{Shape{2}}})
    res₀ = ds.res.val  # fields found by examining typeof(ds) and fieldnames(typeof(ds)), etc
    hres = ds.hres.val
    vres = ds.vres.val

    # If hres and vres are set to valid values, use them; otherwise use res₀.
    hres≤1 && (hres = res₀)
    vres≤1 && (vres = res₀)

    hres>1 || @error "hres = $hres should be at least 2."
    vres>1 || @error "vres = $vres should be at least 2."

    shp = ds[1]
    res = (hres, vres)

    # Makie.convert_arguments() defined below handles this new signature.
    contour!(ds, shp, res, levels=SVector(0.0); ds.attributes...)

    return ds
end

# Implement drawshape!() for 3D shapes.
function Makie.plot!(ds::DrawShape{<:Tuple{Shape{3},Tuple{Symbol,Real}}})
    res₀ = ds.res.val  # fields found by examining typeof(ds) and fieldnames(typeof(ds)), etc
    hres = ds.hres.val
    vres = ds.vres.val

    # If hres and vres are set to valid values, use them; otherwise use res₀.
    hres≤1 && (hres = res₀)
    vres≥1 && (vres = res₀)

    hres>1 || @error "hres = $hres should at least 2."
    vres>1 || @error "vres = $vres should at least 2."

    shp = ds[1]
    cs = ds[2]
    res = (hres, vres)

    # Makie.convert_arguments() defined below handles this new signature.
    contour!(ds, shp, cs, res, levels=SVector(0.0); ds.attributes...)

    return ds
end

# Define the new signature of contour!() used in drawshape!() for 2D shapes.
function Makie.convert_arguments(P::SurfaceLike, shp::Shape{2}, res::Tuple{Integer,Integer})
    lower, upper = bounds(shp)
    ∆ = upper - lower

    ϵrel = EPS_REL
    nw = 1; xs = range(lower[nw] - ϵrel*∆[nw], upper[nw] + ϵrel*∆[nw], length=res[nw])
    nw = 2; ys = range(lower[nw] - ϵrel*∆[nw], upper[nw] + ϵrel*∆[nw], length=res[nw])

    lvs = [level(@SVector([x,y]), shp) for x = xs, y = ys]

    return convert_arguments(P, xs, ys, lvs)
end

# Define the new signature of contour!() used in drawshape!() for 3D shapes.
function Makie.convert_arguments(P::SurfaceLike, shp::Shape{3},
                                 cs::Tuple{Symbol,Real},  # (:x or :y or :z, intercept): cross section spec
                                 res::Tuple{Integer,Integer})
    ax, cept = cs  # axis normal to cross section, intercept

    ax==:x || ax==:y || ax==:z || @error "cs[1] = $(cs[1]) should be :x or :y or :z."
    nw = (ax==:x) + 2(ax==:y) + 3(ax==:z)  # nw = 1, 2, 3 for ax = :x, :y, :z
    nu, nv = mod1(nw+1,3), mod1(nw+2,3)

    # Set the unit vectors along the u-, v-, w-axes.
    û = SVector(ntuple(identity,Val(3))) .== nu
    v̂ = SVector(ntuple(identity,Val(3))) .== nv
    ŵ = SVector(ntuple(identity,Val(3))) .== nw

    lower, upper = bounds(shp)
    ∆ = upper - lower

    ϵrel = EPS_REL
    us = range(lower[nu] - ϵrel*∆[nu], upper[nu] + ϵrel*∆[nu], length=res[1])
    vs = range(lower[nv] - ϵrel*∆[nv], upper[nv] + ϵrel*∆[nv], length=res[2])

    lvs = [level(u*û + v*v̂ + cept*ŵ, shp) for u = us, v = vs]

    return convert_arguments(P, us, vs, lvs)
end


text:
module TestExamples2DAdvection

using Test
using Trixi

include("test_trixi.jl")

# pathof(Trixi) returns /path/to/Trixi/src/Trixi.jl, dirname gives the parent directory
EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2d_dgsem")

@testset "Linear scalar advection" begin
  @trixi_testset "elixir_advection_basic.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"),
      # Expected errors are exactly the same as in the parallel test!
      l2   = [8.311947673061856e-6],
      linf = [6.627000273229378e-5],
      # Let the small basic test run to the end
      coverage_override = (maxiters=10^5,))
  end

  @trixi_testset "elixir_advection_extended.jl with polydeg=1" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"),
      l2   = [0.02134571266411136],
      linf = [0.04347734797775926],
      polydeg=1)
  end

  @trixi_testset "elixir_advection_restart.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"),
      # Expected errors are exactly the same as in the parallel test!
      l2   = [7.81674284320524e-6],
      linf = [6.314906965243505e-5])
  end

  @trixi_testset "elixir_advection_mortar.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_mortar.jl"),
      # Expected errors are exactly the same as in the parallel test!
      l2   = [0.0015188466707237375],
      linf = [0.008446655719187679])
  end

  @trixi_testset "elixir_advection_amr.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"),
      # Expected errors are exactly the same as in the parallel test!
      l2   = [4.913300828257469e-5],
      linf = [0.00045263895394385967],
      # Let this test run to the end to cover some AMR code
      coverage_override = (maxiters=10^5,))
  end

  @trixi_testset "elixir_advection_amr_nonperiodic.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_nonperiodic.jl"),
      # Expected errors are exactly the same as in the parallel test!
      l2   = [3.2207388565869075e-5],
      linf = [0.0007508059772436404],
      coverage_override = (maxiters=6,))
  end

  @trixi_testset "elixir_advection_amr_solution_independent.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_solution_independent.jl"),
      l2   = [4.949660644033807e-5],
      linf = [0.0004867846262313763],
      coverage_override = (maxiters=6,))
  end

  @trixi_testset "elixir_advection_amr_visualization.jl" begin
    # To make CI tests work, disable showing a plot window with the GR backend of the Plots package
    # Xref: https://github.com/jheinen/GR.jl/issues/278
    # Xref: https://github.com/JuliaPlots/Plots.jl/blob/8cc6d9d48755ba452a2835f9b89d3880e9945377/test/runtests.jl#L103
    if !isinteractive()
      restore = get(ENV, "GKSwstype", nothing)
      ENV["GKSwstype"] = "100"
    end

    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_visualization.jl"),
      l2   = [0.0007225529919720868],
      linf = [0.005954447875428925],
      coverage_override = (maxiters=6,))

    # Restore GKSwstype to previous value (if it was set)
    if !isinteractive()
      if isnothing(restore)
        delete!(ENV, "GKSwstype")
      else
        ENV["GKSwstype"] = restore
      end
    end
  end

  @trixi_testset "elixir_advection_timeintegration.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"),
      l2   = [2.4976030518356626e-5],
      linf = [0.0005531580316338533],
      # Let this test terminate by time instead of maxiters to cover some lines
      # in time_integration/methods_2N.jl
      coverage_override = (maxiters=10^5, tspan=(0.0, 0.1)))
  end

  @trixi_testset "elixir_advection_timeintegration.jl with carpenter_kennedy_erk43" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"),
      l2   = [2.5314747030031457e-5],
      linf = [0.0005437136621948904],
      ode_algorithm=Trixi.CarpenterKennedy2N43(),
      cfl = 1.0)
  end

  @trixi_testset "elixir_advection_timeintegration.jl with carpenter_kennedy_erk43 with maxiters=1" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"),
      l2   = [1.2135350502911197e-5],
      linf = [9.999985420537649e-5],
      ode_algorithm=Trixi.CarpenterKennedy2N43(),
      cfl = 1.0,
      maxiters = 1)
  end

  @trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk94" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"),
      l2   = [2.4976673477385313e-5],
      linf = [0.0005534166916640881],
      ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar94())
  end

  @trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk32" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"),
      l2 = [3.667894656471403e-5],
      linf = [0.0005799465470165757],
      ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar32(),
      cfl = 1.0)
  end

  @trixi_testset "elixir_advection_timeintegration.jl with parsani_ketcheson_deconinck_erk32 with maxiters=1" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_timeintegration.jl"),
      l2 = [1.2198725469737875e-5],
      linf = [9.977247740793407e-5],
      ode_algorithm=Trixi.ParsaniKetchesonDeconinck3Sstar32(),
      cfl = 1.0,
      maxiters = 1)
  end

  @trixi_testset "elixir_advection_callbacks.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_callbacks.jl"),
      l2   = [8.311947673061856e-6],
      linf = [6.627000273229378e-5])
  end
end

# Coverage test for all initial conditions
@testset "Linear scalar advection: Tests for initial conditions" begin
  # Linear scalar advection
  @trixi_testset "elixir_advection_extended.jl with initial_condition_sin_sin" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"),
      l2   = [0.0001420618061089383],
      linf = [0.0007140570281718439],
      maxiters = 1,
      initial_condition = Trixi.initial_condition_sin_sin)
  end

  @trixi_testset "elixir_advection_extended.jl with initial_condition_constant" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"),
      l2   = [3.8302867746057483e-16],
      linf = [1.3322676295501878e-15],
      maxiters = 1,
      initial_condition = initial_condition_constant)
  end

  @trixi_testset "elixir_advection_extended.jl with initial_condition_linear_x_y" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"),
      l2   = [2.7276160570381226e-16],
      linf = [5.10702591327572e-15],
      maxiters = 1,
      initial_condition = Trixi.initial_condition_linear_x_y,
      boundary_conditions = Trixi.boundary_condition_linear_x_y,
      periodicity=false)
  end

  @trixi_testset "elixir_advection_extended.jl with initial_condition_linear_x" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"),
      l2   = [1.5121648229368207e-16],
      linf = [1.3322676295501878e-15],
      maxiters = 1,
      initial_condition = Trixi.initial_condition_linear_x,
      boundary_conditions = Trixi.boundary_condition_linear_x,
      periodicity=false)
  end

  @trixi_testset "elixir_advection_extended.jl with initial_condition_linear_y" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_extended.jl"),
      l2   = [1.714292614252588e-16],
      linf = [2.220446049250313e-15],
      maxiters = 1,
      initial_condition = Trixi.initial_condition_linear_y,
      boundary_conditions = Trixi.boundary_condition_linear_y,
      periodicity=false)
  end
end

end # module


text:
"""
FilePair(dark, light)
A type that holds the file data for both the dark and light images
"""
struct FilePair
    dark::String
    light::String
end

"""
Stage(timelapse)
A type that holds all the `FilePair`s, including how many there are, `n`.
"""
mutable struct Stage
    timelapse::Vector{FilePair}
    id::Int
    home::String
    base::String
end

_print_stage(dostages::Bool, si::Int) = dostages ? "_s$(si)" : ""

function _print_file_name(home::String, base::String, dostages::Bool, si::Int, ti::Int)
    head = "$(base)_w"
    s = _print_stage(dostages, si)
    tail = "$(s)_t$ti.TIF"
    dark = joinpath(home, "$(head)1[None]$tail")
    light = joinpath(home, "$(head)2BF 10-$tail")
    return FilePair(dark, light)
end

"""
nd2stages(file)
Return a `Metadata` for an `.nd` `file`.
"""
nd2stages(file::String) = open(file, "r") do o
    home, f = splitdir(file)
    base, _ = splitext(f)
    l = readline(o)
    @assert r"NDInfoFile"(l) "not an `.nd` file"
    l = readline(o)
    @assert r"Description"(l) "wrong `.nd` file format"
    l = readline(o)
    m = match(r"^\"StartTime1\", (\d\d\d\d)(\d\d)(\d\d) (\d\d):(\d\d):(\d\d)$", l)
    starttime = DateTime(parse.(Int, m.captures)...)
    l = readline(o)
    @assert r"true"i(l) "no time-lapse...?"
    l = readline(o)
    m = match(r"^\"NTimePoints\", (\d*)$", l)
    ntimelapses = parse(Int, m.captures[1])
    l = readline(o)
    dostages = r"true"i(l)
    if dostages
        l = readline(o)
        m = match(r"^\"NStagePositions\", (\d*)$", l)
        nstages = parse(Int, m.captures[1])
        for i in 1:nstages
            readline(o)
        end
    else
        nstages = 1
    end
    l = readline(o)
    @assert r"true"i(l) "I don't know yet how to deal with no waves"
    l = readline(o)
    m = match(r"^\"NWavelengths\", (\d*)$", l)
    nwaves = parse(Int, m.captures[1])
    wavenames = Vector{String}(nwaves)
    for i in 1:nwaves
        l = readline(o)
        m = match(r"^\"WaveName\d\", \"(.*)\"$", l)
        wavenames[i] = replace(m.captures[1], '%', '-')
        l = readline(o)
        if r"true"i(l)
            l = readline(o)
            @assert r"false"i(l) "I don't know yet how to deal with `ZSeries`"
        end
    end
    l = readline(o)
    waveinfilename = r"true"i(l)
    timelapses = map(1:nstages) do si
        map(1:ntimelapses) do fi
            _print_file_name(home, base, dostages, si, fi)
        end
    end
    stages = Stage[]
    for (i, tl) in enumerate(timelapses)
        push!(stages, Stage(tl, i, home, base))
    end
    path = joinpath(home, base)
    mkpath(path)
    return stages
end


text:
## ------------------------------------------------------------------
macro new_quote!(ex...)
    label = _insert_label!("new_quote!", ex, __source__)
    _add_secobj!(() -> RBQuote(label), __source__)
end


text:
function addsubdir(pth,str)
    subdirs = readdir(pth)
    iSubdir = findall(occursin.(str,subdirs))
    pth2 = joinpath.(pth,subdirs[iSubdir])
    return pth2
end

function FindGML(pth,tile,type)
    pth_gml = addsubdir(pth,tile)[1]
    pth_gml = addsubdir(pth_gml,type)[1]
    if type=="vml"
        dir = readdir(pth_gml)
        pth_gml = joinpath(pth_gml,dir[occursin.(".",dir).==false][1])
    end
    pth_gml = addsubdir(pth_gml,"gml")[1]
    return pth_gml
end

function LoadXML(pth_fname)
    io=open(pth_fname)
    gml = readlines(io)
    gml = strip.(gml)
    return gml
end

function ParseXML(gml,parseby)
    iStart = findall(occursin.("<$(parseby)>",gml))
    iEnd = findall(occursin.("</$(parseby)>",gml))
    iTag = [iStart[i]:iEnd[i] for i in 1:length(iStart)]
    tagContents = [gml[i] for i in iTag]

    return tagContents
end

function contentSummary(features,pth)
    children = [
        [split(split(child," ")[1],">")[1]*">"
        for child in feature] for feature in features]
    osgb = map(x->x[occursin.("fid=",x)][1],features)
    osgb = map(x->split.(x,"\"")[2],osgb)
    osgb = replace.(osgb,"osgb"=>"")
    osgb = parse.(Int64,osgb)

    coordStrings = ExtractFeatures(features,children,"<gml:coordinates>")

    # Extract eastings/northings (Float64 necessary here for coord accuracy,
    # Float32 introduced RayTracing errors. Could make eastings/northings with
    # reference to local tile for computations, Float32 for plotting. #CUDA)
    coordStrings = map(coordString->split.(coordString,r"[, ]"),coordStrings)
    eastings = map(featCoordSets->map(featCoordSet->parse.(Float64,featCoordSet[1:2:end]),featCoordSets),coordStrings)
    northings = map(featCoordSets->map(featCoordSet->parse.(Float64,featCoordSet[2:2:end]),featCoordSets),coordStrings)

    # Load Building Height Attribute data
    bha = BHAdata(pth)

    # Find indices in `gml` with `bha` data
    iGml = [findfirst(osgb.==bha_osgb) for bha_osgb in bha.OS_TOPO_TOID]

    # Remove 'nothing's
    bha = bha[isa.(iGml,Int64),:]
    iGml = iGml[isa.(iGml,Int64)]

    # Init Missing arrays
    global L = size(features,1)
    TileRef = fill!(Array{Union{Missing,String}}(undef,L),missing)
    for x = [:AbsHMin,:AbsH2,:AbsHMax,:RelH2,:RelHMax]
        @eval $x = fill!(Array{Union{Missing,Float64}}(undef,L),missing)
    end

    # Fill `bha` data
    TileRef[iGml] .= bha.TileRef
    AbsHMin[iGml] = bha.AbsHMin
    AbsH2[iGml] = bha.AbsH2
    AbsHMax[iGml] = bha.AbsHMax
    RelH2[iGml] = bha.RelH2
    RelHMax[iGml] = bha.RelHMax

    df = DataFrame(
        theme = ExtractFeatures(features,children,"<osgb:theme>"),
        osgb = osgb,
        descr = ExtractFeatures(features,children,"<osgb:descriptiveGroup>"),
        areaOS = ExtractFeatures(features,children,"<osgb:calculatedAreaValue>";T=Float64),
        alt = ExtractFeatures(features,children,"<osgb:physicalLevel>";T=Float64),
        logDate = ExtractFeatures(features,children,"<osgb:changeDate>"),
        logChng = ExtractFeatures(features,children,"<osgb:reasonForChange>"),
        eastings = eastings,
        northings = northings,
        TileRef = TileRef,
        AbsHMin = AbsHMin,
        AbsH2 = AbsH2,
        AbsHMax = AbsHMax,
        RelH2 = RelH2,
        RelHMax = RelHMax,
        children=children)

    return df
end

function ProcessGMLs(pth,tile;savepath::String="")

    pth_topo = FindGML(pth,tile,"topo")

    @time gml_topo = LoadXML(pth_topo)

    @time features_topo = ParseXML(gml_topo,"osgb:topographicMember")

    @time summary_topo = contentSummary(features_topo,pth_topo)

    gml=GML(
        tile,
        pth_topo,
        gml_topo,
        features_topo,
        summary_topo,
    )

    if savepath!=""
        CSV.write(joinpath(savepath,"OrdnanceSurvey_$(gml.tile).csv"),gml.summary) # CSV.jl preserves colums better that CSVFiles.jl, for change/date logs
    end

    return gml
end


text:
# ENV["JULIA_DEBUG"] = Metatheory

fibo = @theory begin
    x::Int + y::Int |> x+y
    fib(n::Int) |> (n < 2 ? n : :(fib($(n-1)) + fib($(n-2))))
end

g = EGraph(:(fib(10)))
@time saturate!(g, fibo; timeout=60)

z = EGraph(:(fib(10)))
@time saturate!(z, fibo; timeout=60)

extran = addanalysis!(g, ExtractionAnalysis, astsize)
display(g.M); println()

@testset "Fibonacci" begin
    @test 55 == extract!(g, extran)
end


text:
@testset "Newton Core" begin

    # Test Vertical Indices
    N = 3
    p = 2
    model = UnicycleGame(p=p)
    probsize = ProblemSize(N,model)
    n = probsize.n
    mi = probsize.mi

    verti_inds = vertical_indices(probsize)
    @test verti_inds[stampify(:opt, 1, :x, 1, 2)] == SVector{n,Int}(1:n)
    @test verti_inds[stampify(:opt, 1, :u, 1, 1)] == SVector{mi[1],Int}(n .+ (1:mi[1]))
    @test verti_inds[stampify(:opt, 1, :x, 1, 3)] == SVector{n,Int}(n + mi[1] .+ (1:n))
    @test verti_inds[stampify(:opt, 1, :u, 1, 2)] == SVector{mi[1],Int}(2n + mi[1] .+ (1:mi[1]))
    @test verti_inds[stampify(:opt, 2, :x, 1, 2)] == SVector{n,Int}(2n+2mi[1] .+ (1:n))

    function test_vertical_indices(probsize::ProblemSize, verti_inds)
        N = probsize.N
        n = probsize.n
        m = probsize.m
        p = probsize.p
        mi = probsize.mi
        ni = probsize.ni
        all_inds = Vector{Int}([])
        for i = 1:p
            for k = 1:N-1
                push!(all_inds, verti_inds[stampify(:opt, i, :x, 1, k+1)]...)
                push!(all_inds, verti_inds[stampify(:opt, i, :u, i, k)]...)
            end
        end
        for k = 1:N-1
            push!(all_inds, verti_inds[stampify(:dyn, 1, :x, 1, k)]...)
        end
        sort!(all_inds)
        valid = true
        valid &= length(all_inds) == p*n*(N-1) + m*(N-1) + n*(N-1)
        valid &= all_inds == [i for i=1:length(all_inds)]
        return valid
    end
    @test test_vertical_indices(probsize, verti_inds)

    # Test Horizontal Indices
    N = 3
    p = 2
    model = UnicycleGame(p=p)
    probsize = ProblemSize(N,model)
    n = probsize.n
    m = probsize.m
    mi = probsize.mi

    horiz_inds = horizontal_indices(probsize)
    @test horiz_inds[stampify(:x, 1, 2)] == SVector{n,Int}(1:n)
    @test horiz_inds[stampify(:u, 1, 1)] == SVector{mi[1],Int}(n .+ (1:mi[1]))
    @test horiz_inds[stampify(:u, 2, 1)] == SVector{mi[2],Int}(n + mi[1] .+ (1:mi[2]))
    @test horiz_inds[stampify(:λ, 1, 1)] == SVector{n,Int}(n + m .+ (1:n))
    @test horiz_inds[stampify(:λ, 2, 1)] == SVector{n,Int}(2n + m .+ (1:n))
    @test horiz_inds[stampify(:x, 1, 3)] == SVector{n,Int}(3n + m .+ (1:n))

    function test_horizontal_indices(probsize::ProblemSize, horiz_inds)
        N = probsize.N
        n = probsize.n
        m = probsize.m
        p = probsize.p
        mi = probsize.mi
        ni = probsize.ni
        all_inds = Vector{Int}([])
        for k = 1:N-1
            push!(all_inds, horiz_inds[stampify(:x, 1, k+1)]...)
            for i = 1:p
                push!(all_inds, horiz_inds[stampify(:u, i, k)]...)
                push!(all_inds, horiz_inds[stampify(:λ, i, k)]...)
            end
        end
        sort!(all_inds)
        valid = true
        valid &= length(all_inds) == n*(N-1) + m*(N-1) + p*n*(N-1)
        valid &= all_inds == [i for i=1:length(all_inds)]
        return valid
    end
    @test test_horizontal_indices(probsize, horiz_inds)

    # Test dynamics_indices
    N = 10
    p = 3
    model = UnicycleGame(p=p)
    probsize = ProblemSize(N, model)
    dyn = dynamics_indices(probsize)
    n = probsize.n
    mi = probsize.mi
    pu = probsize.pu
    @test dyn[:x][1] == SVector{n,Int}(1:n)
    @test dyn[:u][1] == SVector{mi[1],Int}(n .+ pu[1])
    @test dyn[:u][2] == SVector{mi[2],Int}(n .+ pu[2])
    @test dyn[:u][3] == SVector{mi[3],Int}(n .+ pu[3])

    # Test Newton Core
    N = 3
    p = 2
    model = UnicycleGame(p=p)
    probsize = ProblemSize(N,model)
    core = NewtonCore(probsize)
    @test typeof(core) <: NewtonCore
    hstamp = stampify(:u, 2, 1)
    vstamp = stampify(:opt, 2, :u, 2, 1)
    stamp = stampify(:opt, 2, :u, 2, 1, :u, 2, 1)
    @test core.horiz_inds[hstamp] == horizontal_idx(core, hstamp)
    @test core.verti_inds[vstamp] == vertical_idx(core, vstamp)
    @test all((core.verti_inds[vstamp], core.horiz_inds[hstamp]) .== idx(core, stamp))

end

@testset "Masks" begin

    # Test Vertical Mask
    N = 6
    p = 5
    model = UnicycleGame(p=p)
    probsize = ProblemSize(N,model)
    verti_inds = vertical_indices(probsize)
    n = probsize.n
    ni = probsize.ni[1]
    mi = probsize.mi[1]

    msk = []
    msks = []
    for i = 1:p
        ms = vertical_mask(probsize, verti_inds, i, splitted_state=true)
        m = vertical_mask(probsize, verti_inds, i, splitted_state=false)
        push!(msk, m)
        push!(msks, ms)
        @test length(m) == (N - 1) * (2n + mi)
        @test length(ms) == (N - 1) * (2ni + mi)
    end
    @test length(intersect(msks...)) == 0

    # Test horizontal Mask
    N = 6
    p = 5
    model = UnicycleGame(p=p)
    probsize = ProblemSize(N,model)
    horiz_inds = horizontal_indices(probsize)
    ni = probsize.ni[1]
    mi = probsize.mi[1]

    msk = []
    msks = []
    for i = 1:p
        m = horizontal_mask(probsize, horiz_inds, i, splitted_state=false)
        ms = horizontal_mask(probsize, horiz_inds, i, splitted_state=true)
        push!(msk, m)
        push!(msks, ms)
        @test length(m) == (N - 1) * (2n + mi)
        @test length(ms) == (N - 1) * (2ni + mi)
    end
    @test length(intersect(msks...)) == 0

end