text:
""" Escape latex symbols in given string """
function escapelatexsymbols(str::String)
   if isascii(str)
      return str
   else
      # create a new string where each symbol in the original string
      # is replaced with its latex representation if it has one
      ret = Vector{String}(undef, length(str))
      retindex = 1
      for i in eachindex(str)
         if isascii(str[i])
            ret[retindex] = string(str[i])
         else
            latexname = REPL.symbol_latex(string(str[i]))
            if latexname != ""
               ret[retindex] = "<" * latexname[2:end] * ">"
               if isempty(ret[retindex])
                  ret[retindex] = string(str[i])
               end
            else
               ret[retindex] = string(str[i])
            end
         end
         retindex += 1
      end
      return join(ret)
   end
end

"""
Returns an object that translates to an R list with keys
"original" and "escaped".
Both entries have as values character vectors.
"original" contains all names that have a different version that
contains latex for describing symbols.
"escaped" contains the names with the latex sequences in the same order.
"""
function escapednames(originalnames::Vector{String})
   escaped = escapelatexsymbols.(originalnames)
   needsescaping = (escaped .!= originalnames)
   original = originalnames[needsescaping]
   escaped = escaped[needsescaping]
   ElementList(Vector{Any}(), Dict{Symbol, Any}(
         :original => original, :escaped => escaped))
end

""" Lists the content of a package for import in R"""
function moduleinfo(modulename::AbstractString; all::Bool = false)
   themodule = RConnector.maineval(modulename)::Module

   function symbolisa(sym::Symbol, type)
      if isdefined(themodule, sym)
         field = themodule.eval(sym)
         return field isa type
      else
         return false
      end
   end

   isafunction(sym) = symbolisa(sym, Function)
   isatype(sym) = symbolisa(sym, Type)

   exportedsyms = names(themodule, all = false)
   exportedfunctions = map(string, filter(isafunction, exportedsyms))
   exportedtypes = map(string, filter(isatype, exportedsyms))

   if all
      allsyms = names(themodule, all = true)
      filter!(sym -> string(sym)[1] != '#', allsyms)
      exportedSymSet = Set(exportedsyms)
      internalsyms = filter(sym -> !(sym in exportedSymSet), allsyms)
      internalfunctions = map(string, filter(isafunction, internalsyms))
      internaltypes = map(string, filter(isatype, internalsyms))
      escapedfunctions = escapednames(vcat(exportedfunctions, internalfunctions))
      escapedtypes = escapednames(vcat(exportedtypes, internaltypes))
      return ElementList(Vector{Any}(), Dict{Symbol, Any}(
                  :exportedFunctions => exportedfunctions,
                  :exportedTypes => exportedtypes,
                  :internalFunctions => internalfunctions,
                  :internalTypes => internaltypes,
                  :escapedFunctions => escapedfunctions,
                  :escapedTypes => escapedtypes))
   else
      escapedfunctions = escapednames(exportedfunctions)
      escapedtypes = escapednames(exportedtypes)
      return ElementList(Vector{Any}(), Dict{Symbol, Any}(
                  :exportedFunctions => exportedfunctions,
                  :exportedTypes => exportedtypes,
                  :escapedFunctions => escapedfunctions,
                  :escapedTypes => escapedtypes))
   end
end


text:
using DocumenterCitations
using Test

@testset "DocumenterCitations.jl" begin
    # Write your tests here.
end

ext: jl


text:
# License for this file: MIT (expat)
# Copyright 2017-2018, DLR Institute of System Dynamics and Control

"""
    module ModiaMath.Variables

Provide variable types for simulation models.

This module provides functions to declare simulation Variables as special structs that
have a `value` and associated attributes. Furthermore, there are functions to copy
the integrator interface variables (`x, derx, residue`) to the appropriate Variables and
vice versa. Therefore, the modeler does not have to care about, how the values of the variables
are mapped to the integrator interface. Typically, a model is constructed with
macro [`@component`](@ref) using `RealXXX` variable declarations. Example:

```julia
  using ModiaMath
  using StaticArrays

  @component Pendulum(;L=1.0, m=1.0, d=0.1, g=9.81) begin
     phi = RealScalar(start=pi/2, unit="rad"    , fixed=true,               numericType=ModiaMath.XD_EXP)
     w   = RealScalar(start=0.0 , unit="rad/s"  , fixed=true, integral=phi, numericType=ModiaMath.XD_EXP)
     a   = RealScalar(            unit="rad/s^2",             integral=w  , numericType=ModiaMath.DER_XD_EXP)
     r   = RealSVector{2}(        unit="m"      ,                           numericType=ModiaMath.WC)
  end;
```

The following variable types are currently supported:

| Variable types                       | Description                                    |
|:-------------------------------------|:-----------------------------------------------|
| [`RealScalar`](@ref)                 | Scalar variable with Float64 value             |
| [`RealSVector`](@ref){Size}          | Variable with SVector{Size,Float64} value      |
| [`RealSVector3`](@ref)               | Variable with SVector{3,Float64} value         |
| [`RealVariable`](@ref){VType, EType} | Variable with value/element type `VType/EType` |

All of them have the following attributes:

| Variable attributes                                 | Description                                           |
|:----------------------------------------------------|:------------------------------------------------------|
| `value::VType`                                      | Value of the variable (scale, vector, matrix, ...)    |
| `info::AbstractString`                              | Description text                                      |
| `causality::`[`ModiaMath.Causality`](@ref)          | Causality of variable                                 |
| `variability::`[`ModiaMath.Variability`](@ref)      | Variability of variable                               |
| `start::EType`                                      | Start value of variable                               |
| `fixed::Bool`                                       | `fixed = true`: `value=start` after initialization    |
| `analysis::`[`VariableAnalysisType`](@ref)          | Analysis for which the variable is used               |
| `min::EType`                                        | Minimum value of `value` and of `start`               |
| `max::EType`                                        | Maximum value of `value` and of `start`               |
| `nominal::EType`                                    | Nominal value of `value` (used to improve numerics)   |
| `flow::Bool`                                        | `= true` if variable is a flow variable               |
| `numericyType::`[`ModiaMath.NumericType`](@ref)     | Defines how variable is used by the integrator        |
| `integral`                                          | = the integral variable or `nothing`                  |
| `unit::String`                                      | Unit of `value` and of `start`                        |

The following functions are provided to perform the actual copy-operations and/or to inquire
information about the variables in the model

- [`ModiaMath.copy_start_to_x!`](@ref)
- [`ModiaMath.copy_x_and_derx_to_variables!`](@ref)
- [`ModiaMath.copy_variables_to_residue!`](@ref)
- [`ModiaMath.print_ModelVariables`](@ref)
- [`ModiaMath.get_xTable`](@ref)
- [`ModiaMath.get_copyToVariableTable`](@ref)
- [`ModiaMath.get_copyToResidueTable`](@ref)
- [`ModiaMath.get_copyToResultTable`](@ref)

# Main developer

[Martin Otter](https://rmc.dlr.de/sr/de/staff/martin.otter/),
[DLR - Institute of System Dynamics and Control](https://www.dlr.de/sr/en)
"""
module Variables

export fullName, instanceName, componentName
export ComponentInternal, isInComponent, isNotInComponent, initComponent!
export @component

export RealVariable, RealScalar, RealSVector, RealSVector3

export ModelVariables
export isArray, isScalar, isUsedInAnalysis, valueLength, indexToString
export get_variableTable, get_xTable, get_copyToVariableTable, get_copyToResidueTable, get_copyToResultTable, print_ModelVariables
export get_variableValueTable, get_residueValueTable
export copy_x_and_derx_to_variables!
export copy_x_to_variables!
export copy_start_to_x!
export copy_variables_to_residue!

export SimulationModel, computeVariables!

# enum values:
export NumericType, Causality, Variability, AnalysisType, VariableAnalysisType
export XD_EXP, XD_IMP, XA, LAMBDA, MUE, DER_XD_EXP, DER_XD_IMP, FD_IMP, FC, WR, WC, TIME, NoNumericType
export Parameter, CalculatedParameter, Input, Output, Local, Independent
export Constant, Fixed, Tunable, Discrete, Continuous
export AnalysisType, KinematicAnalysis, QuasiStaticAnalysis, DynamicAnalysis
export VariableAnalysisType, AllAnalysis, QuasiStaticAndDynamicAnalysis, OnlyDynamicAnalysis, NotUsedInAnalysis

# Enumerations and constants
"""
    @enum NumericType XD_EXP XD_IMP ..

Defines how a variable is used in the integrator interface. The goal is to describe an implicit index-1 DAE:

```math
\\begin{align}
 z &= f_z(x, t) \\\\
 0 &= f_d(\\dot{x}, x, t, z_i > 0) \\\\
 0 &= f_c(x, t, z_i > 0) \\\\
 J &= \\left[ \\frac{\\partial f_d}{\\partial \\dot{x}};
              \\frac{\\partial f_c}{\\partial x} \\right] \\; \\text{is regular}
\\end{align}
```

The integrator interface to the model is

```julia
getModelResidues(m::AbstractSimulationModel, t::Float64, x::Vector{Float64},
                 derx::Vector{Float64}, r::Vector{Float64}
```

In the following table it is shown how `NumericType` values of variables are mapped to this
integrator interface:

| @enum value  | Mapping/Description                                                         |
|:-------------|:----------------------------------------------------------------------------|
| `XD_EXP`     | Copied from `x` into variable; der(v) is **computed by model**              |
| `XD_IMP`     | Copied from `x` into variable; der(v) copied from `derx`                    |
| `XA`         | Copied from `x` into variable; `derx` is ignored (algebraic variable)       |
| `DER_XD_EXP` | Computed by model; automatic: `residue = der(v) - derx`                     |
| `DER_XD_IMP` | Copied from `derx` into variable (= der(v); v has type `XD_IMP`             |
| `LAMBDA`     | Copied from `derx` into variable; index-1 algebraic variable                |
| `MUE`        | Copied from `derx`; stabilizing variable to reduced index to index 1        |
| `FD_IMP`     | Is copied from variable to `residue`; part of ``f_d`` equations             |
| `FC`         | Is copied from variable to `residue`; part of ``f_c`` equations             |
| `WR`         | Computed by model; stored in result; used to compute residues               |
| `WC`         | Computed by model; stored in result; only available at communication points |
| `TIME`       | Copied from `t` into variable; independent variable time                    |
"""
@enum NumericType XD_EXP = 1  XD_IMP = 2  XA = 3  LAMBDA = 4  MUE = 5  DER_XD_EXP = 6  DER_XD_IMP = 7 FD_IMP = 8  FC = 9  WR = 10  WC = 11  TIME = 12 NoNumericType = 13

"""
    @enum Causality Parameter CalculatedParameter Input Output Local Independent

Causality of variable (only used when connecting models)
"""
@enum Causality Parameter CalculatedParameter Input Output Local Independent

"""
    @enum Variability Constant Fixed Tunable Discrete Continuous

Currently not used. Will be used in the future to store only the minimum information
in the result (store value only, when it can potentially change).
"""
@enum Variability Constant Fixed Tunable Discrete Continuous

"""
    @enum AnalysisType KinematicAnalysis QuasiStaticAnalysis DynamicAnalysis

Type of analyis that is actually carried out. The `AnalysisType` is set by the user
of the simulation model. Variables are declared in the model with [`VariableAnalysisType`](@ref)`.
Variables with [`VariableAnalysisType`](@ref)` <= AnalysisType` are removed from the analysis and do
not show up in the result. For example, an *acceleration* would be declared as `OnlyDynamicAnalysis`
and then this variable would not show up in the result, if `AnalysisType = KinematicAnalysis` or
`QuasiStaticAnalysis`.
"""
@enum AnalysisType KinematicAnalysis QuasiStaticAnalysis DynamicAnalysis

"""
    @enum VariableAnalysisType AllAnalysis QuasiStaticAndDynamicAnalysis
                               OnlyDynamicAnalysis NotUsedInAnalysis

Type of analysis that can be carried out with the variable (e.g. a *force* would be defined
as `QuasiStaticAndDynamicAnalysis`, an *acceleration* would be defined as
`OnlyDynamicAnalysis` and a position variable would be defined as
`AllAnalysis`.

Variables with `VariableAnalysisType <= `[`AnalysisType`](@ref) are removed from the analysis and do
not show up in the result. For example, an *acceleration* would be declared as `OnlyDynamicAnalysis`
and then this variable would not show up in the result, if `AnalysisType = KinematicAnalysis` or
`QuasiStaticAnalysis`.
"""
@enum VariableAnalysisType AllAnalysis       QuasiStaticAndDynamicAnalysis OnlyDynamicAnalysis NotUsedInAnalysis

const NumericTypeToVector = [:x, :x, :x, :derx, :derx, :derx, :derx, :residue, :residue, Symbol(""), Symbol(""), Symbol(""), Symbol("")]
const NoNameDefined = :NoNameDefined
const NoUnit = ""

# using/imports
using  StaticArrays
import DataStructures
import DataFrames
import ModiaMath

# include code
include("components.jl")
include("realVariables.jl")
include("modelVariables.jl")
include("simulationModel.jl")

end


text:
using Revise
using FailureRepresentation
using Flux: onecold
using ImageView

include("loadmodels.jl")

X, Y, mapping, adversary, metrics, metrics_rand = sampled_validation_iteration(T=10)


text:
module QuantumTest

using QuantumBayesian
using Test
using LinearAlgebra
using SparseArrays

###
# Fixtures for tests
###

# Capture STDOUT
rd, wr = redirect_stdout()

# Define standard quantum spaces
q = qubit();
f = QFactor(3, "Foo");
o = osc(5);
s = ⊗(q,q,f)
t = (q ⊗ (o ⊗ f)) ⊗ q

include("testQubit.jl")

include("testOscillator.jl")

include("testOperations.jl")

include("testQuantum.jl")

include("testEvolution.jl")

end


text:
### Instructions for adding a new version
#
# * add the version/commit SHA to `llvm_tags`.  Commit SHAs can be found
#   by viewing: https://github.com/llvm/llvm-project/releases
# * create the directory `0_RootFS/LLVMBootstrap@X`.  You can copy the
#   `build_tarballs.jl` file from `0_RootFS/LLVMBootstrap@X-1` and change the
#   version to build.  In order to reduce patches duplication, we want to use as
#   many symlinks as possible, so link to previously existing patches whenever
#   possible.  This shell command should be useful:
#
#      for p in ../../../LLVMBootstrap@X-1/bundled/patches/*.patch; do if [[ -L "${p}" ]]; then cp -a "${p}" .; else ln -s "${p}" .; fi; done
#
# * you only need to build the platform `x86_64-linux-musl`. To deploy the shard
#   and automatically update your BinaryBuilderBase's `Artifacts.toml`, use the
#   `--deploy` flag to the `build_tarballs.jl` script.  You can build & deploy
#   by running:
#
#      julia build_tarballs.jl --debug --verbose --deploy
#

include("./common.jl")

using BinaryBuilder
@eval BinaryBuilder.BinaryBuilderBase empty!(bootstrap_list)
@eval BinaryBuilder.BinaryBuilderBase push!(bootstrap_list, :rootfs, :platform_support)

llvm_tags = Dict(
    v"6.0.1" => "d359f2096850c68b708bc25a7baca4282945949f",
    v"7.1.0" => "4856a9330ee01d30e9e11b6c2f991662b4c04b07",
    v"8.0.1" => "19a71f6bdf2dddb10764939e7f0ec2b98dba76c9",
    v"9.0.1" => "c1a0a213378a458fbea1a5c77b315c7dce08fd05",
    v"10.0.1" => "ef32c611aa214dea855364efd7ba451ec5ec3f74",
    v"11.0.1" => "43ff75f2c3feef64f9d73328230d34dac8832a91",
    v"12.0.0" => "d28af7c654d8db0b68c175db5ce212d74fb5e9bc",
    v"13.0.1" => "75e33f71c2dae584b13a7d1186ae0a038ba98838",
)

function llvm_sources(;version = "v8.0.1", kwargs...)
    return [
        GitSource("https://github.com/llvm/llvm-project.git", llvm_tags[version]),
        DirectorySource("./bundled"; follow_symlinks=true),
    ]
end

# This is the shared buildscript across all versions.
# Thank God we're only building this for a single target.
function llvm_script(;version = v"8.0.1", llvm_build_type = "Release", kwargs...)
    """
    LLVM_MAJ_VER=$(version.major)
    LLVM_BUILD_TYPE=$(llvm_build_type)
    """ *
    raw"""
    apk add build-base python3 python3-dev linux-headers musl-dev zlib-dev

    # We need the XML2, iconv, Zlib libraries in our LLVMBootstrap artifact,
    # and we also need them in target-prefixed directories, so they stick
    # around in `/opt/${target}/${target}/lib64` when mounted.
    mkdir -p ${prefix}/${target}/lib64
    # First, copy in the real files:
    cp -a $(realpath ${libdir}/libxml2.so)  ${prefix}/${target}/lib64
    cp -a $(realpath ${libdir}/libiconv.so) ${prefix}/${target}/lib64
    cp -a $(realpath ${libdir}/libz.so)     ${prefix}/${target}/lib64

    # Then create the symlinks
    ln -s $(basename ${prefix}/${target}/lib64/libxml2.so.*) ${prefix}/${target}/lib64/libxml2.so
    ln -s $(basename ${prefix}/${target}/lib64/libxml2.so.*) ${prefix}/${target}/lib64/libxml2.so.2
    ln -s $(basename ${prefix}/${target}/lib64/libiconv.so.*) ${prefix}/${target}/lib64/libiconv.so
    ln -s $(basename ${prefix}/${target}/lib64/libiconv.so.*) ${prefix}/${target}/lib64/libiconv.so.2
    ln -s $(basename ${prefix}/${target}/lib64/libz.so.*) ${prefix}/${target}/lib64/libz.so
    ln -s $(basename ${prefix}/${target}/lib64/libz.so.*) ${prefix}/${target}/lib64/libz.so.1

    # Include ${prefix}/${target}/lib64 in our linker search path explicitly
    export LDFLAGS="-L${prefix}/${target}/lib64 -Wl,-rpath-link,${prefix}/${target}/lib64"
    # We will also need to run programs which require these libraries, so let them available to the dynamic loader
    export LD_LIBRARY_PATH="${prefix}/${target}/lib64"

    cd ${WORKSPACE}/srcdir/llvm-project
    # Apply all our patches
    if [ -d $WORKSPACE/srcdir/patches ]; then
    for f in $WORKSPACE/srcdir/patches/*.patch; do
        echo "Applying patch ${f}"
        atomic_patch -p1 ${f}
    done
    fi

    # This value is really useful later
    cd ${WORKSPACE}/srcdir/llvm-project/llvm
    LLVM_SRCDIR=$(pwd)

    # Let's do the actual build within the `build` subdirectory
    mkdir build && cd build

    CMAKE_FLAGS=()
    # We build for all platforms, as we're going to use this to do cross-compilation
    CMAKE_FLAGS+=(-DLLVM_TARGETS_TO_BUILD:STRING=all)
    CMAKE_FLAGS+=(-DCMAKE_BUILD_TYPE=${LLVM_BUILD_TYPE})

    # We want a lot of projects
    CMAKE_FLAGS+=(-DLLVM_ENABLE_PROJECTS='clang;compiler-rt;libcxx;libcxxabi;libunwind;polly')

    # We want a build with no bindings
    CMAKE_FLAGS+=(-DLLVM_BINDINGS_LIST=)

    # Turn off docs
    CMAKE_FLAGS+=(-DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF)

    # We want a shared library
    CMAKE_FLAGS+=(-DLLVM_BUILD_LLVM_DYLIB:BOOL=ON -DLLVM_LINK_LLVM_DYLIB:BOOL=ON)
    CMAKE_FLAGS+=("-DCMAKE_INSTALL_PREFIX=${prefix}")

    # Manually set the host triplet, as otherwise on some platforms it tries to guess using
    # `ld -v`, which is hilariously wrong. We set a bunch of musl-related options here
    CMAKE_FLAGS+=("-DLLVM_HOST_TRIPLE=${target}")
    CMAKE_FLAGS+=(-DLIBCXX_HAS_MUSL_LIBC=ON -DLIBCXX_HAS_GCC_S_LIB=OFF)
    CMAKE_FLAGS+=(-DCLANG_DEFAULT_CXX_STDLIB=libc++ -DCLANG_DEFAULT_LINKER=lld -DCLANG_DEFAULT_RTLIB=compiler-rt)
    CMAKE_FLAGS+=(-DLLVM_ENABLE_CXX1Y=ON -DLLVM_ENABLE_PIC=ON)

    # tell libcxx to use compiler-rt
    if [[ "${LLVM_MAJ_VER}" -ge "9" ]]; then
        CMAKE_FLAGS+=(-DLIBCXX_USE_COMPILER_RT=ON)
    fi

    # Tell compiler-rt to generate builtins for all the supported arches, and to use our unwinder
    CMAKE_FLAGS+=(-DCOMPILER_RT_DEFAULT_TARGET_ONLY=OFF)
    CMAKE_FLAGS+=(-DLIBCXXABI_USE_LLVM_UNWINDER=YES)

    # Sanitizers don't support musl
    # https://reviews.llvm.org/D63785
    CMAKE_FLAGS+=(-DCOMPILER_RT_BUILD_XRAY=OFF)
    CMAKE_FLAGS+=(-DCOMPILER_RT_BUILD_SANITIZERS=OFF)
    CMAKE_FLAGS+=(-DCOMPILER_RT_SANITIZERS_TO_BUILD=none)
    CMAKE_FLAGS+=(-DCOMPILER_RT_INCLUDE_TESTS=OFF)

    # Hint to find Zlib
    CMAKE_FLAGS+=(-DZLIB_ROOT="${prefix}")

    # Build!
    cmake ${LLVM_SRCDIR} ${CMAKE_FLAGS[@]}
    cmake -LA || true
    make -j${nproc} VERBOSE=1

    # Install!
    make install -j${nproc} VERBOSE=1
    """
end

# The products that we will ensure are always built
function llvm_products(;kwargs...)
    return [
        # libraries
        LibraryProduct("libLLVM",  :libLLVM)
        LibraryProduct("libLTO",   :libLTO)
        LibraryProduct("libclang", :libclang)
        # tools
        ExecutableProduct("llvm-config", :llvm_config)
    ]
end

# Dependencies that must be installed before this package can be built
function llvm_dependencies(; kwargs...)
    return [
        Dependency("Zlib_jll"),
        Dependency("XML2_jll"),
	# transitive dependency libiconv
    ]
end

function llvm_build_args(; kwargs...)
    return (
        llvm_sources(;kwargs...),
        llvm_script(;kwargs...),
        llvm_products(;kwargs...),
        llvm_dependencies(;kwargs...),
    )
end

max_stars_repo_name: MichelJuillard/Yggdrasil

max_issues_repo_name: MichelJuillard/Yggdrasil

max_forks_repo_name: MichelJuillard/Yggdrasil


text:
module TestGilljamRewire
    using BioEnergeticFoodWebs
    using Test
    using Random

    Random.seed!(1)
    S = 3
    A = [0 0 0 ;
         1 0 0 ;
         1 1 1 ]
    biomass = [1.0,1.0,1.0]
    parameters = BioEnergeticFoodWebs.model_parameters(A, rewire_method = :DS)

#testing Gilljam no extinctions
    GilljamTest = BioEnergeticFoodWebs.Gilljam(S,parameters,biomass)
    @test GilljamTest[1] == A
    @test GilljamTest[2] == parameters
#Testing with extinction
    parameters[:extinctions] = 1
    GilljamTest = BioEnergeticFoodWebs.Gilljam(S,parameters,biomass)
    @test (GilljamTest[1] == [0 0 0; 0 1 0; 0 1 1]) | (GilljamTest[1] == ([0 0 0; 0 0 1; 0 1 1]))
    p1 = deepcopy(parameters)
    p2 = deepcopy(parameters)
    p1[:costMat][2,2] = 0.0
    p2[:costMat][2,3] = 0.0
    @test (GilljamTest[2] == p1) | (GilljamTest[2] == p2)
end


text:
"""
A Julia package for simulations on random trees.
"""
module RandomTree

using Random, DataStructures, Formatting, ArgParse, Distributions, Distributed, PyCall

# For extending these methods
import Base: show, size, iterate, eltype, length

export
    # Types of trees
    AbstractTree,
    FiniteTree,
    ## Conditional Galton Watson trees
    CondGWTree,
    CayleyTree,
    BinaryTree,
    CatalanTree,
    GeneralCondGWTree,
    DAryTree,
    MotzkinTree,
    ## Other random trees
    RandomRecursiveTree,
    ## Fixed trees
    FullDAryTree,

    # Functions applicable to trees
    size,
    name,
    distribution,
    maxdegree,
    degrees,
    treegraph,

    # Graph representations of trees
    FixedGraph,
    FixedDirectedGraph,
    FixedTreeGraph,

    # Functions applicable to FixedGraph
    positions,
    edges,
    nodes,
    sortedge!,
    addedge!,

    # Tree walkers
    AbstractTreeWalker,
    DFSWalker,
    FirstOnlyDFSWalker,
    DepthWalker,
    KcutWalker,
    SubtreeSizeWalker,
    GraphWalker,

    # Functions applicable to AbstractTreeWalker
    walk,
    result,

    # Simulations
    AbstractSimulator,
    KcutSimulator,
    SizePowerSimulator,
    LogProductSimulator,
    HeightSimulator,
    TotalPathSimulator,
    LeafSimulator,

    # Simulations functions
    simulation,
    print_simulation,
    drawtree,

    # Command-line script entry point
    main

include("graph.jl")
include("tree.jl")
include("walker.jl")
include("simulator.jl")
include("graphic.jl")
include("args.jl")
include("main.jl")

end # module


text:
struct NotSet end
const NOTSET = NotSet()

mutable struct Promise{T}
    @atomic value::Union{T,NotSet}
    @const cond::Threads.Condition
    global _Promise(::Type{T}, value, cond) where {T} = new{T}(value, cond)
end

Promise{T}() where {T} = _Promise(T, NotSet(), Threads.Condition())
Promise() = Promise{Any}()

function Base.fetch(promise::Promise)
    value = @atomic :monotonic promise.value
    if !(value isa NotSet)
        atomic_fence(:acquire)
        return value
    end
    lock(promise.cond) do
        local value = @atomic :monotonic promise.value
        value isa NotSet || return value
        wait(promise.cond)
        value = @atomic :monotonic promise.value
        value isa NotSet && error("unreachable: invalid notify")
        return value
    end
end

function Base.wait(promise::Promise)
    fetch(promise)
    return
end

function ConcurrentUtils.try_race_fetch(promise::Promise{T}) where {T}
    value = @atomic :monotonic promise.value
    if value isa NotSet
        return Err(NotSetError())
    else
        atomic_fence(:acquire)
        return Ok{T}(value)
    end
end

ConcurrentUtils.race_put_with!(f::F, promise::Promise) where {F} =
    Try.unwrap_or_else(identity, try_race_put_with!(f, promise))

ConcurrentUtils.race_put!(promise::Promise, value) =
    Try.unwrap_or_else(identity, try_race_put!(promise, value))

function ConcurrentUtils.try_race_put_with!(
    thunk::F,
    promise::Promise{T},
)::Union{Ok{T},Err{T}} where {F,T}
    old = @atomic :monotonic promise.value
    if !(old isa NotSet)
        atomic_fence(:acquire)
        return Err{T}(old)
    end
    lock(promise.cond) do
        local old = @atomic :monotonic promise.value
        if !(old isa NotSet)
            return Err{T}(old)
        end
        new = thunk()
        new = convert(eltype(promise), new)
        @atomic :release promise.value = new
        notify(promise.cond)
        return Ok{T}(new)
    end
end

ConcurrentUtils.try_race_put!(promise, value) =
    ConcurrentUtils.try_race_put_with!(Returns(value), promise)

function Base.put!(promise::Promise{T}, value) where {T}
    Try.unwrap_or_else(try_race_put!(promise, value)) do existing
        throw(OccupiedError{T}(existing))
    end
end


text:
import COBRA, JuMP, GLPKMathProgInterface

export optimize

"""
Optimizes a model. Returns status, f, v, where status
is the status of the LP optimization, f the objective
value, and v the vector of fluxes.
"""
function optimize(model::COBRA.LPproblem)
    m,n = size(model.S)
    lp = JuMP.Model(solver=GLPKMathProgInterface.GLPKSolverLP())
    JuMP.@variable lp model.lb[k] ≤ x[k = 1:n] ≤ model.ub[k]

    for i = 1:m
        JuMP.@expression lp balance sum(model.S[i,k] * x[k] for k = 1:n)
        if model.csense[i] == '<' || model.csense[i] == 'L'
            JuMP.@constraint lp balance ≤ model.b[i]
        elseif model.csense[i] == '>' || model.csense[i] == 'G'
            JuMP.@constraint lp balance ≥ model.b[i]
        elseif model.csense[i] == '=' || model.csense[i] == 'E'
            JuMP.@constraint lp balance == model.b[i]
        else
            error("Invalid csense")
        end
    end

    JuMP.@expression lp obj sum(model.c[k] * x[k] for k = 1:n)

    if model.osense == -1
        JuMP.@objective lp :Min obj
    elseif model.osense == 1
        JuMP.@objective lp :Max obj
    else
        error("Invalid osense")
    end

    sol = JuMP.solve(lp)

    return sol, JuMP.getobjectivevalue(lp), JuMP.getvalue(x)
end

"""
For each reaction in rxns, compute max. and min. flux attainable
in the reaction. Returns two vectors fmin, fmax, where fmin
contains the min fluxes and fmax the max fluxes.
"""
function fva(model::COBRA.LPproblem, rxns::AbstractVector{Int})
    m,n = size(model.S)
    @assert all(1 .≤ rxns .≤ n)

    lp = JuMP.Model(solver=GLPKMathProgInterface.GLPKSolverLP())
    JuMP.@variable lp model.lb[k] ≤ x[k = 1:n] ≤ model.ub[k]

    for i = 1:m
        JuMP.@expression lp balance sum(model.S[i,k] * x[k] for k = 1:n)
        if model.csense[i] == '<' || model.csense[i] == 'L'
            JuMP.@constraint lp balance ≤ model.b[i]
        elseif model.csense[i] == '>' || model.csense[i] == 'G'
            JuMP.@constraint lp balance ≥ model.b[i]
        elseif model.csense[i] == '=' || model.csense[i] == 'E'
            JuMP.@constraint lp balance == model.b[i]
        else
            error("Invalid csense")
        end
    end

    fmin = zeros(length(rxns))
    fmax = zeros(length(rxns))

    for (i,k) in enumerate(rxns)
        JuMP.@objective lp :Min x[k]
        status = JuMP.solve(lp)
        @assert status == :Optimal
        fmin[i] = JuMP.getobjectivevalue(lp)

        JuMP.@objective lp :Max x[k]
        status = JuMP.solve(lp)
        @assert status == :Optimal
        fmax[i] = JuMP.getobjectivevalue(lp)
    end

    return fmin, fmax
end

"Perform fva for every reaction in the model."
fva(model::COBRA.LPproblem) = fva(model, 1 : length(model.rxns))

"Perform fva for the i'th reaction"
function fva(model::COBRA.LPproblem, i::Int)
    fmin, fmax = fva(model, [i])
    fmin[1], fmax[1]
end


text:
# Autogenerated wrapper script for opusfile_jll for aarch64-apple-darwin
export libopusfile, libopusurl

using Ogg_jll
using Opus_jll
using OpenSSL_jll
JLLWrappers.@generate_wrapper_header("opusfile")
JLLWrappers.@declare_library_product(libopusfile, "@rpath/libopusfile.0.dylib")
JLLWrappers.@declare_library_product(libopusurl, "@rpath/libopusurl.0.dylib")
function __init__()
    JLLWrappers.@generate_init_header(Ogg_jll, Opus_jll, OpenSSL_jll)
    JLLWrappers.@init_library_product(
        libopusfile,
        "lib/libopusfile.0.dylib",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libopusurl,
        "lib/libopusurl.0.dylib",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
module TestTransform
    import ManifoldLearning: fit, transform, reconstruct, DataTransform,
                             ZScoreTransform, UnitRangeTransform
    using Statistics: std, mean
    using Test

    @testset "Transform" begin

        X = rand(5, 8)

        t = fit(ZScoreTransform, X; center=false, scale=false)
        Y = transform(t, X)
        @test isa(t, DataTransform)
        @test isempty(t.mean)
        @test isempty(t.scale)
        @test isequal(X, Y)
        @test transform(t, X[:,1]) ≈ Y[:,1]
        @test reconstruct(t, Y[:,1]) ≈ X[:,1]
        @test reconstruct(t, Y) ≈ X

        t = fit(ZScoreTransform, X; center=false)
        Y = transform(t, X)
        @test isa(t, DataTransform)
        @test isempty(t.mean)
        @test length(t.scale) == 5
        @test Y ≈ X ./ std(X, dims=2)
        @test transform(t, X[:,1]) ≈ Y[:,1]
        @test reconstruct(t, Y[:,1]) ≈ X[:,1]
        @test reconstruct(t, Y) ≈ X

        t = fit(ZScoreTransform, X; scale=false)
        Y = transform(t, X)
        @test isa(t, DataTransform)
        @test length(t.mean) == 5
        @test isempty(t.scale)
        @test Y ≈ X .- mean(X, dims=2)
        @test transform(t, X[:,1]) ≈ Y[:,1]
        @test reconstruct(t, Y[:,1]) ≈ X[:,1]
        @test reconstruct(t, Y) ≈ X

        t = fit(ZScoreTransform, X)
        Y = transform(t, X)
        @test isa(t, DataTransform)
        @test length(t.mean) == 5
        @test length(t.scale) == 5
        @test Y ≈ (X .- mean(X, dims=2)) ./ std(X, dims=2)
        @test transform(t, X[:,1]) ≈ Y[:,1]
        @test reconstruct(t, Y[:,1]) ≈ X[:,1]
        @test reconstruct(t, Y) ≈ X

        t = fit(UnitRangeTransform, X)
        Y = transform(t, X)
        @test length(t.min) == 5
        @test length(t.scale) == 5
        @test Y ≈ (X .- minimum(X, dims=2)) ./ (maximum(X, dims=2) .- minimum(X, dims=2))
        @test transform(t, X[:,1]) ≈ Y[:,1]
        @test reconstruct(t, Y[:,1]) ≈ X[:,1]
        @test reconstruct(t, Y) ≈ X

        t = fit(UnitRangeTransform, X; unit=false)
        Y = transform(t, X)
        @test length(t.min) == 5
        @test length(t.scale) == 5
        @test Y ≈ X ./ (maximum(X, dims=2) .- minimum(X, dims=2))
        @test transform(t, X[:,1]) ≈ Y[:,1]
        @test reconstruct(t, Y[:,1]) ≈ X[:,1]
        @test reconstruct(t, Y) ≈ X
    end
end


text:
using Pkg

Pkg.activate(joinpath(@__DIR__, ".."))

using LabClimateDashboard
using Dates
using DelimitedFiles

include(joinpath(@__DIR__, "utils.jl"))

logpath = generate_logdata()
LabClimateDashboard.run(logpath)


text:
using Levels
using Base.Test

@testset "Spectroscopic notation" begin
    is_lj(val, l, j) = NoHyperfineNumberSpec(val) == NoHyperfineNumberSpec(l, j)
    @test is_lj("S_{1/2}", 0, 1//2)
    @test is_lj("P_{3/2}", 1, 3//2)
    @test is_lj("D_{5/2}", 2, 5//2)

    @test is_lj("D_{5//2}", 2, 5//2)
    @test is_lj("D_5/2", 2, 5//2)
    @test is_lj("D_5//2", 2, 5//2)
    @test is_lj("D5/2", 2, 5//2)
    @test is_lj("D5//2", 2, 5//2)

    @test_throws ArgumentError NoHyperfineNumberSpec("D_5//2a")
    @test_throws ArgumentError NoHyperfineNumberSpec("D_52")
    @test_throws ArgumentError NoHyperfineNumberSpec("D_a")
    @test_throws ArgumentError NoHyperfineNumberSpec("D_1/2}")
    @test_throws ArgumentError NoHyperfineNumberSpec("D_{1/2")
end


text:
@enum ContourEnum full_contour=1 keldysh_contour=2 imaginary_contour=3

struct Contour
  domain::ContourEnum
  branches::Vector{Branch}
  branch_indices::NTuple{3, Int} # branches[branch_indices[Int(BranchEnum)]].domain == BranchEnum

  function Contour(branches::AbstractVector{Branch})
    contour_enum = get_contour_enum(branches)
    branch_indices::Vector{Int} = [-1, -1, -1]
    for (i, b) in enumerate(branches)
      branch_indices[Int(b.domain)] = i
    end
    new(contour_enum, branches, Tuple(branch_indices))
  end

end

function Contour(d::ContourEnum; tmax=0.0, β=0.0)
  if d == full_contour
    branches = [Branch(forward_branch, tmax), Branch(backward_branch, tmax), Branch(imaginary_branch, β)]
  elseif d == keldysh_contour
    branches = [Branch(forward_branch, tmax), Branch(backward_branch, tmax)]
  else
    branches = [Branch(imaginary_branch, β)]
  end
  return Contour(branches)
end

function nbranches(c::ContourEnum)
  if c == full_contour
    return 3
  elseif c == keldysh_contour
    return 2
  else
    return 1
  end
end

function nbranches(c::Contour)
  return nbranches(c.domain)
end

function branch_set(c::ContourEnum)
  if c == full_contour
    return Set([forward_branch, backward_branch, imaginary_branch])
  elseif c == keldysh_contour
    return Set([forward_branch, backward_branch])
  else
    return Set([imaginary_branch])
  end
end

function get_contour_enum(branches::Set{BranchEnum})
  for c in instances(ContourEnum)
    branch_set(c) == branches && return c
  end
  @assert false "invalid branch set"
end

function get_contour_enum(branches::AbstractVector{Branch})
  branch_enums = Set([b.domain for b in branches])
  @assert length(branch_enums) == length(branches) "branches must be unique"
  return get_contour_enum(branch_enums)
end

function twist(c::Contour)
  return Contour(circshift(c.branches, -1))
end

function get_branch(c::Contour, d::BranchEnum)
  idx = c.branch_indices[Int(d)]
  return idx == -1 ? nothing : c.branches[idx]
end

"""
θ(t1, t2) = t1 >= t2 ? 1.0 : 0.0
"""
function heaviside(c::Contour, t1::BranchPoint, t2::BranchPoint)
  t1.domain == t2.domain ? t1.ref >= t2.ref : c.branch_indices[t1.domain] > c.branch_indices[t2.domain]
end

"""
Heaviside function on standard keldysh contour
"""
function heaviside(t1::BranchPoint, t2::BranchPoint)
  t1.domain == t2.domain ?  t1.ref >= t2.ref : t1.domain > t2.domain
end

const θ = heaviside

function in(b::BranchEnum, c::ContourEnum)
  if c == keldysh_contour
    return b == imaginary_branch ? false : true
  elseif c == imaginary_branch
    return b == imaginary ? true : false
  else
    return true
  end
end

function in(b::BranchEnum, c::Contour)
  return in(b, c.domain)
end


text:
#=

  Euler #10 in Julia.

  Problem 10
  """
  The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

  Find the sum of all the primes below two million.
  """

  This Julia program was created by Hakan Kjellerstrand, hakank@gmail.com
  See also my Julia page: http://www.hakank.org/Julia/

=#

include("Euler.jl")

# 0.21296016s
function euler10a()
    return sum(primes(2_000_000))
end

# 0.21336632s
function euler10b()
    p = 2;
    for i in 3:2:2_000_000
        if isPrime(i)
            p+=i
        end
    end
    return p;
end

# 0.04506652s
function euler10c()
    return sieve(2_000_000)|>sum
end

# 0.21216517s
function euler10d()
    return primes(2_000_000)|>sum
end

# run_euler(euler10a)
# run_euler(euler10b)
run_euler(euler10c)
# run_euler(euler10d)

max_stars_repo_name: Wikunia/hakank

max_issues_repo_name: Wikunia/hakank

max_forks_repo_name: Wikunia/hakank


text:
#=
    Contents: Functions for processing the app's call to AccessControl.configure().
=#

"""
Updates the default config from that defined in AccessControl.jl to that defined by the args.

NOTE: Only the keys specified in the args are updated, other keys will retain their default values.
"""
function update_config!(acdata = nothing;
                        securecookie = Dict{Symbol, Any}(), session = Dict{Symbol, Any}(),
                        login = Dict{Symbol, Any}(), logout = Dict{Symbol, Any}(), pwdreset = Dict{Symbol, Any}())
    update_config_acdata!(acdata)
    update_config!(:securecookie, securecookie)
    update_config!(:session,      session)
    update_config!(:login,        login)
    update_config!(:logout,       logout)
    update_config!(:pwdreset,     pwdreset)
end

"Overwrite the defaults of cfg[key] with dct."
function update_config!(k1::Symbol, dct::Dict)
    for k2 in keys(dct)
	update_config!(k1, k2, dct[k2])
    end
end

"Update config and trigger update of downstream values."
function update_config!(k1::Symbol, k2::Symbol, val)
    config[k1][k2] = val
    if k1 == :securecookie
	update_securecookie_config!(k2)
    end
end

function update_config_acdata!(acdata)
    if acdata != nothing
	config[:acdata] = acdata
	tp = typeof(acdata)
	if tp == LoggedDict
	    #include(joinpath(dirname(@__FILE__), "backends/backend_loggeddict.jl"))
	else
	    error("Your access control data store has a type that AccessControl.jl doesn't yet support. Please file an issue at the AccessControl.jl github repo.")
	end
    end
end

# EOF


text:
# Tests the routine phisalpha jacobian.  This routine
# computes the force gradient correction after Dehnen & Hernandez (2017).

#include("../src/ttv.jl")

#function phisalpha!(x::Array{Float64,2},v::Array{Float64,2},h::Float64,m::Array{Float64,1},alpha::Float64,n::Int64,jac_step::Array{Float64,4})
#function phisalpha!(x,v,h,m,alpha,n,jac_step)

# Next, try computing three-body Keplerian Jacobian:

@testset "phisalpha" begin
n = 3
t0 = 7257.93115525
h  = 0.05
tmax = 600.0
dlnq = big(1e-15)

elements = readdlm("elements.txt",',')
#elements[2,1] = 1.0
#elements[3,1] = 1.0

m =zeros(n)
x0=zeros(3,n)
v0=zeros(3,n)
alpha = 2.0

# Define which pairs will have impulse rather than -drift+Kepler:
pair = zeros(Bool,n,n)
# We want Keplerian between star & planets, and impulses between
# planets.  Impulse is indicated with 'true', -drift+Kepler with 'false':
#for i=2:n
#  pair[1,i] = false
#  # We don't need to define this, but let's anyways:
#  pair[i,1] = false
#end
println("pair: ",pair)

jac_step = Matrix{Float64}(I,7*n,7*n)

for k=1:n
  m[k] = elements[k,1]
end
m0 = copy(m)

x0,v0 = init_nbody(elements,t0,n)

# Tilt the orbits a bit:
x0[2,1] = 5e-1*sqrt(x0[1,1]^2+x0[3,1]^2)
x0[2,2] = -5e-1*sqrt(x0[1,2]^2+x0[3,2]^2)
x0[2,3] = -5e-1*sqrt(x0[1,2]^2+x0[3,2]^2)
v0[2,1] = 5e-1*sqrt(v0[1,1]^2+v0[3,1]^2)
v0[2,2] = -5e-1*sqrt(v0[1,2]^2+v0[3,2]^2)
v0[2,3] = -5e-1*sqrt(v0[1,2]^2+v0[3,2]^2)

# Take a step:
dh17!(x0,v0,h,m,n,pair)

# Now, copy these to compute Jacobian (so that I don't step
# x0 & v0 forward in time):
x = copy(x0); v = copy(v0); m = copy(m0)
# Compute jacobian exactly:
dqdt_phi = zeros(7*n)
xerror = zeros(3,n); verror = zeros(3,n)
phisalpha!(x,v,xerror,verror,h,m,alpha,n,jac_step,dqdt_phi,pair)

# Now compute numerical derivatives, using BigFloat to avoid
# round-off errors:
jac_step_num = zeros(BigFloat,7*n,7*n)
# Save these so that I can compute derivatives numerically:
xsave = big.(x0)
vsave = big.(v0)
msave = big.(m0)
hbig = big(h)
abig = big(alpha)
# Carry out step using BigFloat for extra precision:
phisalpha!(xsave,vsave,hbig,msave,abig,n,pair)
xbig = big.(x0)
vbig = big.(v0)
mbig = big.(m0)
# Compute numerical derivatives wrt time:
dqdt_num = zeros(BigFloat,7*n)
# Vary time:
phisalpha!(xbig,vbig,hbig,mbig,abig,n,pair)
# Initial positions, velocities & masses:
xbig .= big.(x0)
vbig .= big.(v0)
mbig .= big.(m0)
hbig = big(h)
dq = dlnq * hbig
hbig += dq
phisalpha!(xbig,vbig,hbig,mbig,abig,n,pair)
# Now x & v are final positions & velocities after time step
for i=1:n, k=1:3
  dqdt_num[(i-1)*7+  k] = (xbig[k,i]-xsave[k,i])/dq
  dqdt_num[(i-1)*7+3+k] = (vbig[k,i]-vsave[k,i])/dq
end
hbig = big(h)
# Vary the initial parameters of planet j:
for j=1:n
  # Vary the initial phase-space elements:
  for jj=1:3
  # Initial positions, velocities & masses:
    xbig .= big.(x0)
    vbig .= big.(v0)
    mbig .= big.(m0)
    dq = dlnq * xbig[jj,j]
    if xbig[jj,j] != 0.0
      xbig[jj,j] +=  dq
    else
      dq = dlnq
      xbig[jj,j] = dq
    end
    phisalpha!(xbig,vbig,hbig,mbig,abig,n,pair)
  # Now x & v are final positions & velocities after time step
    for i=1:n
      for k=1:3
        jac_step_num[(i-1)*7+  k,(j-1)*7+jj] = (xbig[k,i]-xsave[k,i])/dq
        jac_step_num[(i-1)*7+3+k,(j-1)*7+jj] = (vbig[k,i]-vsave[k,i])/dq
      end
    end
    xbig .= big.(x0)
    vbig .= big.(v0)
    mbig .= big.(m0)
    dq = dlnq * vbig[jj,j]
    if vbig[jj,j] != 0.0
      vbig[jj,j] +=  dq
    else
      dq = dlnq
      vbig[jj,j] = dq
    end
    phisalpha!(xbig,vbig,hbig,mbig,abig,n,pair)
    for i=1:n
      for k=1:3
        jac_step_num[(i-1)*7+  k,(j-1)*7+3+jj] = (xbig[k,i]-xsave[k,i])/dq
        jac_step_num[(i-1)*7+3+k,(j-1)*7+3+jj] = (vbig[k,i]-vsave[k,i])/dq
      end
    end
  end
# Now vary mass of planet:
  xbig .= big.(x0)
  vbig .= big.(v0)
  mbig .= big.(m0)
  dq = mbig[j]*dlnq
  mbig[j] += dq
  phisalpha!(xbig,vbig,hbig,mbig,abig,n,pair)
  for i=1:n
    for k=1:3
      jac_step_num[(i-1)*7+  k,j*7] = (xbig[k,i]-xsave[k,i])/dq
      jac_step_num[(i-1)*7+3+k,j*7] = (vbig[k,i]-vsave[k,i])/dq
    end
    # Mass unchanged -> identity
    jac_step_num[7*i,7*i] = big(1.0)
  end
end

# Now, compare the results:
#println(jac_step)
#println(convert(Array{Float64,2},jac_step_num))

#for j=1:3
#  for i=1:7
#    for k=1:3
#      println(jac_step[(j-1)*7+i,(k-1)*7+1:7*k]," ",jac_step_num[(j-1)*7+i,(k-1)*7+1:7*k]," ",jac_step_num[(j-1)*7+i,(k-1)*7+1:7*k]./jac_step[(j-1)*7+i,(k-1)*7+1:7*k]-1.)
#    end
#  end
#end

jacmax = 0.0
for i=1:7, j=1:3, k=1:7, l=1:3
  if jac_step[(j-1)*7+i,(l-1)*7+k] != 0 && jac_step_num[(j-1)*7+i,(l-1)*7+k] != 0
    # Compute the fractional error and absolute error, and take the minimum of the two:
#    diff = minimum([abs(float(jac_step_num[(j-1)*7+i,(l-1)*7+k])/jac_step[(j-1)*7+i,(l-1)*7+k]-1.0);float(jac_step_num[(j-1)*7+i,(l-1)*7+k])-jac_step[(j-1)*7+i,(l-1)*7+k]])
    diff = abs(float(jac_step_num[(j-1)*7+i,(l-1)*7+k])/jac_step[(j-1)*7+i,(l-1)*7+k]-1.0)
    if diff > jacmax
      jacmax = diff
      println(i," ",j," ",k," ",l," ",jacmax," ",convert(Float64,jac_step_num[(j-1)*7+i,(l-1)*7+k])," ",jac_step[(j-1)*7+i,(l-1)*7+k])
    end
  end
end

println("Maximum jac_step phisalpha error: ",convert(Float64,jacmax))
dqdt_num = convert(Array{Float64,1},dqdt_num)
println("Maximum dqdt_phi phisalpha error: ",maximum(abs.(dqdt_phi-dqdt_num)))

@test isapprox(jac_step,jac_step_num;norm=maxabs)
@test isapprox(dqdt_phi,dqdt_num;norm=maxabs)
end


text:
using Test

@testset "Vertices Congruence" begin
	err = 1e-7
	G = [
		0.0 err 0.0 0.0 0.0
		0.0 0.0 err 0.0 0.0
		0.0 0.0 0.0 err 0.0
	]
	G1, Vcls = CAGD.vcongruence(G[:, 1:4], epsilon=err)
	@test G1 == ([err; err; err]/4)[:,:];
	@test Vcls == [[1, 2, 3, 4]]
	G1, Vcls = CAGD.vcongruence(G[:, 2:5], epsilon=err)
	@test G1 == G[:, 2:4]/2;
	@test Vcls == [[1,4],[2,4],[3,4]];
end

@testset "Cell Congruence" begin

end

@testset "One Cube Fragmentation" begin
	G = [
		0.5310492999999998 1.0146684 0.3477716 0.8313907882395298 0.6061046999999998 1.0897237999999998 0.42282699999999984 0.9064461979373597 0.5310493 1.0146684000000001 0.6061047 1.0897237772434623 0.3477716 0.8313908 0.422827 0.9064462 0.5310493 0.34777160000000007 0.6061047 0.4228270000000002 1.0146684 0.8313908 1.0897238 0.9064461675456482;
		0.8659989999999999 0.6827212999999999 0.5268921 0.3436144447063971 1.2188832999999994 1.0356056999999999 0.8797763999999998 0.6964987903021808 0.8659989999999999 0.6827213 1.2188833 1.035605657895053 0.5268921 0.3436145 0.8797764000000001 0.6964988 0.8659989999999999 0.5268920999999999 1.2188833 0.8797764 0.6827213 0.3436145 1.0356057 0.6964988122992563;
		0.14191280000000003 0.2169682 0.4947971000000001 0.5698524407571428 0.5200012 0.5950565999999999 0.8728855 0.9479408896095312 0.14191279999999987 0.21696819999999994 0.5200011999999999 0.5950566438156151 0.4947971 0.5698525000000001 0.8728855 0.9479409 0.14191280000000006 0.4947971000000001 0.5200012000000002 0.8728855000000001 0.21696819999999994 0.5698525000000001 0.5950565999999999 0.9479408949632379
	];
	Delta_0 = SparseArrays.sparse((
		[1, 3, 1, 4, 2, 3, 2, 4, 5, 7, 5, 8, 6, 7, 6, 8, 9, 11, 9, 12, 10, 11, 10, 12, 13, 15, 13, 16, 14, 15, 14, 16, 17, 19, 17, 20, 18, 19, 18, 20, 21, 23, 21, 24, 22, 23, 22, 24],
		[1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24],
		Int8[-1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1]
	)...);
	Delta_1 = SparseArrays.sparse((
		[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6],
		[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
		Int8[1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1]
	)...);

	V, EV, FE = CAGD.chaincongruence(G, Delta_0, Delta_1)

	@test V == [0.5310492999999998 1.0146684 0.3477716 0.8313907960798432 0.6061046999999999 1.0897237924144874 0.422827 0.906446188494336; 0.8659989999999999 0.6827212999999999 0.5268921 0.343614481568799 1.2188832999999997 1.0356056859650178 0.8797763999999999 0.6964988008671457; 0.14191279999999998 0.21696819999999994 0.49479710000000005 0.569852480252381 0.5200012 0.595056614605205 0.8728855000000001 0.9479408948575897]
	@test sort(EV) == [[1, 2], [1, 3], [1, 5], [2, 4], [2, 6], [3, 4], [3, 7], [4, 8], [5, 6], [5, 7], [6, 8], [7, 8]]
	@test sort(FE) == [[1, 2, 3, 4], [1, 5, 9, 10], [2, 6, 11, 12], [3, 7, 9, 11], [4, 8, 10, 12], [5, 6, 7, 8]]
end


text:
function test_parse(production, code; v=v"1.6")
    stream = ParseStream(code, version=v)
    production(JuliaSyntax.ParseState(stream))
    t = JuliaSyntax.build_tree(GreenNode, stream, wrap_toplevel_as_kind=K"None")
    source = SourceFile(code)
    s = SyntaxNode(source, t)
    if JuliaSyntax.kind(s) == K"None"
        join([sprint(show, MIME("text/x.sexpression"), c) for c in children(s)], ' ')
    else
        sprint(show, MIME("text/x.sexpression"), s)
    end
end

# TODO:
# * Extract the following test cases from the source itself.
# * Use only the green tree to generate the S-expressions
#   (add flag annotations to heads)
tests = [
    JuliaSyntax.parse_toplevel => [
        "a \n b"     =>  "(toplevel a b)"
        "a;b \n c;d" =>  "(toplevel (toplevel a b) (toplevel c d))"
        "a \n \n"    =>  "(toplevel a)"
        ""           =>  "(toplevel)"
    ],
    JuliaSyntax.parse_block => [
        "a;b;c"   => "(block a b c)"
        "a;;;b;;" => "(block a b)"
        ";a"      => "(block a)"
        "\n a"    => "(block a)"
        "a\nb"    => "(block a b)"
    ],
    JuliaSyntax.parse_stmts => [
        "a;b;c"   => "(toplevel a b c)"
        "a;;;b;;" => "(toplevel a b)"
        """ "x" a ; "y" b """ =>
            """(toplevel (macrocall :(Core.var"@doc") "x" a) (macrocall :(Core.var"@doc") "y" b))"""
        "x y"  =>  "x (error-t y)"
    ],
    JuliaSyntax.parse_eq => [
        # parse_assignment
        "a = b"       =>  "(= a b)"
        "a .= b"      =>  "(.= a b)"
        "a += b"      =>  "(+= a b)"
        "a .+= b"     =>  "(.+= a b)"
        "a, b = c, d" =>  "(= (tuple a b) (tuple c d))"
        "x, = xs"     =>  "(= (tuple x) xs)"
        "[a ~b]"      =>  "(hcat a (call ~ b))"
        "a ~ b"       =>  "(call-i a ~ b)"
        "[a ~ b c]"   =>  "(hcat (call-i a ~ b) c)"
    ],
    JuliaSyntax.parse_pair => [
        "a => b"  =>  "(call-i a => b)"
    ],
    JuliaSyntax.parse_cond => [
        "a ? b : c"   => "(if a b c)"
        "a ?\nb : c"  => "(if a b c)"
        "a ? b :\nc"  => "(if a b c)"
        "a ? b : c:d" =>   "(if a b (call-i c : d))"
        # Following are errors but should recover
        "a? b : c"    => "(if a (error-t) b c)"
        "a ?b : c"    => "(if a (error-t) b c)"
        "a ? b: c"    => "(if a b (error-t) c)"
        "a ? b :c"    => "(if a b (error-t) c)"
        "a ? b c"     => "(if a b (error-t) c)"
    ],
    JuliaSyntax.parse_arrow => [
        "x → y"     =>  "(call-i x → y)"
        "x <--> y"  =>  "(call-i x <--> y)"
        "x --> y"   =>  "(--> x y)"
        "x .--> y"  =>  "(call-i x .--> y)"
        "x -->₁ y"  =>  "(call-i x -->₁ y)"
    ],
    JuliaSyntax.parse_or => [
        "x || y || z" => "(|| x (|| y z))"
        ((v=v"1.6",), "x .|| y") => "(error (.|| x y))"
        ((v=v"1.7",), "x .|| y") => "(.|| x y)"
    ],
    JuliaSyntax.parse_and => [
        "x && y && z" => "(&& x (&& y z))"
        ((v=v"1.6",), "x .&& y") => "(error (.&& x y))"
        ((v=v"1.7",), "x .&& y") => "(.&& x y)"
    ],
    JuliaSyntax.parse_comparison => [
        # Type comparisons are syntactic
        "x <: y"      => "(<: x y)"
        "x >: y"      => "(>: x y)"
        # Normal binary comparisons
        "x < y"       => "(call-i x < y)"
        # Comparison chains
        "x < y < z"   => "(comparison x < y < z)"
        "x == y < z"  => "(comparison x == y < z)"
    ],
    JuliaSyntax.parse_pipe_lt => [
        "x <| y <| z" => "(call-i x <| (call-i y <| z))"
    ],
    JuliaSyntax.parse_pipe_gt => [
        "x |> y |> z" => "(call-i (call-i x |> y) |> z)"
    ],
    JuliaSyntax.parse_range => [
        "1:2"       => "(call-i 1 : 2)"
        "1:2:3"     => "(call-i 1 : 2 3)"
        "a:b:c:d:e" => "(call-i (call-i a : b c) : d e)"
        "a :< b"    => "(call-i a (error : <) b)"
    ],
    JuliaSyntax.parse_range => [
        "a..b"       => "(call-i a .. b)"
        "a … b"      => "(call-i a … b)"
        "[1 :a]"     => "(hcat 1 (quote a))"
        "[1 2:3 :a]" =>  "(hcat 1 (call-i 2 : 3) (quote a))"
        "x..."     => "(... x)"
        "x:y..."   => "(... (call-i x : y))"
        "x..y..."  => "(... (call-i x .. y))"
    ],
    JuliaSyntax.parse_expr => [
        "a - b - c"  => "(call-i (call-i a - b) - c)"
        "a + b + c"  => "(call-i a + b c)"
        "a + b .+ c" => "(call-i (call-i a + b) .+ c)"
        # parse_with_chains:
        # The following is two elements of a hcat
        "[x +y]"     =>  "(hcat x (call + y))"
        "[x+y +z]"   =>  "(hcat (call-i x + y) (call + z))"
        # Conversely the following are infix calls
        "[x +₁y]"    =>  "(vect (call-i x +₁ y))"
        "[x+y+z]"    =>  "(vect (call-i x + y z))"
        "[x+y + z]"  =>  "(vect (call-i x + y z))"
        # Dotted and normal operators
        "a +₁ b +₁ c"  =>  "(call-i (call-i a +₁ b) +₁ c)"
        "a .+ b .+ c"  =>  "(call-i (call-i a .+ b) .+ c)"
    ],
    JuliaSyntax.parse_term => [
        "a * b * c"  => "(call-i a * b c)"
        # parse_unary
        "-2*x"   =>  "(call-i -2 * x)"
        ":T"     =>  "(quote T)"
        "in::T"  =>  "(:: in T)"
        "isa::T" =>  "(:: isa T)"
    ],
    JuliaSyntax.parse_juxtapose => [
        "2x"         => "(call-i 2 * x)"
        "2x"         => "(call-i 2 * x)"
        "2(x)"       => "(call-i 2 * x)"
        "(2)(3)x"    => "(call-i 2 * 3 x)"
        "(x-1)y"     => "(call-i (call-i x - 1) * y)"
        "x'y"        => "(call-i (' x) * y)"
        # errors
        "\"a\"\"b\"" => "(call-i \"a\" * (error-t) \"b\")"
        "\"a\"x"     => "(call-i \"a\" * (error-t) x)"
        # Not juxtaposition - parse_juxtapose will consume only the first token.
        "x.3"       =>  "x"
        "sqrt(2)2"  =>  "(call sqrt 2)"
        "x' y"      =>  "(' x)"
        "x 'y"      =>  "x"
        "0xenomorph" => "0x0e"
    ],
    JuliaSyntax.parse_unary => [
        "+2"       => "2"
        "-2^x"     => "(call - (call-i 2 ^ x))"
        "-2[1, 3]" => "(call - (ref 2 1 3))"
    ],
    JuliaSyntax.parse_unary_call => [
        # Standalone dotted operators are parsed as (|.| op)
        ".+"   =>  "(. +)"
        ".+\n" =>  "(. +)"
        ".+ =" =>  "(. +)"
        ".+)"  =>  "(. +)"
        ".&"   =>  "(. &)"
        # Standalone non-dotted operators
        "+)"   =>  "+"
        # Call with type parameters or non-unary prefix call
        "+{T}(x::T)"  =>  "(call (curly + T) (:: x T))"
        "*(x)"        =>  "(call * x)"
        # Prefix function calls for operators which are both binary and unary
        "+(a,b)"   =>  "(call + a b)"
        "+(a=1,)"  =>  "(call + (kw a 1))"
        "+(a...)"  =>  "(call + (... a))"
        "+(a;b,c)" =>  "(call + a (parameters b c))"
        "+(;a)"    =>  "(call + (parameters a))"
        # Whitespace not allowed before prefix function call bracket
        "+ (a,b)"  =>  "(call + (error) a b)"
        # Prefix calls have higher precedence than ^
        "+(a,b)^2"  =>  "(call-i (call + a b) ^ 2)"
        "+(a,b)(x)^2"  =>  "(call-i (call (call + a b) x) ^ 2)"
        # Unary function calls with brackets as grouping, not an arglist
        "+(a;b)"  =>  "(call + (block a b))"
        "+(a=1)"  =>  "(call + (= a 1))"
        # Unary operators have lower precedence than ^
        "+(a)^2"  =>  "(call + (call-i a ^ 2))"
        "+(a)(x,y)^2"  =>  "(call + (call-i (call a x y) ^ 2))"
        # Normal unary calls (see parse_unary)
        "+x" => "(call + x)"
        "√x" => "(call √ x)"
        "±x" => "(call ± x)"
        # Not a unary operator
        "/x"     => "(call (error /) x)"
        "+₁ x"   => "(call (error +₁) x)"
        ".<: x"  => "(call (error .<:) x)"
    ],
    JuliaSyntax.parse_factor => [
        "x^y"      =>  "(call-i x ^ y)"
        "x^y^z"    =>  "(call-i x ^ (call-i y ^ z))"
        "begin x end::T"  =>  "(:: (block x) T)"
        # parse_decl_with_initial_ex
        "a::b"     =>  "(:: a b)"
        "a->b"     =>  "(-> a b)"
        "a::b::c"  =>  "(:: (:: a b) c)"
        "a::b->c"  =>  "(-> (:: a b) c)"
    ],
    JuliaSyntax.parse_unary_subtype => [
        "<: )"    =>  "<:"
        "<: \n"   =>  "<:"
        "<: ="    =>  "<:"
        "<:{T}(x::T)"   =>  "(call (curly <: T) (:: x T))"
        "<:(x::T)"      =>  "(<: (:: x T))"
        "<: A where B"  =>  "(<: (where A B))"
        # Really for parse_where
        "x where \n {T}"  =>  "(where x T)"
        "x where {T,S}"  =>  "(where x T S)"
        "x where {T S}"  =>  "(where x (bracescat (row T S)))"
        "x where {y for y in ys}"  =>  "(where x (braces (generator y (= y ys))))"
        "x where T"  =>  "(where x T)"
        "x where \n T"  =>  "(where x T)"
        "x where T<:S"  =>  "(where x (<: T S))"
    ],
    JuliaSyntax.parse_unary_prefix => [
        "&)"   => "&"
        "\$\n" => "\$"
        "&a"   => "(& a)"
        "::a"  => "(:: a)"
        "\$a"  => "(\$ a)"
        "\$\$a"  => "(\$ (\$ a))"
    ],
    JuliaSyntax.parse_call => [
        # Mostly parse_call_chain
        "f(x)"    =>  "(call f x)"
        "\$f(x)"  =>  "(call (\$ f) x)"
        "f(a,b)"  => "(call f a b)"
        "f (a)" => "(call f (error-t) a)"
        "f(a).g(b)" => "(call (. (call f a) (quote g)) b)"
        "\$A.@x"    =>  "(macrocall (. (\$ A) (quote @x)))"
        # do
        "f() do\nend"         =>  "(do (call f) (-> (tuple) (block)))"
        "f() do ; body end"   =>  "(do (call f) (-> (tuple) (block body)))"
        "f() do x, y\n body end"  =>  "(do (call f) (-> (tuple x y) (block body)))"
        "f(x) do y body end"  =>  "(do (call f x) (-> (tuple y) (block body)))"
        # Keyword arguments depend on call vs macrocall
        "foo(a=1)"  =>  "(call foo (kw a 1))"
        "@foo(a=1)" =>  "(macrocall @foo (= a 1))"
        "@foo a b"     =>  "(macrocall @foo a b)"
        "@foo (x)"     =>  "(macrocall @foo x)"
        "@foo (x,y)"   =>  "(macrocall @foo (tuple x y))"
        "A.@foo a b"   =>  "(macrocall (. A (quote @foo)) a b)"
        "@A.foo a b"   =>  "(macrocall (. A (quote @foo)) a b)"
        "[@foo \"x\"]"   =>  "(vect (macrocall @foo \"x\"))"
        "[f (x)]"     =>  "(hcat f x)"
        "[f \"x\"]"   =>  "(hcat f \"x\")"
        # Macro names
        "@! x"  => "(macrocall @! x)"
        "@.. x" => "(macrocall @.. x)"
        "@\$ y"  => "(macrocall @\$ y)"
        # Special @doc parsing rules
        "@doc x\ny"    =>  "(macrocall @doc x y)"
        "A.@doc x\ny"  =>  "(macrocall (. A (quote @doc)) x y)"
        "@A.doc x\ny"  =>  "(macrocall (. A (quote @doc)) x y)"
        "@doc x y\nz"  =>  "(macrocall @doc x y)"
        "@doc x\n\ny"  =>  "(macrocall @doc x)"
        "@doc x\nend"  =>  "(macrocall @doc x)"
        # .' discontinued
        "f.'"    =>  "f (error-t . ')"
        # Allow `@` in macrocall only in first and last position
        "A.B.@x"    =>  "(macrocall (. (. A (quote B)) (quote @x)))"
        "@A.B.x"    =>  "(macrocall (. (. A (quote B)) (quote @x)))"
        "A.@B.x"    =>  "(macrocall (. (. A (quote B)) (error-t) (quote @x)))"
        "A.@. y"    =>  "(macrocall (. A (quote @__dot__)) y)"
        "a().@x(y)" =>  "(macrocall (error (. (call a) (quote x))) y)"
        "a().@x y"  =>  "(macrocall (error (. (call a) (quote x))) y)"
        "a().@x{y}" =>  "(macrocall (error (. (call a) (quote x))) (braces y))"
        # array indexing, typed comprehension, etc
        "a().@x[1]" => "(macrocall (ref (error (. (call a) (quote x))) 1))"
        "a[i]"  =>  "(ref a i)"
        "a [i]"  =>  "(ref a (error-t) i)"
        "a[i,j]"  =>  "(ref a i j)"
        "T[x   y]"  =>  "(typed_hcat T x y)"
        "T[x ; y]"  =>  "(typed_vcat T x y)"
        "T[a b; c d]"  =>  "(typed_vcat T (row a b) (row c d))"
        "T[x for x in xs]"  =>  "(typed_comprehension T (generator x (= x xs)))"
        ((v=v"1.8",), "T[a ; b ;; c ; d]") => "(typed_ncat-2 T (nrow-1 a b) (nrow-1 c d))"
        # Keyword params always use kw inside tuple in dot calls
        "f.(a,b)"   =>  "(. f (tuple a b))"
        "f.(a=1)"   =>  "(. f (tuple (kw a 1)))"
        "f. (x)"    =>  "(. f (error-t) (tuple x))"
        # Other dotted syntax
        "A.:+"      =>  "(. A (quote +))"
        "A.: +"     =>  "(. A (quote (error-t) +))"
        "f.\$x"     =>  "(. f (inert (\$ x)))"
        "f.\$(x+y)" =>  "(. f (inert (\$ (call-i x + y))))"
        "A.\$B.@x"  =>  "(macrocall (. (. A (inert (\$ B))) (quote @x)))"
        # Field/property syntax
        "f.x.y"  =>  "(. (. f (quote x)) (quote y))"
        "x .y"   =>  "(. x (error-t) (quote y))"
        # Adjoint
        "f'"  => "(' f)"
        "f'ᵀ" => "(call-i f 'ᵀ)"
        # Curly calls
        "@S{a,b}" => "(macrocall @S (braces a b))"
        "S{a,b}"  => "(curly S a b)"
        "S {a}"   =>  "(curly S (error-t) a)"
        # String macros
        "x\"str\""   => """(macrocall @x_str "str")"""
        "x`str`"     => """(macrocall @x_cmd "str")"""
        "x\"\""      => """(macrocall @x_str "")"""
        "x``"        => """(macrocall @x_cmd "")"""
        # Triple quoted procesing for custom strings
        "r\"\"\"\nx\"\"\""        => raw"""(macrocall @r_str "x")"""
        "r\"\"\"\n x\n y\"\"\""   => raw"""(macrocall @r_str (string-sr "x\n" "y"))"""
        "r\"\"\"\n x\\\n y\"\"\"" => raw"""(macrocall @r_str (string-sr "x\\\n" "y"))"""
        # Macro sufficies can include keywords and numbers
        "x\"s\"y"    => """(macrocall @x_str "s" "y")"""
        "x\"s\"end"  => """(macrocall @x_str "s" "end")"""
        "x\"s\"in"   => """(macrocall @x_str "s" "in")"""
        "x\"s\"2"    => """(macrocall @x_str "s" 2)"""
        "x\"s\"10.0" => """(macrocall @x_str "s" 10.0)"""
    ],
    JuliaSyntax.parse_resword => [
        # In normal_context
        "begin f() where T = x end" => "(block (= (where (call f) T) x))"
        # block
        "begin end"         =>  "(block)"
        "begin a ; b end"   =>  "(block a b)"
        "begin\na\nb\nend"  =>  "(block a b)"
        # quote
        "quote end"         =>  "(quote (block))"
        "quote body end"    =>  "(quote (block body))"
        # while
        "while cond body end"  =>  "(while cond (block body))"
        "while x < y \n a \n b \n end"  =>  "(while (call-i x < y) (block a b))"
        # for
        "for x in xs end" => "(for (= x xs) (block))"
        "for x in xs, y in ys \n a \n end" => "(for (block (= x xs) (= y ys)) (block a))"
        # let
        "let x=1\n end"    =>  "(let (= x 1) (block))"
        "let x ; end"      =>  "(let x (block))"
        "let x=1 ; end"    =>  "(let (= x 1) (block))"
        "let x::1 ; end"   =>  "(let (:: x 1) (block))"
        "let x=1,y=2 end"  =>  "(let (block (= x 1) (= y 2)) (block))"
        "let x+=1 ; end"   =>  "(let (block (+= x 1)) (block))"
        "let ; end"        =>  "(let (block) (block))"
        "let ; body end"   =>  "(let (block) (block body))"
        "let\na\nb\nend"   =>  "(let (block) (block a b))"
        # abstract type
        "abstract type A end"            =>  "(abstract A)"
        "abstract type A ; end"          =>  "(abstract A)"
        "abstract type \n\n A \n\n end"  =>  "(abstract A)"
        "abstract type A <: B end"       =>  "(abstract (<: A B))"
        "abstract type A <: B{T,S} end"  =>  "(abstract (<: A (curly B T S)))"
        "abstract type A < B end"        =>  "(abstract (call-i A < B))"
        # primitive type
        "primitive type A 32 end"   =>  "(primitive A 32)"
        "primitive type A 32 ; end" =>  "(primitive A 32)"
        "primitive type A \$N end"  =>  "(primitive A (\$ N))"
        "primitive type A <: B \n 8 \n end"  =>  "(primitive (<: A B) 8)"
        # struct
        "struct A <: B \n a::X \n end"  =>  "(struct false (<: A B) (block (:: a X)))"
        "mutable struct A end"          =>  "(struct true A (block))"
        "struct A end"    =>  "(struct false A (block))"
        "struct try end"  =>  "(struct false (error (try)) (block))"
        # return
        "return\nx"   =>  "(return nothing)"
        "return)"     =>  "(return nothing)"
        "return x"    =>  "(return x)"
        "return x,y"  =>  "(return (tuple x y))"
        # break/continue
        "break"    => "(break)"
        "continue" => "(continue)"
        # module/baremodule
        "module A end"      =>  "(module true A (block))"
        "baremodule A end"  =>  "(module false A (block))"
        "module do \n end"  =>  "(module true (error (do)) (block))"
        "module \$A end"    =>  "(module true (\$ A) (block))"
        "module A \n a \n b \n end"  =>  "(module true A (block a b))"
        """module A \n "x"\na\n end""" => """(module true A (block (macrocall :(Core.var"@doc") "x" a)))"""
        # export
        "export a"  =>  "(export a)"
        "export @a"  =>  "(export @a)"
        "export a, \n @b"  =>  "(export a @b)"
        "export +, =="  =>  "(export + ==)"
        "export \n a"  =>  "(export a)"
        "export \$a, \$(a*b)"  =>  "(export (\$ a) (\$ (call-i a * b)))"
        "export (x::T)"  =>  "(export (error (:: x T)))"
        "export outer"  =>  "(export outer)"
        "export (\$f)"  =>  "(export (\$ f))"
    ],
    JuliaSyntax.parse_if_elseif => [
        "if a xx elseif b yy else zz end" => "(if a (block xx) (elseif (block b) (block yy) (block zz)))"
        "if end"        =>  "(if (error) (block))"
        "if \n end"     =>  "(if (error) (block))"
        "if a end"      =>  "(if a (block))"
        "if a xx end"   =>  "(if a (block xx))"
        "if a \n\n xx \n\n end"   =>  "(if a (block xx))"
        "if a xx elseif b yy end"   =>  "(if a (block xx) (elseif (block b) (block yy)))"
        "if a xx else if b yy end"  =>  "(if a (block xx) (error-t) (elseif (block b) (block yy)))"
        "if a xx else yy end"   =>  "(if a (block xx) (block yy))"
    ],
    JuliaSyntax.parse_const_local_global => [
        "global x"             =>  "(global x)"
        "local x"              =>  "(local x)"
        "global const x = 1"   =>  "(const (global (= x 1)))"
        "local const x = 1"    =>  "(const (local (= x 1)))"
        "const x = 1"          =>  "(const (= x 1))"
        "const global x = 1"   =>  "(const (global (= x 1)))"
        "const local x = 1"    =>  "(const (local (= x 1)))"
        "const x,y = 1,2"      =>  "(const (= (tuple x y) (tuple 1 2)))"
        ((v=v"1.8",), "const x,y")  => "(const (tuple x y))"
        "const x = 1"   =>  "(const (= x 1))"
        "global x ~ 1"  =>  "(global (call-i x ~ 1))"
        "global x += 1" =>  "(global (+= x 1))"
        "global x"    =>  "(global x)"
        "local x"     =>  "(local x)"
        "global x,y"  =>  "(global x y)"
        ((v=v"1.8",), "const x")      => "(const x)"
        ((v=v"1.8",), "const x::T")   => "(const (:: x T))"
        ((v=v"1.7",), "const x")      => "(const (error x))"
        ((v=v"1.7",), "const x .= 1") => "(const (error (.= x 1)))"
    ],
    JuliaSyntax.parse_function => [
        "macro while(ex) end"  =>  "(macro (call (error while) ex) (block))"
        "macro f()     end"    =>  "(macro (call f) (block))"
        "macro (:)(ex) end"    =>  "(macro (call : ex) (block))"
        "macro (type)(ex) end" =>  "(macro (call type ex) (block))"
        "macro \$f()    end"   =>  "(macro (call (\$ f)) (block))"
        "macro (\$f)()  end"   =>  "(macro (call (\$ f)) (block))"
        "function (x) body end"=>  "(function (tuple x) (block body))"
        "function (x,y) end"   =>  "(function (tuple x y) (block))"
        "function (x=1) end"   =>  "(function (tuple (kw x 1)) (block))"
        "function (;x=1) end"  =>  "(function (tuple (parameters (kw x 1))) (block))"
        "function (:)() end"   =>  "(function (call :) (block))"
        "function (x::T)() end"=>  "(function (call (:: x T)) (block))"
        "function (::T)() end" =>  "(function (call (:: T)) (block))"
        "function begin() end" =>  "(function (call (error begin)) (block))"
        "function f() end"     =>  "(function (call f) (block))"
        "function type() end"  =>  "(function (call type) (block))"
        "function \n f() end"  =>  "(function (call f) (block))"
        "function \$f() end"   =>  "(function (call (\$ f)) (block))"
        "function (:)() end"   =>  "(function (call :) (block))"
        "function (::Type{T})(x) end"  =>  "(function (call (:: (curly Type T)) x) (block))"
        # Function/macro definition with no methods
        "function f end"      =>  "(function f)"
        "function f \n\n end" =>  "(function f)"
        "function \$f end"    =>  "(function (\$ f))"
        "macro f end"         =>  "(macro f)"
        # Function argument list
        "function f(x,y) end"    =>  "(function (call f x y) (block))"
        "function f{T}() end"    =>  "(function (call (curly f T)) (block))"
        "function A.f()   end"   =>  "(function (call (. A (quote f))) (block))"
        "function f body end"    =>  "(function (error f) (block body))"
        "function f()::T    end" =>  "(function (:: (call f) T) (block))"
        "function f()::g(T) end" =>  "(function (:: (call f) (call g T)) (block))"
        "function f() where {T} end"  =>  "(function (where (call f) T) (block))"
        "function f() where T   end"  =>  "(function (where (call f) T) (block))"
        "function f() \n a \n b end"  =>  "(function (call f) (block a b))"
        "function f() end"       =>  "(function (call f) (block))"
    ],
    JuliaSyntax.parse_try => [
        "try \n x \n catch e \n y \n finally \n z end" =>
            "(try (block x) e (block y) false (block z))"
        ((v=v"1.8",), "try \n x \n catch e \n y \n else z finally \n w end") =>
            "(try (block x) e (block y) (block z) (block w))"
        "try x catch end"       =>  "(try (block x) false (block) false false)"
        "try x catch ; y end"   =>  "(try (block x) false (block y) false false)"
        "try x catch \n y end"  =>  "(try (block x) false (block y) false false)"
        "try x catch e y end"   =>  "(try (block x) e (block y) false false)"
        "try x catch \$e y end" =>  "(try (block x) (\$ e) (block y) false false)"
        "try x finally y end"   =>  "(try (block x) false false false (block y))"
        # v1.8 only
        ((v=v"1.8",), "try catch ; else end") => "(try (block) false (block) (block) false)"
        ((v=v"1.8",), "try else end") => "(try (block) false false (error (block)) false)"
        ((v=v"1.7",), "try catch ; else end")  =>  "(try (block) false (block) (error (block)) false)"
        # finally before catch :-(
        "try x finally y catch e z end"  =>  "(try-f (block x) false false false (block y) e (block z))"
    ],
    JuliaSyntax.parse_imports => [
        "import A as B: x"  => "(import (: (error (as (. A) B)) (. x)))"
        "import A, y"       => "(import (. A) (. y))"
        "import A: +, =="       => "(import (: (. A) (. +) (. ==)))"
        "import A: x, y"    => "(import (: (. A) (. x) (. y)))"
        "import A: x, B: y" => "(import (: (. A) (. x) (. B) (error-t (. y))))"
        "import A: x"       => "(import (: (. A) (. x)))"
        "using  A"          => "(using (. A))"
        "import A"          => "(import (. A))"
        # parse_import
        "import A: x, y"   =>  "(import (: (. A) (. x) (. y)))"
        "import A as B"    =>  "(import (as (. A) B))"
        "import A: x as y" =>  "(import (: (. A) (as (. x) y)))"
        "using  A: x as y" =>  "(using (: (. A) (as (. x) y)))"
        ((v=v"1.5",), "import A as B") =>  "(import (error (as (. A) B)))"
        "using A as B"     =>  "(using (error (as (. A) B)))"
        "using A, B as C"  =>  "(using (. A) (error (as (. B) C)))"
        # parse_import_path
        # When parsing import we must split initial dots into nontrivial
        # leading dots for relative paths
        "import .A"  =>  "(import (. . A))"
        "import ..A"  =>  "(import (. . . A))"
        "import ...A"  =>  "(import (. . . . A))"
        "import ....A"  =>  "(import (. . . . . A))"
        # Dots with spaces are allowed (a misfeature?)
        "import . .A"  =>  "(import (. . . A))"
        # Modules with operator symbol names
        "import .⋆"  =>  "(import (. . ⋆))"
        # Expressions allowed in import paths
        "import @x"  =>  "(import (. @x))"
        "import \$A"  =>  "(import (. (\$ A)))"
        "import \$A.@x"  =>  "(import (. (\$ A) @x))"
        "import A.B"  =>  "(import (. A B))"
        "import A.B.C"  =>  "(import (. A B C))"
        "import A.=="  =>  "(import (. A ==))"
        "import A.⋆.f" =>  "(import (. A ⋆ f))"
        "import A..."  =>  "(import (. A ..))"
        "import A; B"  =>  "(import (. A))"
    ],
    JuliaSyntax.parse_iteration_spec => [
        "i = rhs"        =>  "(= i rhs)"
        "i in rhs"       =>  "(= i rhs)"
        "i ∈ rhs"        =>  "(= i rhs)"
        "i = 1:10"       =>  "(= i (call-i 1 : 10))"
        "(i,j) in iter"  =>  "(= (tuple i j) iter)"
        "outer = rhs"       =>  "(= outer rhs)"
        "outer <| x = rhs"  =>  "(= (call-i outer <| x) rhs)"
        "outer i = rhs"     =>  "(= (outer i) rhs)"
        "outer (x,y) = rhs" =>  "(= (outer (tuple x y)) rhs)"
    ],
    JuliaSyntax.parse_paren => [
        # Tuple syntax with commas
        "()"          =>  "(tuple)"
        "(x,)"        =>  "(tuple x)"
        "(x,y)"       =>  "(tuple x y)"
        "(x=1, y=2)"  =>  "(tuple (= x 1) (= y 2))"
        # Named tuples with initial semicolon
        "(;)"         =>  "(tuple (parameters))"
        "(; a=1)"     =>  "(tuple (parameters (kw a 1)))"
        # Extra credit: nested parameters and frankentuples
        "(x...; y)"       => "(tuple (... x) (parameters y))"
        "(x...;)"         => "(tuple (... x) (parameters))"
        "(; a=1; b=2)"    => "(tuple (parameters (kw a 1) (parameters (kw b 2))))"
        "(a; b; c,d)"     => "(tuple a (parameters b (parameters c d)))"
        "(a=1, b=2; c=3)" => "(tuple (= a 1) (= b 2) (parameters (kw c 3)))"
        # Block syntax
        "(;;)"        =>  "(block)"
        "(a=1;)"      =>  "(block (= a 1))"
        "(a;b;;c)"    =>  "(block a b c)"
        "(a=1; b=2)"  =>  "(block (= a 1) (= b 2))"
        # Parentheses used for grouping
        "(a * b)"     =>  "(call-i a * b)"
        "(a=1)"       =>  "(= a 1)"
        "(x)"         =>  "x"
        "(a...)"      =>  "(... a)"
        # Generators
        "(x for a in as)"       =>  "(generator x (= a as))"
        "(x \n\n for a in as)"  =>  "(generator x (= a as))"
    ],
    JuliaSyntax.parse_atom => [
        ":foo"   => "(quote foo)"
        ": foo"  => "(quote (error-t) foo)"
        # Literal colons
        ":)"   => ":"
        ": end"   => ":"
        # var syntax
        """var"x" """  =>  "x"
        """var"x"+"""  =>  "x"
        """var"x")"""  =>  "x"
        """var"x"("""  =>  "x"
        """var"x"end"""  =>  "x (error (end))"
        """var"x"1"""  =>  "x (error 1)"
        """var"x"y"""  =>  "x (error y)"
        # var syntax raw string unescaping
        "var\"\""          =>  ""
        "var\"\\\"\""      =>  "\""
        "var\"\\\\\\\"\""  =>  "\\\""
        "var\"\\\\x\""     =>  "\\\\x"
        # Syntactic operators
        "+="  =>  "(error +=)"
        ".+="  =>  "(error .+=)"
        # Normal operators
        "+"  =>  "+"
        "~"  =>  "~"
        # Quoted syntactic operators allowed
        ":+="  =>  "(quote +=)"
        ":.="  =>  "(quote .=)"
        # Special symbols quoted
        ":end" => "(quote end)"
        ":(end)" => "(quote (error (end)))"
        ":<:"  => "(quote <:)"
        # parse_cat
        "[]"        =>  "(vect)"
        "[x,]"      =>  "(vect x)"
        "[x]"       =>  "(vect x)"
        "[x"        =>  "(vect x (error-t))"
        "[x \n ]"   =>  "(vect x)"
        "[x \n\n ]" =>  "(vect x)"
        "[x for a in as]"  =>  "(comprehension (generator x (= a as)))"
        "[x \n\n for a in as]"  =>  "(comprehension (generator x (= a as)))"
        # parse_generator
        "[x for a = as for b = bs if cond1 for c = cs if cond2]"  =>  "(comprehension (flatten x (= a as) (filter (= b bs) cond1) (filter (= c cs) cond2)))"
        "[(x)for x in xs]"  =>  "(comprehension (generator x (error-t) (= x xs)))"
        "(a for x in xs if cond)"  =>  "(generator a (filter (= x xs) cond))"
        "(xy for x in xs for y in ys)"  =>  "(flatten xy (= x xs) (= y ys))"
        "(xy for x in xs for y in ys for z in zs)"  =>  "(flatten xy (= x xs) (= y ys) (= z zs))"
        "(x for a in as)"  =>  "(generator x (= a as))"
        # parse_vect
        "[x, y]"        =>  "(vect x y)"
        "[x, y]"        =>  "(vect x y)"
        "[x,y ; z]"     =>  "(vect x y (parameters z))"
        "[x=1, y=2]"    =>  "(vect (= x 1) (= y 2))"
        "[x=1, ; y=2]"  =>  "(vect (= x 1) (parameters (= y 2)))"
        # parse_paren
        ":(=)"  =>  "(quote =)"
        ":(::)"  =>  "(quote ::)"
        "(function f \n end)" => "(function f)"
        # braces
        "{x y}"      =>  "(bracescat (row x y))"
        ((v=v"1.7",), "{x ;;; y}") =>  "(bracescat (nrow-3 x y))"
        # Macro names can be keywords
        "@end x" => "(macrocall @end x)"
        # __dot__ macro
        "@. x y" => "(macrocall @__dot__ x y)"
        # cmd strings
        "``"         =>  "(macrocall :(Core.var\"@cmd\") \"\")"
        "`cmd`"      =>  "(macrocall :(Core.var\"@cmd\") \"cmd\")"
        "```cmd```"  =>  "(macrocall :(Core.var\"@cmd\") \"cmd\")"
        # Errors
        ": foo" => "(quote (error-t) foo)"
    ],
    JuliaSyntax.parse_atom => [
        # Actually parse_array
        # Normal matrix construction syntax
        "[x y ; z w]"  =>  "(vcat (row x y) (row z w))"
        "[x y ; z w ; a b]"  =>  "(vcat (row x y) (row z w) (row a b))"
        "[x ; y ; z]"  =>  "(vcat x y z)"
        "[x;]"  =>  "(vcat x)"
        "[x y]"  =>  "(hcat x y)"
        # Mismatched rows
        "[x y ; z]"  =>  "(vcat (row x y) z)"
        # Single elements in rows
        ((v=v"1.7",), "[x ; y ;; z ]")  =>  "(ncat-2 (nrow-1 x y) z)"
        ((v=v"1.7",), "[x  y ;;; z ]")  =>  "(ncat-3 (row x y) z)"
        # Higher dimensional ncat
        # Row major
        ((v=v"1.7",), "[x y ; z w ;;; a b ; c d]")  =>
            "(ncat-3 (nrow-1 (row x y) (row z w)) (nrow-1 (row a b) (row c d)))"
        # Column major
        ((v=v"1.7",), "[x ; y ;; z ; w ;;; a ; b ;; c ; d]")  =>
            "(ncat-3 (nrow-2 (nrow-1 x y) (nrow-1 z w)) (nrow-2 (nrow-1 a b) (nrow-1 c d)))"
        # Array separators
        # Newlines before semicolons are not significant
        "[a \n ;]"  =>  "(vcat a)"
        # Newlines after semicolons are not significant
        "[a ; \n]"  =>  "(vcat a)"
        "[a ; \n\n b]"  =>  "(vcat a b)"
        ((v=v"1.7",), "[a ;; \n b]")  =>  "(ncat-2 a b)"
        # In hcat with spaces as separators, `;;` is a line
        # continuation character
        ((v=v"1.7",), "[a b ;; \n c]")  =>  "(hcat a b c)"
        ((v=v"1.7",), "[a b \n ;; c]")  =>  "(ncat-2 (row a b (error-t)) c)"
        # Can't mix spaces and multiple ;'s
        ((v=v"1.7",), "[a b ;; c]")  =>  "(ncat-2 (row a b (error-t)) c)"
        # Treat a linebreak prior to a value as a semicolon (ie, separator for
        # the first dimension) if no previous semicolons observed
        "[a \n b]"  =>  "(vcat a b)"
        # Can't mix multiple ;'s and spaces
        ((v=v"1.7",), "[a ;; b c]")  =>  "(ncat-2 a (row b (error-t) c))"
        # Empty nd arrays
        ((v=v"1.8",), "[;]")   =>  "(ncat-1)"
        ((v=v"1.8",), "[;;]")  =>  "(ncat-2)"
        ((v=v"1.8",), "[\n  ;; \n ]")  =>  "(ncat-2)"
        ((v=v"1.7",), "[;;]")  =>  "(ncat-2 (error))"
        # parse_string
        "\"a \$(x + y) b\""  =>  "(string \"a \" (call-i x + y) \" b\")"
        "\"hi\$(\"ho\")\""   =>  "(string \"hi\" (string \"ho\"))"
        "\"hi\$(\"\"\"ho\"\"\")\""  =>  "(string \"hi\" (string-s \"ho\"))"
        "\"a \$foo b\""  =>  "(string \"a \" foo \" b\")"
        "\"\$var\""      =>  "(string var)"
        "\"\$outer\""    =>  "(string outer)"
        "\"\$in\""       =>  "(string in)"
        # Triple-quoted dedenting:
        "\"\"\"\nx\"\"\""   =>  "\"x\""
        "\"\"\"\n\nx\"\"\"" =>  raw"""(string-s "\n" "x")"""
        # Various newlines (\n \r \r\n) and whitespace (' ' \t)
        "\"\"\"\n x\n y\"\"\""  =>  raw"""(string-s "x\n" "y")"""
        "\"\"\"\r x\r y\"\"\""  =>  raw"""(string-s "x\n" "y")"""
        "\"\"\"\r\n x\r\n y\"\"\""  =>  raw"""(string-s "x\n" "y")"""
        # Spaces or tabs or mixtures acceptable
        "\"\"\"\n\tx\n\ty\"\"\""  =>  raw"""(string-s "x\n" "y")"""
        "\"\"\"\n \tx\n \ty\"\"\""  =>  raw"""(string-s "x\n" "y")"""
        # Mismatched tab vs space not deindented
        # Find minimum common prefix in mismatched whitespace
        "\"\"\"\n\tx\n y\"\"\""  =>  raw"""(string-s "\tx\n" " y")"""
        "\"\"\"\n x\n  y\"\"\""  =>  raw"""(string-s "x\n" " y")"""
        "\"\"\"\n  x\n y\"\"\""  =>  raw"""(string-s " x\n" "y")"""
        "\"\"\"\n \tx\n  y\"\"\""  =>  raw"""(string-s "\tx\n" " y")"""
        "\"\"\"\n  x\n \ty\"\"\""  =>  raw"""(string-s " x\n" "\ty")"""
        # Empty lines don't affect dedenting
        "\"\"\"\n x\n\n y\"\"\""  =>  raw"""(string-s "x\n" "\n" "y")"""
        # Non-empty first line doesn't participate in deindentation
        "\"\"\" x\n y\"\"\""  =>  raw"""(string-s " x\n" "y")"""
        # Dedenting and interpolations
        "\"\"\"\n  \$a\n  \$b\"\"\""  =>  raw"""(string-s a "\n" b)"""
        "\"\"\"\n  \$a \n  \$b\"\"\""  =>  raw"""(string-s a " \n" b)"""
        "\"\"\"\n  \$a\n  \$b\n\"\"\""  =>  raw"""(string-s "  " a "\n" "  " b "\n")"""
        # Empty chunks after dedent are removed
        "\"\"\"\n \n \"\"\""  =>  "\"\\n\""
        # Newline at end of string
        "\"\"\"\n x\n y\n\"\"\""  =>  raw"""(string-s " x\n" " y\n")"""
        # Empty strings, or empty after triple quoted processing
        "\"\""              =>  "\"\""
        "\"\"\"\n  \"\"\""  =>  "\"\""
        # Missing delimiter
        "\"str"  =>  "\"str\" (error-t)"
        # String interpolations
        "\"\$x\$y\$z\""  =>  "(string x y z)"
        "\"\$(x)\""  =>  "(string x)"
        "\"\$x\""  =>  "(string x)"
        # Strings with embedded whitespace trivia
        "\"a\\\nb\""     =>  raw"""(string "a" "b")"""
        "\"a\\\rb\""     =>  raw"""(string "a" "b")"""
        "\"a\\\r\nb\""   =>  raw"""(string "a" "b")"""
        "\"a\\\n \tb\""  =>  raw"""(string "a" "b")"""
        # Strings with only a single valid string chunk
        "\"str\""  =>  "\"str\""
    ],
    JuliaSyntax.parse_docstring => [
        """ "notdoc" ]        """ => "\"notdoc\""
        """ "notdoc" \n]      """ => "\"notdoc\""
        """ "notdoc" \n\n foo """ => "\"notdoc\""
        """ "doc" \n foo      """ => """(macrocall :(Core.var"@doc") "doc" foo)"""
        """ "doc" foo         """ => """(macrocall :(Core.var"@doc") "doc" foo)"""
        """ "doc \$x" foo     """ => """(macrocall :(Core.var"@doc") (string "doc " x) foo)"""
        # Allow docstrings with embedded trailing whitespace trivia
        "\"\"\"\n doc\n \"\"\" foo"  => """(macrocall :(Core.var"@doc") "doc\\n" foo)"""
    ],
]

# Known bugs / incompatibilities
broken_tests = [
    JuliaSyntax.parse_atom => [
        """var""\"x""\""""  =>  "x"
        # Operator-named macros without spaces
        "@!x"   => "(macrocall @! x)"
        "@..x"  => "(macrocall @.. x)"
        "@.x"   => "(macrocall @__dot__ x)"
        # Invalid numeric literals, not juxtaposition
        "0b12" => "(error \"0b12\")"
        "0xex" => "(error \"0xex\")"
        # Square brackets without space in macrocall
        "@S[a,b]"  => "(macrocall S (vect a b))"
        "@S[a b]"  => "(macrocall S (hcat a b))"
        "@S[a; b]" => "(macrocall S (vcat a b))"
        "@S[a; b ;; c; d]" => "(macrocall S (ncat-2 (nrow-1 a b) (nrow-1 c d)))"
        # Bad character literals
        "'\\xff'"  => "(error '\\xff')"
        "'\\x80'"  => "(error '\\x80')"
        "'ab'"     => "(error 'ab')"
    ]
    JuliaSyntax.parse_call => [
        # kw's in ref
        "x[i=y]" => "(ref x (kw i y))"
    ]
    JuliaSyntax.parse_juxtapose => [
        # Want: "numeric constant \"10.\" cannot be implicitly multiplied because it ends with \".\""
        "10.x" => "(error (call * 10.0 x))"
    ]
]

@testset "Inline test cases" begin
    @testset "$production" for (production, test_specs) in tests
        @testset "$(repr(input))" for (input,output) in test_specs
            if !(input isa AbstractString)
                opts,input = input
            else
                opts = NamedTuple()
            end
            @test test_parse(production, input; opts...) == output
        end
    end
    @testset "Broken $production" for (production, test_specs) in broken_tests
        @testset "$(repr(input))" for (input,output) in test_specs
            if !(input isa AbstractString)
                opts,input = input
            else
                opts = NamedTuple()
            end
            @test_broken test_parse(production, input; opts...) == output
        end
    end
end

@testset "Unicode normalization in tree conversion" begin
    # ɛµ normalizes to εμ
    @test test_parse(JuliaSyntax.parse_eq, "\u025B\u00B5()") == "(call \u03B5\u03BC)"
    @test test_parse(JuliaSyntax.parse_eq, "@\u025B\u00B5") == "(macrocall @\u03B5\u03BC)"
    @test test_parse(JuliaSyntax.parse_eq, "\u025B\u00B5\"\"") == "(macrocall @\u03B5\u03BC_str \"\")"
    @test test_parse(JuliaSyntax.parse_eq, "\u025B\u00B5``") == "(macrocall @\u03B5\u03BC_cmd \"\")"
    # · and · normalize to ⋅
    @test test_parse(JuliaSyntax.parse_eq, "a \u00B7 b") == "(call-i a \u22C5 b)"
    @test test_parse(JuliaSyntax.parse_eq, "a \u0387 b") == "(call-i a \u22C5 b)"
    # − normalizes to -
    @test test_parse(JuliaSyntax.parse_expr, "a \u2212 b")  == "(call-i a - b)"
    @test test_parse(JuliaSyntax.parse_eq, "a \u2212= b") == "(-= a b)"
    @test test_parse(JuliaSyntax.parse_eq, "a .\u2212= b") == "(.-= a b)"
end


text:
##
# Here, we copy a few definitions from TimeSpans.jl in order to not depend on internals
# https://github.com/beacon-biosignals/TimeSpans.jl/blob/e3c999021336e51a08d118e6defb792e38ac1cc7/src/TimeSpans.jl

const NS_IN_SEC = Dates.value(Nanosecond(Second(1)))  # Number of nanoseconds in one second

# Tweaked from TimeSpans version: https://github.com/beacon-biosignals/AlignedSpans.jl/pull/2#discussion_r829582819
nanoseconds_per_sample(sample_rate) = NS_IN_SEC / sample_rate

function time_from_index(sample_rate, sample_index)
    sample_index > 0 || throw(ArgumentError("`sample_index` must be > 0"))
    return Nanosecond(ceil(Int, (sample_index - 1) * nanoseconds_per_sample(sample_rate)))
end
#
##

# Helper to get the index and the rounding error in units of time
function index_and_error_from_time(sample_rate, sample_time::Period, mode::RoundingMode)
    time_in_nanoseconds = Dates.value(convert(Nanosecond, sample_time))
    time_in_nanoseconds >= 0 ||
        throw(ArgumentError("`sample_time` must be >= 0 nanoseconds"))
    time_in_seconds = time_in_nanoseconds / NS_IN_SEC
    floating_index = time_in_seconds * sample_rate + 1
    index = round(Int, floating_index, mode)
    return index, time_from_index(sample_rate, index) - sample_time
end

"""
    n_samples(sample_rate, duration::Period)

Returns the minimal number of samples that can occur in a span of duration `duration`.
"""
function n_samples(sample_rate, duration::Period)
    duration_in_nanoseconds = Dates.value(convert(Nanosecond, duration))
    duration_in_nanoseconds >= 0 ||
        throw(ArgumentError("`duration` must be >= 0 nanoseconds"))
    duration_in_seconds = duration_in_nanoseconds / NS_IN_SEC
    n_indices = duration_in_seconds * sample_rate
    return floor(Int, n_indices)
end


text:
include("TestShader.jl")
include("TestVertexInputState.jl")
include("TestRenderpass.jl")

mutable struct CameraData
    view::Mat4f0
    proj::Mat4f0

    CameraData() = new(Mat4f0(1I), Mat4f0(1I))
    CameraData(view::Mat4f0, proj::Mat4f0) = new(view, proj)
end
@class CameraData

function testCreateGraphicsPipeline(device, glfw, pipelineRef::Ref, passRef::Ref)
    plLayout = device.createPipelineLayout(CameraData)
    @test testDescriptorSetLayout(device)

    @test testRenderPass(device, glfw, passRef)

    stagesRef = Ref{Vector}()
    @test testShaderStages(device, stagesRef)

    inputStateRef = Ref{lava.PipelineVertexInputStateCreateInfo}()
    @test testVertexInputState(inputStateRef)

    ci = lava.defaults(lava.GraphicsPipelineCreateInfo,
        stages = stagesRef[],
        layout = plLayout,
        renderPass = lava.handleRef(passRef[])[],
        subpass = UInt32(0),
        depthTestEnable = VkExt.VK_TRUE,
        depthWriteEnable = VkExt.VK_TRUE,
        # Due to the flipped y axis in NDC, the triangle winding order is inverted, too
        frontFace = vk.VK_FRONT_FACE_CLOCKWISE,
        inputState = inputStateRef[]
    )
    pipeline = lava.GraphicsPipeline(ci)
    pipelineRef[] = pipeline
    return true
end

function testGraphicsPipelineFlag()
    createFlagRef = Ref{vk.VkPipelineCreateFlags}()
    lava.deriveFrom(createFlagRef)
    @test createFlagRef[] & vk.VK_PIPELINE_CREATE_DERIVATIVE_BIT != 0
    lava.allowDerivatives(createFlagRef, true)
    @test createFlagRef[] & vk.VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT != 0
    lava.allowDerivatives(createFlagRef, false)
    @test createFlagRef[] & vk.VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT == 0
    lava.disableOptimization(createFlagRef, true)
    @test createFlagRef[] & vk.VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT != 0
    lava.disableOptimization(createFlagRef, false)
    @test createFlagRef[] & vk.VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT == 0

    @test testColorBlendStateFlag()

    return true
end

function testColorBlendStateFlag()
    states = Vector{vk.VkPipelineColorBlendAttachmentState}()
    lava.addNoBlend(states)
    lava.addTransparencyBlend(states)
    @test length(states) == 2
    return true
end


text:
module SetOperations

import Base: eltype, tail, in, issubset

abstract type Style end
struct VectorStyle <: Style end
struct SetStyle <: Style end
struct Unknown <: Style end

Style(::Type{<:AbstractSet}) = SetStyle()
Style(::Type) = VectorStyle()

Style(::S, ::S) where S<:Style = S() # homogeneous types preserved
# Fall back to Unknown. This is necessary to implement argument-swapping
Style(::Style, ::Style) = Unknown()
# Unknown loses to everything
Style(::Unknown, ::Unknown) = Unknown()
Style(::SetStyle, ::VectorStyle) = SetStyle()

# Code adapted from julia/base/broadcast.jl

# combine_styles operates on values (arbitrarily many)
combine_styles() = VectorStyle()
combine_styles(c) = result_style(Style(typeof(c)))
combine_styles(c1, c2) = result_style(combine_styles(c1), combine_styles(c2))
@inline combine_styles(c1, c2, cs...) = result_style(combine_styles(c1), combine_styles(c2, cs...))

# result_style works on types (singletons and pairs), and leverages `Style`
result_style(s::Style) = s
result_style(s1::S, s2::S) where S<:Style = S()
# Test both orders so users typically only have to declare one order
result_style(s1, s2) = result_join(s1, s2, Style(s1, s2), Style(s2, s1))

# result_join is the final arbiter. Because `Style` for undeclared pairs results in Unknown,
# we defer to any case where the result of `Style` is known.
result_join(::Any, ::Any, ::Unknown, ::Unknown)   = Unknown()
result_join(::Any, ::Any, ::Unknown, s::Style) = s
result_join(::Any, ::Any, s::Style, ::Unknown) = s
# For AbstractArray types with specialized broadcasting and undefined precedence rules,
# we have to signal conflict. Because ArrayConflict is a subtype of AbstractArray,
# this will "poison" any future operations (if we instead returned `DefaultArrayStyle`, then for
# 3-array broadcasting the returned type would depend on argument order).
result_join(::VectorStyle, ::VectorStyle, ::Unknown, ::Unknown) =
    ArrayConflict()
# Fallbacks in case users define `rule` for both argument-orders (not recommended)
result_join(::Any, ::Any, ::S, ::S) where S<:Style = S()
@noinline function result_join(::S, ::T, ::U, ::V) where {S,T,U,V}
    error("""
conflicting broadcast rules defined
  LazyArays.Style(::$S, ::$T) = $U()
  LazyArays.Style(::$T, ::$S) = $V()
One of these should be undefined (and thus return Unknown).""")
end

abstract type SetOperation{Style} end

for Typ in (:Unioned, :Intersected, :SetDiffed)
    @eval begin
        struct $Typ{Style, Args<:Tuple} <: SetOperation{Style}
            args::Args
        end

        $Typ(args) = $Typ{typeof(combine_styles(args...))}(args)
        $Typ{Style}(args) where Style = $Typ{Style, typeof(args)}(args)
    end
end

eltype(u::SetOperation) = mapreduce(eltype, promote_type, u.args)

emptymutable(::SetOperation{SetStyle}, ::Type{T}) where T = Set{T}()
emptymutable(::SetOperation{VectorStyle}, ::Type{T}) where T = Vector{T}()

emptymutable(u::SetOperation) = emptymutable(u, eltype(u))

materialize(u::SetOperation) = copy(u)

unioned(args...) = Unioned(args)
union(a...) = materialize(unioned(a...))
intersected(args...) = Intersected(args)
intersect(a...) = materialize(intersected(a...))
setdiffed(args...) = SetDiffed(args)
setdiff(a...) = materialize(setdiffed(a...))

const ∪ = union
const ∩ = intersect

copy(u::Unioned) = union!(emptymutable(u), u.args...)
copy(u::Intersected) = intersect!(emptymutable(u), u.args...)
copy(u::SetDiffed) = setdiff!(emptymutable(u), u.args...)

function in(x, u::Unioned)
    for d in u.args
        x ∈ d && return true
    end
    return false
end

function in(x, u::Intersected)
    for d in u.args
        x ∈ d || return false
    end
    return true
end

function in(x, u::SetDiffed)
    x ∈ first(u.args) || return false
    for d in tail(u.args)
        x ∈ d && return false
    end
    return true
end

function issubset(l, r::SetOperation)
    for x in l
        x ∈ r || return false
    end
    return true
end

end # SetOperations


text:
assetpath(files...) =  joinpath(dirname(@__DIR__), "assets", files...)

const LOAD_CACHE = Dict{String, Any}()

function earth()
    return get!(LOAD_CACHE, "earth") do
        FileIO.load(assetpath("raster", "50-natural-earth-1-downsampled.png"))
    end
end

function coastlines()
    return get!(LOAD_CACHE, "coastlines") do
        geometry = GeoJSON.read(read(assetpath("vector", "110m_coastline.geojson"), String))
        return geo2basic(geometry)
    end
end


text:
# RUN: julia -e "import Brutus; Brutus.lit(:emit_optimized)" --startup-file=no %s 2>&1 | FileCheck %s

function sum(A)
    acc = zero(eltype(A))
    for i in 1:prod(size(A))
        acc += A[i]
    end
    return acc
end

emit(sum, Matrix{Float64})

# CHECK:   func nested @"Tuple{typeof(Main.sum), Array{Float64, 2}}"(%arg0: !jlir<"typeof(Main.sum)">, %arg1: !jlir<"Array{Float64, 2}">) -> !jlir.Float64 attributes {llvm.emit_c_interface} {
# CHECK-NEXT:     "jlir.goto"()[^bb1] : () -> ()
# CHECK-NEXT:   ^bb1:  // pred: ^bb0
# CHECK-NEXT:     %0 = "jlir.constant"() {value = #jlir<"1">} : () -> !jlir.Int64
# CHECK-NEXT:     %1 = "jlir.arraysize"(%arg1, %0) : (!jlir<"Array{Float64, 2}">, !jlir.Int64) -> !jlir.Int64
# CHECK-NEXT:     %2 = "jlir.constant"() {value = #jlir<"2">} : () -> !jlir.Int64
# CHECK-NEXT:     %3 = "jlir.arraysize"(%arg1, %2) : (!jlir<"Array{Float64, 2}">, !jlir.Int64) -> !jlir.Int64
# CHECK-NEXT:     %4 = "jlir.mul_int"(%1, %3) : (!jlir.Int64, !jlir.Int64) -> !jlir.Int64
# CHECK-NEXT:     %5 = "jlir.sle_int"(%0, %4) : (!jlir.Int64, !jlir.Int64) -> !jlir.Bool
# CHECK-NEXT:     %6 = "jlir.constant"() {value = #jlir<"0">} : () -> !jlir.Int64
# CHECK-NEXT:     %7 = "jlir.ifelse"(%5, %4, %6) : (!jlir.Bool, !jlir.Int64, !jlir.Int64) -> !jlir.Int64
# CHECK-NEXT:     %8 = "jlir.slt_int"(%7, %0) : (!jlir.Int64, !jlir.Int64) -> !jlir.Bool
# CHECK-NEXT:     "jlir.gotoifnot"(%8)[^bb3, ^bb2] {operand_segment_sizes = dense<[1, 0, 0]> : vector<3xi32>} : (!jlir.Bool) -> ()
# CHECK-NEXT:   ^bb2:  // pred: ^bb1
# CHECK-NEXT:     %9 = "jlir.constant"() {value = #jlir.true} : () -> !jlir.Bool
# CHECK-NEXT:     %10 = "jlir.undef"() : () -> !jlir.Int64
# CHECK-NEXT:     %11 = "jlir.undef"() : () -> !jlir.Int64
# CHECK-NEXT:     "jlir.goto"(%9, %10, %11)[^bb4] : (!jlir.Bool, !jlir.Int64, !jlir.Int64) -> ()
# CHECK-NEXT:   ^bb3:  // pred: ^bb1
# CHECK-NEXT:     %12 = "jlir.constant"() {value = #jlir.false} : () -> !jlir.Bool
# CHECK-NEXT:     "jlir.goto"(%12, %0, %0)[^bb4] : (!jlir.Bool, !jlir.Int64, !jlir.Int64) -> ()
# CHECK-NEXT:   ^bb4(%13: !jlir.Bool, %14: !jlir.Int64, %15: !jlir.Int64):  // 2 preds: ^bb2, ^bb3
# CHECK-NEXT:     %16 = "jlir.not_int"(%13) : (!jlir.Bool) -> !jlir.Bool
# CHECK-NEXT:     %17 = "jlir.constant"() {value = #jlir<"0">} : () -> !jlir.Float64
# CHECK-NEXT:     "jlir.gotoifnot"(%16, %17, %14, %15, %17)[^bb10, ^bb5] {operand_segment_sizes = dense<[1, 1, 3]> : vector<3xi32>} : (!jlir.Bool, !jlir.Float64, !jlir.Int64, !jlir.Int64, !jlir.Float64) -> ()
# CHECK-NEXT:   ^bb5(%18: !jlir.Int64, %19: !jlir.Int64, %20: !jlir.Float64):  // 2 preds: ^bb4, ^bb9
# CHECK-NEXT:     %21 = "jlir.constant"() {value = #jlir.true} : () -> !jlir.Bool
# CHECK-NEXT:     %22 = "jlir.arrayref"(%21, %arg1, %18) : (!jlir.Bool, !jlir<"Array{Float64, 2}">, !jlir.Int64) -> !jlir.Float64
# CHECK-NEXT:     %23 = "jlir.add_float"(%20, %22) : (!jlir.Float64, !jlir.Float64) -> !jlir.Float64
# CHECK-NEXT:     %24 = "jlir.==="(%19, %7) : (!jlir.Int64, !jlir.Int64) -> !jlir.Bool
# CHECK-NEXT:     "jlir.gotoifnot"(%24)[^bb7, ^bb6] {operand_segment_sizes = dense<[1, 0, 0]> : vector<3xi32>} : (!jlir.Bool) -> ()
# CHECK-NEXT:   ^bb6:  // pred: ^bb5
# CHECK-NEXT:     %25 = "jlir.undef"() : () -> !jlir.Int64
# CHECK-NEXT:     %26 = "jlir.undef"() : () -> !jlir.Int64
# CHECK-NEXT:     "jlir.goto"(%25, %26, %21)[^bb8] : (!jlir.Int64, !jlir.Int64, !jlir.Bool) -> ()
# CHECK-NEXT:   ^bb7:  // pred: ^bb5
# CHECK-NEXT:     %27 = "jlir.add_int"(%19, %0) : (!jlir.Int64, !jlir.Int64) -> !jlir.Int64
# CHECK-NEXT:     %28 = "jlir.constant"() {value = #jlir.false} : () -> !jlir.Bool
# CHECK-NEXT:     "jlir.goto"(%27, %27, %28)[^bb8] : (!jlir.Int64, !jlir.Int64, !jlir.Bool) -> ()
# CHECK-NEXT:   ^bb8(%29: !jlir.Int64, %30: !jlir.Int64, %31: !jlir.Bool):  // 2 preds: ^bb6, ^bb7
# CHECK-NEXT:     %32 = "jlir.not_int"(%31) : (!jlir.Bool) -> !jlir.Bool
# CHECK-NEXT:     "jlir.gotoifnot"(%32, %23)[^bb10, ^bb9] {operand_segment_sizes = dense<[1, 1, 0]> : vector<3xi32>} : (!jlir.Bool, !jlir.Float64) -> ()
# CHECK-NEXT:   ^bb9:  // pred: ^bb8
# CHECK-NEXT:     "jlir.goto"(%29, %30, %23)[^bb5] : (!jlir.Int64, !jlir.Int64, !jlir.Float64) -> ()
# CHECK-NEXT:   ^bb10(%33: !jlir.Float64):  // 2 preds: ^bb4, ^bb8
# CHECK-NEXT:     "jlir.return"(%33) : (!jlir.Float64) -> ()
# CHECK-NEXT:   }
# CHECK-NEXT: }

max_stars_repo_name: femtomc/brutus

max_issues_repo_name: femtomc/brutus

max_forks_repo_name: femtomc/brutus