text:
"""
Information about pagination in a connection.
"""
mutable struct PageInfo
    "When paginating forwards, are there more items?"
    hasNextPage::Bool
    "When paginating backwards, are there more items?"
    hasPreviousPage::Bool
    "When paginating backwards, the cursor to continue."
    startCursor::Union{String,Missing,Nothing}
    "When paginating forwards, the cursor to continue."
    endCursor::Union{String,Missing,Nothing}
end
function PageInfo(;
    hasNextPage,
    hasPreviousPage,
    startCursor = nothing,
    endCursor = nothing,
)
    PageInfo(hasNextPage, hasPreviousPage, startCursor, endCursor)
end
StructTypes.StructType(::Type{PageInfo}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PageInfo}) = true

"""
An edge in a connection.
"""
mutable struct FilmCharactersEdge
    node::Any
    "A cursor for use in pagination"
    cursor::String
end
function FilmCharactersEdge(; node = nothing, cursor)
    FilmCharactersEdge(node, cursor)
end
StructTypes.StructType(::Type{FilmCharactersEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmCharactersEdge}) = true
function Base.getproperty(t::FilmCharactersEdge, sym::Symbol)
    if s === Symbol("node")
        getfield(t, Symbol("node"))::Union{Person,Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A connection to a list of items.
"""
mutable struct FilmCharactersConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{FilmCharactersEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    characters::Any
end
function FilmCharactersConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    characters = nothing,
)
    FilmCharactersConnection(pageInfo, edges, totalCount, characters)
end
StructTypes.StructType(::Type{FilmCharactersConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmCharactersConnection}) = true
function Base.getproperty(t::FilmCharactersConnection, sym::Symbol)
    if s === Symbol("characters")
        getfield(
            t,
            Symbol("characters"),
        )::Union{Vector{Union{Person,Missing,Nothing}},Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
An edge in a connection.
"""
mutable struct StarshipFilmsEdge
    node::Any
    "A cursor for use in pagination"
    cursor::String
end
function StarshipFilmsEdge(; node = nothing, cursor)
    StarshipFilmsEdge(node, cursor)
end
StructTypes.StructType(::Type{StarshipFilmsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{StarshipFilmsEdge}) = true
function Base.getproperty(t::StarshipFilmsEdge, sym::Symbol)
    if s === Symbol("node")
        getfield(t, Symbol("node"))::Union{Film,Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A connection to a list of items.
"""
mutable struct StarshipFilmsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{StarshipFilmsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    films::Any
end
function StarshipFilmsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    films = nothing,
)
    StarshipFilmsConnection(pageInfo, edges, totalCount, films)
end
StructTypes.StructType(::Type{StarshipFilmsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{StarshipFilmsConnection}) = true
function Base.getproperty(t::StarshipFilmsConnection, sym::Symbol)
    if s === Symbol("films")
        getfield(
            t,
            Symbol("films"),
        )::Union{Vector{Union{Film,Missing,Nothing}},Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
An edge in a connection.
"""
mutable struct StarshipPilotsEdge
    node::Any
    "A cursor for use in pagination"
    cursor::String
end
function StarshipPilotsEdge(; node = nothing, cursor)
    StarshipPilotsEdge(node, cursor)
end
StructTypes.StructType(::Type{StarshipPilotsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{StarshipPilotsEdge}) = true
function Base.getproperty(t::StarshipPilotsEdge, sym::Symbol)
    if s === Symbol("node")
        getfield(t, Symbol("node"))::Union{Person,Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A connection to a list of items.
"""
mutable struct StarshipPilotsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{StarshipPilotsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    pilots::Any
end
function StarshipPilotsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    pilots = nothing,
)
    StarshipPilotsConnection(pageInfo, edges, totalCount, pilots)
end
StructTypes.StructType(::Type{StarshipPilotsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{StarshipPilotsConnection}) = true
function Base.getproperty(t::StarshipPilotsConnection, sym::Symbol)
    if s === Symbol("pilots")
        getfield(
            t,
            Symbol("pilots"),
        )::Union{Vector{Union{Person,Missing,Nothing}},Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A single transport craft that has hyperdrive capability.
"""
mutable struct Starship
    "The name of this starship. The common name, such as \"Death Star\"."
    name::Union{String,Missing,Nothing}
    "\n  The model or official name of this starship. Such as \"T-65 X-wing\" or \"DS-1\n  Orbital Battle Station\".\n  "
    model::Union{String,Missing,Nothing}
    "\n  The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile\n  Battlestation\"\n  "
    starshipClass::Union{String,Missing,Nothing}
    "The manufacturers of this starship."
    manufacturers::Union{Vector{Union{String,Missing,Nothing}},Missing,Nothing}
    "The cost of this starship new, in galactic credits."
    costInCredits::Union{Float64,Missing,Nothing}
    "The length of this starship in meters."
    length::Union{Float64,Missing,Nothing}
    "The number of personnel needed to run or pilot this starship."
    crew::Union{String,Missing,Nothing}
    "The number of non-essential people this starship can transport."
    passengers::Union{String,Missing,Nothing}
    "\n  The maximum speed of this starship in atmosphere. null if this starship is\n  incapable of atmosphering flight.\n  "
    maxAtmospheringSpeed::Union{Int32,Missing,Nothing}
    "The class of this starships hyperdrive."
    hyperdriveRating::Union{Float64,Missing,Nothing}
    "\n  The Maximum number of Megalights this starship can travel in a standard hour.\n  A \"Megalight\" is a standard unit of distance and has never been defined before\n  within the Star Wars universe. This figure is only really useful for measuring\n  the difference in speed of starships. We can assume it is similar to AU, the\n  distance between our Sun (Sol) and Earth.\n  "
    MGLT::Union{Int32,Missing,Nothing}
    "The maximum number of kilograms that this starship can transport."
    cargoCapacity::Union{Float64,Missing,Nothing}
    "\n  The maximum length of time that this starship can provide consumables for its\n  entire crew without having to resupply.\n  "
    consumables::Union{String,Missing,Nothing}
    pilotConnection::Union{StarshipPilotsConnection,Missing,Nothing}
    filmConnection::Union{StarshipFilmsConnection,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was created."
    created::Union{String,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was edited."
    edited::Union{String,Missing,Nothing}
    "The ID of an object"
    id::String
end
function Starship(;
    name = nothing,
    model = nothing,
    starshipClass = nothing,
    manufacturers = nothing,
    costInCredits = nothing,
    length = nothing,
    crew = nothing,
    passengers = nothing,
    maxAtmospheringSpeed = nothing,
    hyperdriveRating = nothing,
    MGLT = nothing,
    cargoCapacity = nothing,
    consumables = nothing,
    pilotConnection = nothing,
    filmConnection = nothing,
    created = nothing,
    edited = nothing,
    id,
)
    Starship(
        name,
        model,
        starshipClass,
        manufacturers,
        costInCredits,
        length,
        crew,
        passengers,
        maxAtmospheringSpeed,
        hyperdriveRating,
        MGLT,
        cargoCapacity,
        consumables,
        pilotConnection,
        filmConnection,
        created,
        edited,
        id,
    )
end
StructTypes.StructType(::Type{Starship}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{Starship}) = true

"""
An edge in a connection.
"""
mutable struct FilmStarshipsEdge
    "The item at the end of the edge"
    node::Union{Starship,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function FilmStarshipsEdge(; node = nothing, cursor)
    FilmStarshipsEdge(node, cursor)
end
StructTypes.StructType(::Type{FilmStarshipsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmStarshipsEdge}) = true

"""
A connection to a list of items.
"""
mutable struct FilmStarshipsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{FilmStarshipsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    starships::Union{Vector{Union{Starship,Missing,Nothing}},Missing,Nothing}
end
function FilmStarshipsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    starships = nothing,
)
    FilmStarshipsConnection(pageInfo, edges, totalCount, starships)
end
StructTypes.StructType(::Type{FilmStarshipsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmStarshipsConnection}) = true

"""
An edge in a connection.
"""
mutable struct FilmVehiclesEdge
    node::Any
    "A cursor for use in pagination"
    cursor::String
end
function FilmVehiclesEdge(; node = nothing, cursor)
    FilmVehiclesEdge(node, cursor)
end
StructTypes.StructType(::Type{FilmVehiclesEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmVehiclesEdge}) = true
function Base.getproperty(t::FilmVehiclesEdge, sym::Symbol)
    if s === Symbol("node")
        getfield(t, Symbol("node"))::Union{Vehicle,Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A connection to a list of items.
"""
mutable struct FilmVehiclesConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{FilmVehiclesEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    vehicles::Any
end
function FilmVehiclesConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    vehicles = nothing,
)
    FilmVehiclesConnection(pageInfo, edges, totalCount, vehicles)
end
StructTypes.StructType(::Type{FilmVehiclesConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmVehiclesConnection}) = true
function Base.getproperty(t::FilmVehiclesConnection, sym::Symbol)
    if s === Symbol("vehicles")
        getfield(
            t,
            Symbol("vehicles"),
        )::Union{Vector{Union{Vehicle,Missing,Nothing}},Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
An edge in a connection.
"""
mutable struct FilmPlanetsEdge
    node::Any
    "A cursor for use in pagination"
    cursor::String
end
function FilmPlanetsEdge(; node = nothing, cursor)
    FilmPlanetsEdge(node, cursor)
end
StructTypes.StructType(::Type{FilmPlanetsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmPlanetsEdge}) = true
function Base.getproperty(t::FilmPlanetsEdge, sym::Symbol)
    if s === Symbol("node")
        getfield(t, Symbol("node"))::Union{Planet,Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A connection to a list of items.
"""
mutable struct FilmPlanetsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{FilmPlanetsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    planets::Any
end
function FilmPlanetsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    planets = nothing,
)
    FilmPlanetsConnection(pageInfo, edges, totalCount, planets)
end
StructTypes.StructType(::Type{FilmPlanetsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmPlanetsConnection}) = true
function Base.getproperty(t::FilmPlanetsConnection, sym::Symbol)
    if s === Symbol("planets")
        getfield(
            t,
            Symbol("planets"),
        )::Union{Vector{Union{Planet,Missing,Nothing}},Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
An edge in a connection.
"""
mutable struct SpeciesFilmsEdge
    node::Any
    "A cursor for use in pagination"
    cursor::String
end
function SpeciesFilmsEdge(; node = nothing, cursor)
    SpeciesFilmsEdge(node, cursor)
end
StructTypes.StructType(::Type{SpeciesFilmsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{SpeciesFilmsEdge}) = true
function Base.getproperty(t::SpeciesFilmsEdge, sym::Symbol)
    if s === Symbol("node")
        getfield(t, Symbol("node"))::Union{Film,Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A connection to a list of items.
"""
mutable struct SpeciesFilmsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{SpeciesFilmsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    films::Any
end
function SpeciesFilmsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    films = nothing,
)
    SpeciesFilmsConnection(pageInfo, edges, totalCount, films)
end
StructTypes.StructType(::Type{SpeciesFilmsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{SpeciesFilmsConnection}) = true
function Base.getproperty(t::SpeciesFilmsConnection, sym::Symbol)
    if s === Symbol("films")
        getfield(
            t,
            Symbol("films"),
        )::Union{Vector{Union{Film,Missing,Nothing}},Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
An edge in a connection.
"""
mutable struct SpeciesPeopleEdge
    node::Any
    "A cursor for use in pagination"
    cursor::String
end
function SpeciesPeopleEdge(; node = nothing, cursor)
    SpeciesPeopleEdge(node, cursor)
end
StructTypes.StructType(::Type{SpeciesPeopleEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{SpeciesPeopleEdge}) = true
function Base.getproperty(t::SpeciesPeopleEdge, sym::Symbol)
    if s === Symbol("node")
        getfield(t, Symbol("node"))::Union{Person,Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A connection to a list of items.
"""
mutable struct SpeciesPeopleConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{SpeciesPeopleEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    people::Any
end
function SpeciesPeopleConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    people = nothing,
)
    SpeciesPeopleConnection(pageInfo, edges, totalCount, people)
end
StructTypes.StructType(::Type{SpeciesPeopleConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{SpeciesPeopleConnection}) = true
function Base.getproperty(t::SpeciesPeopleConnection, sym::Symbol)
    if s === Symbol("people")
        getfield(
            t,
            Symbol("people"),
        )::Union{Vector{Union{Person,Missing,Nothing}},Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A type of person or character within the Star Wars Universe.
"""
mutable struct Species
    "The name of this species."
    name::Union{String,Missing,Nothing}
    "The classification of this species, such as \"mammal\" or \"reptile\"."
    classification::Union{String,Missing,Nothing}
    "The designation of this species, such as \"sentient\"."
    designation::Union{String,Missing,Nothing}
    "The average height of this species in centimeters."
    averageHeight::Union{Float64,Missing,Nothing}
    "The average lifespan of this species in years, null if unknown."
    averageLifespan::Union{Int32,Missing,Nothing}
    "\n  Common eye colors for this species, null if this species does not typically\n  have eyes.\n  "
    eyeColors::Union{Vector{Union{String,Missing,Nothing}},Missing,Nothing}
    "\n  Common hair colors for this species, null if this species does not typically\n  have hair.\n  "
    hairColors::Union{Vector{Union{String,Missing,Nothing}},Missing,Nothing}
    "\n  Common skin colors for this species, null if this species does not typically\n  have skin.\n  "
    skinColors::Union{Vector{Union{String,Missing,Nothing}},Missing,Nothing}
    "The language commonly spoken by this species."
    language::Union{String,Missing,Nothing}
    homeworld::Any
    personConnection::Union{SpeciesPeopleConnection,Missing,Nothing}
    filmConnection::Union{SpeciesFilmsConnection,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was created."
    created::Union{String,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was edited."
    edited::Union{String,Missing,Nothing}
    "The ID of an object"
    id::String
end
function Species(;
    name = nothing,
    classification = nothing,
    designation = nothing,
    averageHeight = nothing,
    averageLifespan = nothing,
    eyeColors = nothing,
    hairColors = nothing,
    skinColors = nothing,
    language = nothing,
    homeworld = nothing,
    personConnection = nothing,
    filmConnection = nothing,
    created = nothing,
    edited = nothing,
    id,
)
    Species(
        name,
        classification,
        designation,
        averageHeight,
        averageLifespan,
        eyeColors,
        hairColors,
        skinColors,
        language,
        homeworld,
        personConnection,
        filmConnection,
        created,
        edited,
        id,
    )
end
StructTypes.StructType(::Type{Species}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{Species}) = true
function Base.getproperty(t::Species, sym::Symbol)
    if s === Symbol("homeworld")
        getfield(t, Symbol("homeworld"))::Union{Planet,Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
An edge in a connection.
"""
mutable struct FilmSpeciesEdge
    "The item at the end of the edge"
    node::Union{Species,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function FilmSpeciesEdge(; node = nothing, cursor)
    FilmSpeciesEdge(node, cursor)
end
StructTypes.StructType(::Type{FilmSpeciesEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmSpeciesEdge}) = true

"""
A connection to a list of items.
"""
mutable struct FilmSpeciesConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{FilmSpeciesEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    species::Union{Vector{Union{Species,Missing,Nothing}},Missing,Nothing}
end
function FilmSpeciesConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    species = nothing,
)
    FilmSpeciesConnection(pageInfo, edges, totalCount, species)
end
StructTypes.StructType(::Type{FilmSpeciesConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmSpeciesConnection}) = true

"""
A single film.
"""
mutable struct Film
    "The title of this film."
    title::Union{String,Missing,Nothing}
    "The episode number of this film."
    episodeID::Union{Int32,Missing,Nothing}
    "The opening paragraphs at the beginning of this film."
    openingCrawl::Union{String,Missing,Nothing}
    "The name of the director of this film."
    director::Union{String,Missing,Nothing}
    "The name(s) of the producer(s) of this film."
    producers::Union{Vector{Union{String,Missing,Nothing}},Missing,Nothing}
    "The ISO 8601 date format of film release at original creator country."
    releaseDate::Union{String,Missing,Nothing}
    speciesConnection::Union{FilmSpeciesConnection,Missing,Nothing}
    starshipConnection::Union{FilmStarshipsConnection,Missing,Nothing}
    vehicleConnection::Union{FilmVehiclesConnection,Missing,Nothing}
    characterConnection::Union{FilmCharactersConnection,Missing,Nothing}
    planetConnection::Union{FilmPlanetsConnection,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was created."
    created::Union{String,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was edited."
    edited::Union{String,Missing,Nothing}
    "The ID of an object"
    id::String
end
function Film(;
    title = nothing,
    episodeID = nothing,
    openingCrawl = nothing,
    director = nothing,
    producers = nothing,
    releaseDate = nothing,
    speciesConnection = nothing,
    starshipConnection = nothing,
    vehicleConnection = nothing,
    characterConnection = nothing,
    planetConnection = nothing,
    created = nothing,
    edited = nothing,
    id,
)
    Film(
        title,
        episodeID,
        openingCrawl,
        director,
        producers,
        releaseDate,
        speciesConnection,
        starshipConnection,
        vehicleConnection,
        characterConnection,
        planetConnection,
        created,
        edited,
        id,
    )
end
StructTypes.StructType(::Type{Film}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{Film}) = true

"""
An edge in a connection.
"""
mutable struct VehicleFilmsEdge
    "The item at the end of the edge"
    node::Union{Film,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function VehicleFilmsEdge(; node = nothing, cursor)
    VehicleFilmsEdge(node, cursor)
end
StructTypes.StructType(::Type{VehicleFilmsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{VehicleFilmsEdge}) = true

"""
A connection to a list of items.
"""
mutable struct VehicleFilmsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{VehicleFilmsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    films::Union{Vector{Union{Film,Missing,Nothing}},Missing,Nothing}
end
function VehicleFilmsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    films = nothing,
)
    VehicleFilmsConnection(pageInfo, edges, totalCount, films)
end
StructTypes.StructType(::Type{VehicleFilmsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{VehicleFilmsConnection}) = true

"""
An edge in a connection.
"""
mutable struct VehiclePilotsEdge
    node::Any
    "A cursor for use in pagination"
    cursor::String
end
function VehiclePilotsEdge(; node = nothing, cursor)
    VehiclePilotsEdge(node, cursor)
end
StructTypes.StructType(::Type{VehiclePilotsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{VehiclePilotsEdge}) = true
function Base.getproperty(t::VehiclePilotsEdge, sym::Symbol)
    if s === Symbol("node")
        getfield(t, Symbol("node"))::Union{Person,Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A connection to a list of items.
"""
mutable struct VehiclePilotsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{VehiclePilotsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    pilots::Any
end
function VehiclePilotsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    pilots = nothing,
)
    VehiclePilotsConnection(pageInfo, edges, totalCount, pilots)
end
StructTypes.StructType(::Type{VehiclePilotsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{VehiclePilotsConnection}) = true
function Base.getproperty(t::VehiclePilotsConnection, sym::Symbol)
    if s === Symbol("pilots")
        getfield(
            t,
            Symbol("pilots"),
        )::Union{Vector{Union{Person,Missing,Nothing}},Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
A single transport craft that does not have hyperdrive capability
"""
mutable struct Vehicle
    "\n  The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder\n  bike\".\n  "
    name::Union{String,Missing,Nothing}
    "\n  The model or official name of this vehicle. Such as \"All-Terrain Attack\n  Transport\".\n  "
    model::Union{String,Missing,Nothing}
    "The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\"."
    vehicleClass::Union{String,Missing,Nothing}
    "The manufacturers of this vehicle."
    manufacturers::Union{Vector{Union{String,Missing,Nothing}},Missing,Nothing}
    "The cost of this vehicle new, in Galactic Credits."
    costInCredits::Union{Float64,Missing,Nothing}
    "The length of this vehicle in meters."
    length::Union{Float64,Missing,Nothing}
    "The number of personnel needed to run or pilot this vehicle."
    crew::Union{String,Missing,Nothing}
    "The number of non-essential people this vehicle can transport."
    passengers::Union{String,Missing,Nothing}
    "The maximum speed of this vehicle in atmosphere."
    maxAtmospheringSpeed::Union{Int32,Missing,Nothing}
    "The maximum number of kilograms that this vehicle can transport."
    cargoCapacity::Union{Float64,Missing,Nothing}
    "\n  The maximum length of time that this vehicle can provide consumables for its\n  entire crew without having to resupply.\n  "
    consumables::Union{String,Missing,Nothing}
    pilotConnection::Union{VehiclePilotsConnection,Missing,Nothing}
    filmConnection::Union{VehicleFilmsConnection,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was created."
    created::Union{String,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was edited."
    edited::Union{String,Missing,Nothing}
    "The ID of an object"
    id::String
end
function Vehicle(;
    name = nothing,
    model = nothing,
    vehicleClass = nothing,
    manufacturers = nothing,
    costInCredits = nothing,
    length = nothing,
    crew = nothing,
    passengers = nothing,
    maxAtmospheringSpeed = nothing,
    cargoCapacity = nothing,
    consumables = nothing,
    pilotConnection = nothing,
    filmConnection = nothing,
    created = nothing,
    edited = nothing,
    id,
)
    Vehicle(
        name,
        model,
        vehicleClass,
        manufacturers,
        costInCredits,
        length,
        crew,
        passengers,
        maxAtmospheringSpeed,
        cargoCapacity,
        consumables,
        pilotConnection,
        filmConnection,
        created,
        edited,
        id,
    )
end
StructTypes.StructType(::Type{Vehicle}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{Vehicle}) = true

"""
An edge in a connection.
"""
mutable struct PersonVehiclesEdge
    "The item at the end of the edge"
    node::Union{Vehicle,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function PersonVehiclesEdge(; node = nothing, cursor)
    PersonVehiclesEdge(node, cursor)
end
StructTypes.StructType(::Type{PersonVehiclesEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PersonVehiclesEdge}) = true

"""
A connection to a list of items.
"""
mutable struct PersonVehiclesConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{PersonVehiclesEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    vehicles::Union{Vector{Union{Vehicle,Missing,Nothing}},Missing,Nothing}
end
function PersonVehiclesConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    vehicles = nothing,
)
    PersonVehiclesConnection(pageInfo, edges, totalCount, vehicles)
end
StructTypes.StructType(::Type{PersonVehiclesConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PersonVehiclesConnection}) = true

"""
An edge in a connection.
"""
mutable struct PersonFilmsEdge
    "The item at the end of the edge"
    node::Union{Film,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function PersonFilmsEdge(; node = nothing, cursor)
    PersonFilmsEdge(node, cursor)
end
StructTypes.StructType(::Type{PersonFilmsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PersonFilmsEdge}) = true

"""
A connection to a list of items.
"""
mutable struct PersonFilmsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{PersonFilmsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    films::Union{Vector{Union{Film,Missing,Nothing}},Missing,Nothing}
end
function PersonFilmsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    films = nothing,
)
    PersonFilmsConnection(pageInfo, edges, totalCount, films)
end
StructTypes.StructType(::Type{PersonFilmsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PersonFilmsConnection}) = true

"""
An edge in a connection.
"""
mutable struct PersonStarshipsEdge
    "The item at the end of the edge"
    node::Union{Starship,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function PersonStarshipsEdge(; node = nothing, cursor)
    PersonStarshipsEdge(node, cursor)
end
StructTypes.StructType(::Type{PersonStarshipsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PersonStarshipsEdge}) = true

"""
A connection to a list of items.
"""
mutable struct PersonStarshipsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{PersonStarshipsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    starships::Union{Vector{Union{Starship,Missing,Nothing}},Missing,Nothing}
end
function PersonStarshipsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    starships = nothing,
)
    PersonStarshipsConnection(pageInfo, edges, totalCount, starships)
end
StructTypes.StructType(::Type{PersonStarshipsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PersonStarshipsConnection}) = true

"""
An individual person or character within the Star Wars universe.
"""
mutable struct Person
    "The name of this person."
    name::Union{String,Missing,Nothing}
    "\n  The birth year of the person, using the in-universe standard of BBY or ABY -\n  Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is\n  a battle that occurs at the end of Star Wars episode IV: A New Hope.\n  "
    birthYear::Union{String,Missing,Nothing}
    "\n  The eye color of this person. Will be \"unknown\" if not known or \"n/a\" if the\n  person does not have an eye.\n  "
    eyeColor::Union{String,Missing,Nothing}
    "\n  The gender of this person. Either \"Male\", \"Female\" or \"unknown\",\n  \"n/a\" if the person does not have a gender.\n  "
    gender::Union{String,Missing,Nothing}
    "\n  The hair color of this person. Will be \"unknown\" if not known or \"n/a\" if the\n  person does not have hair.\n  "
    hairColor::Union{String,Missing,Nothing}
    "The height of the person in centimeters."
    height::Union{Int32,Missing,Nothing}
    "The mass of the person in kilograms."
    mass::Union{Float64,Missing,Nothing}
    "The skin color of this person."
    skinColor::Union{String,Missing,Nothing}
    homeworld::Any
    filmConnection::Union{PersonFilmsConnection,Missing,Nothing}
    "The species that this person belongs to, or null if unknown."
    species::Union{Species,Missing,Nothing}
    starshipConnection::Union{PersonStarshipsConnection,Missing,Nothing}
    vehicleConnection::Union{PersonVehiclesConnection,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was created."
    created::Union{String,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was edited."
    edited::Union{String,Missing,Nothing}
    "The ID of an object"
    id::String
end
function Person(;
    name = nothing,
    birthYear = nothing,
    eyeColor = nothing,
    gender = nothing,
    hairColor = nothing,
    height = nothing,
    mass = nothing,
    skinColor = nothing,
    homeworld = nothing,
    filmConnection = nothing,
    species = nothing,
    starshipConnection = nothing,
    vehicleConnection = nothing,
    created = nothing,
    edited = nothing,
    id,
)
    Person(
        name,
        birthYear,
        eyeColor,
        gender,
        hairColor,
        height,
        mass,
        skinColor,
        homeworld,
        filmConnection,
        species,
        starshipConnection,
        vehicleConnection,
        created,
        edited,
        id,
    )
end
StructTypes.StructType(::Type{Person}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{Person}) = true
function Base.getproperty(t::Person, sym::Symbol)
    if s === Symbol("homeworld")
        getfield(t, Symbol("homeworld"))::Union{Planet,Missing,Nothing}
    else
        getfield(t, s)
    end
end

"""
An edge in a connection.
"""
mutable struct PlanetResidentsEdge
    "The item at the end of the edge"
    node::Union{Person,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function PlanetResidentsEdge(; node = nothing, cursor)
    PlanetResidentsEdge(node, cursor)
end
StructTypes.StructType(::Type{PlanetResidentsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PlanetResidentsEdge}) = true

"""
A connection to a list of items.
"""
mutable struct PlanetResidentsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{PlanetResidentsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    residents::Union{Vector{Union{Person,Missing,Nothing}},Missing,Nothing}
end
function PlanetResidentsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    residents = nothing,
)
    PlanetResidentsConnection(pageInfo, edges, totalCount, residents)
end
StructTypes.StructType(::Type{PlanetResidentsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PlanetResidentsConnection}) = true

"""
An edge in a connection.
"""
mutable struct PlanetFilmsEdge
    "The item at the end of the edge"
    node::Union{Film,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function PlanetFilmsEdge(; node = nothing, cursor)
    PlanetFilmsEdge(node, cursor)
end
StructTypes.StructType(::Type{PlanetFilmsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PlanetFilmsEdge}) = true

"""
A connection to a list of items.
"""
mutable struct PlanetFilmsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{PlanetFilmsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    films::Union{Vector{Union{Film,Missing,Nothing}},Missing,Nothing}
end
function PlanetFilmsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    films = nothing,
)
    PlanetFilmsConnection(pageInfo, edges, totalCount, films)
end
StructTypes.StructType(::Type{PlanetFilmsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PlanetFilmsConnection}) = true

"""
A large mass, planet or planetoid in the Star Wars Universe, at the time of
0 ABY.
"""
mutable struct Planet
    "The name of this planet."
    name::Union{String,Missing,Nothing}
    "The diameter of this planet in kilometers."
    diameter::Union{Int32,Missing,Nothing}
    "\n  The number of standard hours it takes for this planet to complete a single\n  rotation on its axis.\n  "
    rotationPeriod::Union{Int32,Missing,Nothing}
    "\n  The number of standard days it takes for this planet to complete a single orbit\n  of its local star.\n  "
    orbitalPeriod::Union{Int32,Missing,Nothing}
    "\n  A number denoting the gravity of this planet, where \"1\" is normal or 1 standard\n  G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.\n  "
    gravity::Union{String,Missing,Nothing}
    "The average population of sentient beings inhabiting this planet."
    population::Union{Float64,Missing,Nothing}
    "The climates of this planet."
    climates::Union{Vector{Union{String,Missing,Nothing}},Missing,Nothing}
    "The terrains of this planet."
    terrains::Union{Vector{Union{String,Missing,Nothing}},Missing,Nothing}
    "\n  The percentage of the planet surface that is naturally occuring water or bodies\n  of water.\n  "
    surfaceWater::Union{Float64,Missing,Nothing}
    residentConnection::Union{PlanetResidentsConnection,Missing,Nothing}
    filmConnection::Union{PlanetFilmsConnection,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was created."
    created::Union{String,Missing,Nothing}
    "The ISO 8601 date format of the time that this resource was edited."
    edited::Union{String,Missing,Nothing}
    "The ID of an object"
    id::String
end
function Planet(;
    name = nothing,
    diameter = nothing,
    rotationPeriod = nothing,
    orbitalPeriod = nothing,
    gravity = nothing,
    population = nothing,
    climates = nothing,
    terrains = nothing,
    surfaceWater = nothing,
    residentConnection = nothing,
    filmConnection = nothing,
    created = nothing,
    edited = nothing,
    id,
)
    Planet(
        name,
        diameter,
        rotationPeriod,
        orbitalPeriod,
        gravity,
        population,
        climates,
        terrains,
        surfaceWater,
        residentConnection,
        filmConnection,
        created,
        edited,
        id,
    )
end
StructTypes.StructType(::Type{Planet}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{Planet}) = true

"""
An edge in a connection.
"""
mutable struct PlanetsEdge
    "The item at the end of the edge"
    node::Union{Planet,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function PlanetsEdge(; node = nothing, cursor)
    PlanetsEdge(node, cursor)
end
StructTypes.StructType(::Type{PlanetsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PlanetsEdge}) = true

"""
An edge in a connection.
"""
mutable struct PeopleEdge
    "The item at the end of the edge"
    node::Union{Person,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function PeopleEdge(; node = nothing, cursor)
    PeopleEdge(node, cursor)
end
StructTypes.StructType(::Type{PeopleEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PeopleEdge}) = true

"""
An edge in a connection.
"""
mutable struct VehiclesEdge
    "The item at the end of the edge"
    node::Union{Vehicle,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function VehiclesEdge(; node = nothing, cursor)
    VehiclesEdge(node, cursor)
end
StructTypes.StructType(::Type{VehiclesEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{VehiclesEdge}) = true

"""
A connection to a list of items.
"""
mutable struct VehiclesConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{VehiclesEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    vehicles::Union{Vector{Union{Vehicle,Missing,Nothing}},Missing,Nothing}
end
function VehiclesConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    vehicles = nothing,
)
    VehiclesConnection(pageInfo, edges, totalCount, vehicles)
end
StructTypes.StructType(::Type{VehiclesConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{VehiclesConnection}) = true

"""
An edge in a connection.
"""
mutable struct FilmsEdge
    "The item at the end of the edge"
    node::Union{Film,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function FilmsEdge(; node = nothing, cursor)
    FilmsEdge(node, cursor)
end
StructTypes.StructType(::Type{FilmsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmsEdge}) = true

"""
An edge in a connection.
"""
mutable struct SpeciesEdge
    "The item at the end of the edge"
    node::Union{Species,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function SpeciesEdge(; node = nothing, cursor)
    SpeciesEdge(node, cursor)
end
StructTypes.StructType(::Type{SpeciesEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{SpeciesEdge}) = true

"""
A connection to a list of items.
"""
mutable struct SpeciesConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{SpeciesEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    species::Union{Vector{Union{Species,Missing,Nothing}},Missing,Nothing}
end
function SpeciesConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    species = nothing,
)
    SpeciesConnection(pageInfo, edges, totalCount, species)
end
StructTypes.StructType(::Type{SpeciesConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{SpeciesConnection}) = true

"""
A connection to a list of items.
"""
mutable struct PeopleConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{PeopleEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    people::Union{Vector{Union{Person,Missing,Nothing}},Missing,Nothing}
end
function PeopleConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    people = nothing,
)
    PeopleConnection(pageInfo, edges, totalCount, people)
end
StructTypes.StructType(::Type{PeopleConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PeopleConnection}) = true

"""
A connection to a list of items.
"""
mutable struct FilmsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{FilmsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    films::Union{Vector{Union{Film,Missing,Nothing}},Missing,Nothing}
end
function FilmsConnection(; pageInfo, edges = nothing, totalCount = nothing, films = nothing)
    FilmsConnection(pageInfo, edges, totalCount, films)
end
StructTypes.StructType(::Type{FilmsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{FilmsConnection}) = true

"""
A connection to a list of items.
"""
mutable struct PlanetsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{PlanetsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    planets::Union{Vector{Union{Planet,Missing,Nothing}},Missing,Nothing}
end
function PlanetsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    planets = nothing,
)
    PlanetsConnection(pageInfo, edges, totalCount, planets)
end
StructTypes.StructType(::Type{PlanetsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{PlanetsConnection}) = true

"""
An edge in a connection.
"""
mutable struct StarshipsEdge
    "The item at the end of the edge"
    node::Union{Starship,Missing,Nothing}
    "A cursor for use in pagination"
    cursor::String
end
function StarshipsEdge(; node = nothing, cursor)
    StarshipsEdge(node, cursor)
end
StructTypes.StructType(::Type{StarshipsEdge}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{StarshipsEdge}) = true

"""
A connection to a list of items.
"""
mutable struct StarshipsConnection
    "Information to aid in pagination."
    pageInfo::PageInfo
    "A list of edges."
    edges::Union{Vector{Union{StarshipsEdge,Missing,Nothing}},Missing,Nothing}
    "\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  "
    totalCount::Union{Int32,Missing,Nothing}
    "\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  "
    starships::Union{Vector{Union{Starship,Missing,Nothing}},Missing,Nothing}
end
function StarshipsConnection(;
    pageInfo,
    edges = nothing,
    totalCount = nothing,
    starships = nothing,
)
    StarshipsConnection(pageInfo, edges, totalCount, starships)
end
StructTypes.StructType(::Type{StarshipsConnection}) = StructTypes.Mutable()
StructTypes.omitempties(::Type{StarshipsConnection}) = true


text:
# perhaps move these to EBayesDatasets.jl

const chetty_hendren_file = joinpath(dirname(@__FILE__),
                          "..",
                          "datasets",
                          "chetty_hendren2005.csv")

const prostate_data_file = joinpath(dirname(@__FILE__),
                          "..",
                          "datasets",
                          "prostz.RData")

ext: jl


text:
"""
    size(x::SummarizedExperiment)

Return a 2-tuple containing the number of rows and columns in `x`.

# Examples
```jldoctest
julia> using SummarizedExperiments

julia> x = exampleobject(20, 10);

julia> size(x)
(20, 10)
```
"""
function Base.size(x::SummarizedExperiment)
    return (size(x.rowdata)[1], size(x.coldata)[1])
end

function check_dataframe_in_getter(value::DataFrame, expected::Int, message::String)
    if expected != size(value)[1]
        @warn "'" * message * "(x)' has a different number of rows than 'x'"
        return
    end

    if !check_dataframe_has_name(value)
        @warn "first column of '" * message * "(x)' should exist and be called 'name'"
        return
    end

    if !check_dataframe_firstcol(value)
        @warn "first column of '" * message * "(x)' should be a vector of strings or nothings"
        return
    end
end

"""
    rowdata(x; check = true)

Return the row annotations as a `DataFrame` with number of rows equal to the number of rows in `x`.
The first column is called `"name"` and contains the row names of `x`;
this can either be an `AbstractVector{AbstractString}` or a `Vector{Nothing}` (if no row names are available).

If `check = true`, this function will verify that the above expectations on the returned `DataFrame` are satisfied.
Any failures will cause warnings to be emitted.

# Examples
```jldoctest
julia> using SummarizedExperiments

julia> x = exampleobject(20, 10);

julia> names(rowdata(x))
2-element Vector{String}:
 "name"
 "Type"

julia> size(rowdata(x))
(20, 2)
```
"""
function rowdata(x::SummarizedExperiment; check = true)
    output = x.rowdata
    if check
        check_dataframe_in_getter(output, size(x)[1], "rowdata")
    end
    return output
end

"""
    coldata(x, check = true)

Return the column annotations as a `DataFrame` with number of rows equal to the number of columns in `x`.
The first column is called `"name"` and contains the column names of `x`;
this can either be a `Vector{String}` or a `Vector{Nothing}` (if no column names are available).

If `check = true`, this function will verify that the expectations on the returned `DataFrame` are satisfied.
Any failures will cause warnings to be emitted.

# Examples
```jldoctest
julia> using SummarizedExperiments

julia> x = exampleobject(20, 10);

julia> names(coldata(x))
3-element Vector{String}:
 "name"
 "Treatment"
 "Response"

julia> size(coldata(x))
(10, 3)
```
"""
function coldata(x::SummarizedExperiment; check = true)
    output = x.coldata
    if check
        check_dataframe_in_getter(output, size(x)[2], "coldata")
    end
    return output
end

"""
    assay(x[, i]; check = true)

Return the requested assay in `x`.
`i` may be an integer specifying an index or a string containing the name.
If `i` is not supplied, the first assay is returned.

The returned assay should have the same extents as `x` for the first two dimensions.
If `check = true`, this function will verify that this expectation is satisfied.
Any failures will cause warnings to be emitted.

# Examples
```jldoclist
julia> using SummarizedExperiments

julia> x = exampleobject(20, 10);

# All of these give the same value.
julia> assay(x);

julia> assay(x, 1);

julia> assay(x, "foo");
```
"""
function assay(x::SummarizedExperiment; check = true)
    return assay(x, 1; check = check)
end

function assay(x::SummarizedExperiment, i::Int64; check = true)
    counter = 0

    for val in values(x.assays)
        counter += 1
        if counter == i
            if check
                if !check_assay_dimensions(size(val), size(x))
                    @warn "dimensions of assay '" * string(i) * "' do not match those of 'x'"
                end
            end
            return val
        end
    end

    throw(BoundsError("'i = " * string(i) * "' is out of range of 'assays(x)'"))
end

function assay(x::SummarizedExperiment, i::String; check = true)
    if !haskey(x.assays, i)
        throw(KeyError("'" * i * "' is not present in 'assays(x)'"))
    end

    val = x.assays[i]
    if check
        if !check_assay_dimensions(size(val), size(x))
            @warn "dimensions of assay '" * i * "' do not match those of 'x'"
        end
    end

    return val
end

"""
    assays(x; check = true)

Return all assays from `x` as an `OrderedDict` where the keys are the assay names.
Each returned assay should have the same extents as `x` for the first two dimensions.
If `check = true`, this function will verify that this expectation is satisfied.
Any failures will cause warnings to be emitted.

# Examples
```jldoctest
julia> using SummarizedExperiments

julia> x = exampleobject(20, 10);

julia> collect(keys(assays(x)))
3-element Vector{String}:
 "foo"
 "bar"
 "whee"
```
"""
function assays(x::SummarizedExperiment; check = true)
    if check
        for (k, v) in x.assays
            if !check_assay_dimensions(size(v), size(x))
                @warn "dimensions of assay '" * k * "' do not match those of 'x'"
            end
        end
    end
    return x.assays
end

"""
    metadata(x)

Return metadata from `x` as a `Dict` where the keys are the metadata field names.

# Examples
```jldoctest
julia> using SummarizedExperiments

julia> x = exampleobject(20, 10);

julia> metadata(x)
Dict{String, Any} with 1 entry:
  "version" => "1.1.0"
```
"""
function metadata(x::SummarizedExperiment)
    return x.metadata;
end


text:
module Torch

using PythonCall: Py, pynew, pycopy!, @pyeval, @pyexec

using ChainRulesCore
using DLPack
using Functors: @functor
using Adapt

using ..PythonCallChainRules: PyAdaptor

const inspect = pynew()
const torch = pynew()
const functorch = pynew()
const dlpack = pynew()

const ispysetup = Ref{Bool}(false)

struct TorchModuleWrapper
    torch_stateless_module::Py
    dtype::Py
    params::Tuple
    buffers::Py
end

@functor TorchModuleWrapper (params,)

Base.show(io::IO, f::TorchModuleWrapper) = print(io, f.torch_stateless_module, " ", f.dtype, " ", " params size=", size.(f.params))

Base.length(f::TorchModuleWrapper) = length(f.params)
Base.iterate(f::TorchModuleWrapper) = iterate(f.params)
Base.iterate(f::TorchModuleWrapper, state) = iterate(f.params, state)

function TorchModuleWrapper(torch_module)
    pyconvert(Bool, pyisinstance(torch_module, torch.nn.Module)) || error("Not a torch.nn.Module")
    funmod, params, buffers = functorch.make_functional_with_buffers(torch_module)
    dtype = params[0].dtype
    jlparams = pyconvert(Tuple, map(x->DLPack.wrap(x, dlpack.to_dlpack), params))
    return TorchModuleWrapper(funmod, dtype, jlparams, buffers)
end

function (wrap::TorchModuleWrapper)(args...; kwargs...)
    # TODO: handle multiple outputs
    params = wrap.params
    tensor_out = wrap.torch_stateless_module((map(x -> DLPack.share(x, Py, dlpack.from_dlpack).requires_grad_(true), params)),
        wrap.buffers, map(x -> DLPack.share(x, Py, dlpack.from_dlpack), args)...; kwargs...)
    res = DLPack.wrap(tensor_out, dlpack.to_dlpack)
    return res
end

function ChainRulesCore.rrule(wrap::TorchModuleWrapper, args...; kwargs...)
    T = typeof(first(args))
    params = wrap.params
    torch_primal, torch_vjpfun = functorch.vjp(@pyeval("buffer_implicit")(wrap.torch_stateless_module, wrap.buffers), Tuple(map(x -> DLPack.share(x, Py, dlpack.from_dlpack).requires_grad_(true), params)),
        map(x -> DLPack.share(x, Py, dlpack.from_dlpack).requires_grad_(true), args)...; kwargs...)
    project = ProjectTo(args)
    function TorchModuleWrapper_pullback(Δ)
        torch_tangent_vals = torch_vjpfun(DLPack.share(Adapt.adapt(PyAdaptor{T}, Δ), Py, dlpack.from_dlpack))
        jlparams_tangents = map(x -> (DLPack.wrap(x, dlpack.to_dlpack)), torch_tangent_vals[1])
        args_tangents = project(map(x -> (DLPack.wrap(x, dlpack.to_dlpack)), torch_tangent_vals[2:end]))
        return (Tangent{TorchModuleWrapper}(; torch_stateless_module = NoTangent(), dtype = NoTangent(), params = jlparams_tangents, buffers = NoTangent()), args_tangents...)
    end
    res = DLPack.wrap(torch_primal, dlpack.to_dlpack)
    return res, TorchModuleWrapper_pullback
end

function __init__()
    try
        pycopy!(torch, pyimport("torch"))
        pycopy!(dlpack, pyimport("torch.utils.dlpack"))
        pycopy!(functorch, pyimport("functorch"))
        pycopy!(inspect, pyimport("inspect"))
        ispysetup[] = true
        @pyexec """
        global buffer_implicit
        def buffer_implicit(fn, buffers):
            def newfn(params, inputs):
                return fn(params, buffers, inputs)

            return newfn
        """
    catch err
        @warn """PythonCallChainRules.jl has failed to import torch and functorch from Python.
                 Please make sure these are installed.
        """
        @debug err
        ispysetup[] = false
        #rethrow(err)
    end
end

end


text:
# import GitCommand: git
import GitHub

function git(f)
  return f("git")
end

"""
    MassInstallAction.install(workflow, user_or_org::AbstractString, [pkgs]; token, cc::AbstractVector{<:AbstractString})

Submit a pull request to install `workflow` for all packages owned by `user_or_org`.
`token` is your personal access token for authentication, or `nothing` if you do not have privileges and need to fork the package.
`cc` is a list of GitHub usernames that should receive notification about this pull request (beyond the regular watchers).

If `pkgs` is supplied, pull requests will only be made to the listed packages.
"""
function install(workflow::Workflow,
                 org::AbstractString;
                 token::Union{AbstractString, Nothing},
                 cc::AbstractVector{<:AbstractString})
    if token === nothing
        auth = nothing
    else
        auth = GitHub.authenticate(token)
    end
    if auth === nothing
        orgrepos, page_data = GitHub.repos(org)
    else
        orgrepos, page_data = GitHub.repos(org; auth = auth)
    end
    pkgs = Vector{String}(undef, 0)
    for r in orgrepos
        name = r.name
        endswith(name, ".jl") && push!(pkgs, name[1:(end-3)])
    end
    unique!(pkgs)
    sort!(pkgs)
    install(workflow,
            org,
            pkgs;
            cc = cc,
            token = token)
    return nothing
end

function install(workflow::Workflow,
                 org::AbstractString,
                 pkgs::AbstractVector{<:AbstractString};
                 token,
                 cc::AbstractVector{<:AbstractString})
    if token === nothing
        auth = nothing
    else
        auth = GitHub.authenticate(token)
    end
    cc_string = string("cc: ", join(string.("@",
                                            strip.(strip.(strip.(cc),
                                                          '@'))), " "))
    pr_body = "This pull request sets up the $(workflow.name) workflow on this repository. $(cc_string)"
    for pkg in pkgs
        if auth === nothing
            pkgrepo = GitHub.repo("$(org)/$(pkg).jl")
        else
            pkgrepo = GitHub.repo("$(org)/$(pkg).jl";
                                  auth = auth)
        end
        install(workflow, pkgrepo; auth=auth, pr_body=pr_body)

        # Avoid GitHub secondary rate limits
        # https://docs.github.com/en/rest/overview/resources-in-the-rest-api#secondary-rate-limits
        sleep(1)
    end
end

"""
    MassInstallAction.install(workflow, repo::GitHub.Repo; auth, pr_branch_name=..., pr_title=..., pr_body=..., commit_message=...)

Submit a pull request to install `workflow` for repository `repo`. This version of `install` is
designed to work in concert with [GitHub.jl](https://github.com/JuliaWeb/GitHub.jl), so that you can run queries, filter results,
and then submit changes. See the documentation of that package for more detail about `repo` and `auth`.

The remaining keywords are all strings, and have generic defaults but allow customization.
"""
function install(workflow::Workflow,
                 repo::GitHub.Repo;
                 auth::Union{Nothing,GitHub.Authorization},
                 pr_branch_name::AbstractString = "massinstallaction/set-up-$(workflow.name)",
                 pr_title::AbstractString = "MassInstallAction: Install the $(workflow.name) workflow on this repository",
                 pr_body::AbstractString = "This pull request sets up the $(workflow.name) workflow on this repository.",
                 commit_message::AbstractString = "Automated commit made by MassInstallAction.jl")
    pkg_url_with_auth = repo.html_url.uri
    with_temp_dir() do tmp_dir
        git() do git
            cd(tmp_dir)
            run(`$(git) clone $(pkg_url_with_auth) REPO`)
            cd("REPO")
            run(`$(git) checkout -B $(pr_branch_name)`)
            workflows_directory = joinpath(pwd(), ".github", "workflows")
            mkpath(workflows_directory)
            cd(workflows_directory)
            for filename in workflow.files_to_delete
                rm(filename; force = true, recursive = true)
            end
            for filename in keys(workflow.files_to_create)
                file_content = workflow.files_to_create[filename]
                open(filename, "w") do io
                    print(io, file_content)
                end
            end
            try
                run(`$(git) add -A`)
                run(`$(git) commit -m $(commit_message)`)
                try
                    run(`$(git) push --force origin $(pr_branch_name)`)
                catch
                    # try again?
                    run(`$(git) push --force origin $(pr_branch_name)`)
                end
                params = Dict{String, String}()
                params["title"] = pr_title
                params["head"] = pr_branch_name
                params["base"] = repo.default_branch
                params["body"] = pr_body
                if auth === nothing
                    GitHub.create_pull_request(repo;
                                               params = params)
                else
                    GitHub.create_pull_request(repo;
                                               params = params,
                                               auth = auth)
                end
                @info "Pull request submitted for $(repo.name)"
            catch error
                @warn "Assembling the pull request failed, skipping $(repo.name)"
                show(error)
            end
        end
    end
    return nothing
end


text:
# Old linalg.jl functions, for comparison with the new ones

#### SVD, i.e. UDV decomposition
function decompose_udv!(A::Matrix{T}) where T<:Number
    Base.LinAlg.LAPACK.gesvd!('A','A',A)
end

function decompose_udv(A::Matrix{T}) where T<:Number
    X = copy(A)
    decompose_udv!(X)
    return X
end

#### QR, i.e. UDT decomposition
function decompose_udt(A::AbstractMatrix{C}) where C<:Number
    F = qr(A, Val(true))
    p = F.p
    @views p[p] = collect(1:length(p))
    # D = abs.(real(diag(triu(R))))
    D = abs.(real(diag(F.R)))
    T = (Diagonal(1. ./ D) * F.R)[:, p]
    return Matrix(F.Q), D, T
end

#### Other
function expm_diag!(A::Matrix{T}) where T<:Number
    F = eigfact!(A)
    return F[:vectors] * spdiagm(0 => exp(F[:values])) * ctranspose(F[:vectors])
end

function lu_det(M)
    L, U, p = lu(M)
    return prod(diag(L)) * prod(diag(U))
end


text:
using sem, Feather, ModelingToolkit, Statistics, LinearAlgebra,
    Optim, SparseArrays, Test, Zygote, LineSearches, ForwardDiff

## Observed Data
three_path_dat = Feather.read("test/comparisons/three_path_dat.feather")
three_path_par = Feather.read("test/comparisons/three_path_par.feather")
three_path_start = Feather.read("test/comparisons/three_path_start.feather")

semobserved = SemObsCommon(data = Matrix(three_path_dat))

diff_fin = SemFiniteDiff(LBFGS(
        ;alphaguess = LineSearches.InitialStatic(;scaled = true),
        linesearch = LineSearches.Static()), Optim.Options(;g_tol = 0.001))
diff_fin = SemFiniteDiff(BFGS(), Optim.Options())
diff_for = SemForwardDiff(LBFGS(), Optim.Options())
diff_rev = SemReverseDiff(LBFGS(), Optim.Options())

## Model definition
@ModelingToolkit.variables x[1:31]

S =[x[1]  0     0     0     0     0     0     0     0     0     0     0     0     0
    0     x[2]  0     0     0     0     0     0     0     0     0     0     0     0
    0     0     x[3]  0     0     0     0     0     0     0     0     0     0     0
    0     0     0     x[4]  0     0     0     x[15] 0     0     0     0     0     0
    0     0     0     0     x[5]  0     x[16] 0     x[17] 0     0     0     0     0
    0     0     0     0     0     x[6]  0     0     0     x[18] 0     0     0     0
    0     0     0     0     x[16] 0     x[7]  0     0     0     x[19] 0     0     0
    0     0     0     x[15] 0     0     0     x[8]  0     0     0     0     0     0
    0     0     0     0     x[17] 0     0     0     x[9]  0     x[20] 0     0     0
    0     0     0     0     0     x[18] 0     0     0     x[10] 0     0     0     0
    0     0     0     0     0     0     x[19] 0     x[20] 0     x[11] 0     0     0
    0     0     0     0     0     0     0     0     0     0     0     x[12] 0     0
    0     0     0     0     0     0     0     0     0     0     0     0     x[13] 0
    0     0     0     0     0     0     0     0     0     0     0     0     0     x[14]]

F =[1.0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 1 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 1 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 1 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 1 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 1 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 1 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 1 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 1 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 1 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 1 0 0 0]

A =[0  0  0  0  0  0  0  0  0  0  0     1     0     0
    0  0  0  0  0  0  0  0  0  0  0     x[21] 0     0
    0  0  0  0  0  0  0  0  0  0  0     x[22] 0     0
    0  0  0  0  0  0  0  0  0  0  0     0     1     0
    0  0  0  0  0  0  0  0  0  0  0     0     x[23] 0
    0  0  0  0  0  0  0  0  0  0  0     0     x[24] 0
    0  0  0  0  0  0  0  0  0  0  0     0     x[25] 0
    0  0  0  0  0  0  0  0  0  0  0     0     0     1
    0  0  0  0  0  0  0  0  0  0  0     0     0     x[26]
    0  0  0  0  0  0  0  0  0  0  0     0     0     x[27]
    0  0  0  0  0  0  0  0  0  0  0     0     0     x[28]
    0  0  0  0  0  0  0  0  0  0  0     0     0     0
    0  0  0  0  0  0  0  0  0  0  0     x[29] 0     0
    0  0  0  0  0  0  0  0  0  0  0     x[30] x[31] 0]

S = sparse(S)

#F
F = sparse(F)

#A
A = sparse(A)

start_val = vcat(
    vec(var(Matrix(three_path_dat), dims = 1))./2,
    fill(0.05, 3),
    fill(0.0, 6),
    fill(1.0, 8),
    fill(0, 3)
    )

loss = Loss([SemML(semobserved, [0.0], similar(start_val))])

imply = ImplySymbolic(A, S, F, x, start_val)

@benchmark ImplySymbolic(A, S, F, x, start_val)

imply_alloc = sem.ImplySymbolicAlloc(A, S, F, x, start_val)
#imply_forward = sem.ImplySymbolicForward(A, S, F, x, start_val)

model_fin = Sem(semobserved, imply, loss, diff_fin)
model_rev = Sem(semobserved, imply_alloc, loss, diff_rev)
#model_for = Sem(semobserved, imply_alloc, loss, diff_for)
#model_for2 = Sem(semobserved, imply_forward, loss, diff_for)
#model_ana = Sem(semobserved, imply, loss, diff_ana)

#Zygote.@nograd isposdef
#Zygote.@nograd Symmetric

solution_fin = sem_fit(model_fin)
#solution_for = sem_fit(model_for)
#solution_for2 = sem_fit(model_for2)
solution_rev = sem_fit(model_rev)
#solution_ana = sem_fit(model_ana)

par_order = [collect(21:34); collect(15:20); 2;3; 5;6;7; collect(9:14)]

all(
    abs.(solution_fin.minimizer .- three_path_par.est[par_order]
        ) .< 0.05*abs.(three_path_par.est[par_order]))

start_lav = three_path_start.start[par_order]

model_fin(start_val)
model_rev(start_val)

FiniteDiff.finite_difference_jacobian(model_rev, start_val) ==
    FiniteDiff.finite_difference_jacobian(model_fin, start_val)

truegrad = similar(start_val)

truegrad = FiniteDiff.finite_difference_jacobian(model_fin, start_val)

truegrad = [truegrad...]
const tape2 =
    ReverseDiff.GradientTape(model_rev, (start_val))
# compile `f_tape` into a more optimized representation
const compiled_tape2 = ReverseDiff.compile(tape2)

results = similar(start_val)
g_r(G, x) = ReverseDiff.gradient!(G, compiled_tape2, x)

truegrad .≈ results
##

g_f(x) = FiniteDiff.finite_difference_gradient(model_fin, x)

@benchmark model_fin(start_val)
@benchmark g_f(start_val)
@benchmark g_r(results, start_val)

solution = sem_fit(model_fin, g_f)
solution2 = sem_fit(model_fin)

solution.minimizer ≈ solution2.minimizer

solution3 = sem_fit(model_fin, g_r)

solution3.minimizer ≈ solution2.minimizer

@benchmark sem_fit(model_fin)
@benchmark sem_fit(model_fin, g_r)

const tape3 =
    ReverseDiff.HessianTape(model_rev, (start_val))
# compile `f_tape` into a more optimized representation
const compiled_tape3 = ReverseDiff.compile(tape3)

results = similar(start_val)
h_r(G, x) = ReverseDiff.hessian!(G, compiled_tape3, x)

@benchmark sem_fit(model_fin, g_r, h_r)

G = zeros(31,31)
@btime h_r(G, start_val)

using LinearAlgebra, Optim

obs = abs.(randn(20))

obs = obs*transpose(obs)

obs .= abs.(obs)

function myf(par, A)
    A[1] = par[1]
    A[2] = par[2]
    A[3] = par[3]
    A[4] = par[1]
    if !isposdef(A)
        return Inf
    else
        cholesky!(A)
        F = logdet(A) + tr(obs*inv(A))
    end
end

A = ones(2,2)

mysol = optimize(par -> myf(par, A), [2.4,2.05, 2.05],
    Optim.Options(show_trace=true, extended_trace = true))

A = [0 0 0 "c"
     1.0 0 0 .5
     0 0 0 0]

struct ImplySparse3{T1 <: AbstractSparseArray, T2 <: AbstractArray} <: Imply
    A::T1
    Aw::T2
end

function get_indices(A, func)
   permutedims(reinterpret(Int, reshape(findall(replace(func, A)), 1, :)))
end

function ImplySparse3(A)
    Aw = get_indices(A, x -> isa(x, String))
    ind = get_indices(A, x -> !(isa(x, Number) && iszero(x)))
    out = sparse(ind[:, 1], ind[:, 2], Vector{Float64}(undef, size(ind)[1]), size(A)...)
    for i in 1:size(ind)[1]
        probe = A[ind[i, 1], ind[i, 2]] # element of A
        if isa(probe, Number)
            out[ind[i, :]...] = probe
        end
    end
    ImplySparse3(out, Aw)
end

using StructuredOptimization

x = Variable(n)               # initialize optimization variable

λ = 1e-2*norm(A'*y, Inf)       # define λ

@minimize ls( A*x - y ) + λ*norm(x, 1)

##
using StructuredOptimization

n, m = 100, 10;                # define problem size

A, y = randn(m,n), randn(m);

x = StructuredOptimization.Variable(n)               # initialize optimization variable

λ = 1e-2*norm(A'*y, Inf)       # define λ

sol = @minimize ls( A*x - y ) #+ λ*norm(x, 1)

x = StructuredOptimization.Variable(31)

sol = @minimize model_for(x)


text:
include("learn_DashBootstrap.jl")

#app = dash(external_stylesheets=["https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"])
#app = dash(external_stylesheets=[dbc_themes.MATERIA])
app = dash(external_stylesheets=[dbc_themes.SPACELAB])
#app = dash()

#app = hello_world()
#app = alert_dismissing()
#app = badge_example(app=app)
#app = button_example(app=app)
#app = button_group_example(app=app)
#app = card_example(app=app)
#app = layout_row_with_columns_1(app=app)
app = layout_row_with_columns_2(app=app)
#app = layout_specify_order_and_offset(app=app)
#app = layout_specify_width_for_different_screen_sizes(app=app)
#app = nav_example(app=app)
#app = navbar_example(app=app)

run_server(
    app,
    "0.0.0.0",
    8050,
    debug=true, # enables hot reload and more
)


text:
# Benchmark the parsing of a mmCIF file given as an argument

using BioStructures

mmcif_filepath = ARGS[1]

# Run to JIT compile
read(mmcif_filepath, MMCIF)

elapsed = @elapsed struc = read(mmcif_filepath, MMCIF)

println(elapsed)

max_stars_repo_name: wojdyr/pdb-benchmarks

max_issues_repo_name: wojdyr/pdb-benchmarks

max_forks_repo_name: wojdyr/pdb-benchmarks


text:
export
    # AbstractTrackCoord,

    TrackCoord,
    TrackCoordIm

abstract AbstractTrackCoord
type TrackCoord <: AbstractTrackCoord

    trackid::Cint # id of the corresponding track
    s::Cdouble    # distance along the track
    t::Cdouble    # distance perpendicular to the track
    z::Cdouble    # height
    h::Cdouble    # heading [rad]
    p::Cdouble    # pitch [rad]
    r::Cdouble    # roll [rad]

    TrackCoord() = new() # create one without setting any values
    TrackCoord(trackid::Integer, s::Real, t::Real, z::Real=0.0, h::Real=0.0, p::Real=0.0, r::Real=0.0) =
        new(trackid, s, t, z, h, p, r)
end
immutable TrackCoordIm <: AbstractTrackCoord

    trackid::Cint # id of the corresponding track
    s::Cdouble    # distance along the track
    t::Cdouble    # distance perpendicular to the track
    z::Cdouble    # height
    h::Cdouble    # heading [rad]
    p::Cdouble    # pitch [rad]
    r::Cdouble    # roll [rad]

    TrackCoordIm() = new() # create one without setting any values
    TrackCoordIm(trackid::Integer, s::Real, t::Real, z::Real=0.0, h::Real=0.0, p::Real=0.0, r::Real=0.0) =
        new(trackid, s, t, z, h, p, r)
end

Base.convert(::Type{TrackCoordIm}, c::TrackCoord) = TrackCoordIm(c.trackid, c.s, c.t, c.z, c.h, c.p, c.r)
Base.convert(::Type{TrackCoord}, c::TrackCoordIm) = TrackCoord(c.trackid, c.s, c.t, c.z, c.h, c.p, c.r)

function ==(a::TrackCoord, b::TrackCoord)
    a.trackid == b.trackid &&
    a.s == b.s &&
    a.t == b.t &&
    a.z == b.z &&
    a.h == b.h &&
    a.p == b.p &&
    a.r == b.r
end

show(io::IO, coord::TrackCoord) = @printf(io, "(%d, %.16e, %.16e, %.16e, %.16e, %.16e, %.16e)", coord.trackid, coord.s, coord.t, coord.z, coord.h, coord.p, coord.r)
print(io::IO, coord::TrackCoord) = @printf(io, "(%d, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f)", coord.trackid, coord.s, coord.t, coord.z, coord.h, coord.p, coord.r)

copy(coord::TrackCoord) = TrackCoord(coord.trackid, coord.s, coord.t, coord.z, coord.h, coord.p, coord.r) # FINISH
deepcopy(coord::TrackCoord) = copy(coord)
function copy!(dest::TrackCoord, src::TrackCoord)
    dest.trackid = src.trackid
    dest.s = src.s
    dest.t = src.t
    dest.z = src.z
    dest.h = src.h
    dest.p = src.p
    dest.r = src.r
    dest
end

function init!(coord::TrackCoord)
    coord.trackid = 0
    coord.s = 0.0
    coord.t = 0.0
    coord.z = 0.0
    coord.h = 0.0
    coord.p = 0.0
    coord.r = 0.0
    coord
end
function plus!(a::TrackCoord, b::TrackCoord)
    (ccall( (:trackcoord_plusequal, LIB_ODRMGR), Void, (Ptr{Void},Ptr{Void}),
       pointer_from_objref(a), pointer_from_objref(b)))
    a
end

max_stars_repo_name: sisl/OpenDriveManagerLite

max_issues_repo_name: sisl/OpenDriveManagerLite

max_forks_repo_name: sisl/OpenDriveManagerLite


text:
function G_to_R( Ns::Array{Int,1}, fG )
    out = reshape( ifft( reshape(fG,Ns[1],Ns[2],Ns[3]) ), size(fG) )
end

function c_G_to_R(Ns::Array{Int,1}, fG)
    out = zeros(Complex128,Ns[1]*Ns[2]*Ns[3])
    ccall( (:fftw_inv_fft3d, "../libs/fft3d.so"), Void,
           (Ptr{Complex128}, Ptr{Complex128}, Int64, Int64, Int64),
            fG, out, Ns[3],Ns[2],Ns[1] )
    return out
end

function R_to_G( Ns::Array{Int,1}, fR )
    #
    out = reshape( fft( reshape(fR,Ns[1],Ns[2],Ns[3]) ),
          size(fR) )
    #
end

function c_R_to_G( Ns::Array{Int,1}, fR::Array{Complex128,1} )
    #
    out = zeros(Complex128,Ns[1]*Ns[2]*Ns[3])
    ccall( (:fftw_fw_fft3d, "../libs/fft3d.so"), Void,
           (Ptr{Complex128}, Ptr{Complex128}, Int64, Int64, Int64),
            fR, out, Ns[3],Ns[2],Ns[1] )
    return out
    #
end

#
# Input array is of type Float64. This input is converted
# to Complex128 before supplied to `fftw_fw_fft3d`
#
function c_R_to_G( Ns::Array{Int,1}, fR::Array{Float64,1} )
    out = zeros(Complex128,Ns[1]*Ns[2]*Ns[3])
    ccall( (:fftw_fw_fft3d, "../libs/fft3d.so"), Void,
           (Ptr{Complex128}, Ptr{Complex128}, Int64, Int64, Int64),
            convert(Array{Complex128,1},fR), out, Ns[3],Ns[2],Ns[1] )
    return out
end


text:
"""
# `module Data`

Provides methods to read files containing simulation data. Primarily this is
intended to load `.xyz` files and convert them to JuLIP-compatible data:
```
data = IPFitting.Data.load_data("mydata.xyz")
```
where `mydata.xyz` contains multiple configurations, will read in those
configurations, then convert them into a `JuLIP.Atoms` object, extract
energies, forces, etc store each configuration in a `Dat` and return them
as a `Vector{Dat}`. This can then be stored using `JLD` or `JLD2`.

If `d::Dat`, then one can call `energy(d), forces(d)`, etc to extract the
loaded information.
"""
module Data

using JuLIP, ProgressMeter, FileIO
using IPFitting: Dat, vec_obs, devec_obs, observation, hasobservation
using IPFitting.DataTypes
import JuLIP: Atoms, energy, forces, virial
import Base: length, Dict

import ASE     # use ASE since this will have already figured out how to
               # load `ase` without problems
ase_io = ASE.ase_io

export configtype, weight, load_data

Atoms(d) = d.at
length(d::Dat) = length(d.at)
configtype(d::Dat) = d.configtype
energy(d::Dat) = haskey(d.D, ENERGY) ? devec_obs(Val(:E), d.D[ENERGY]) : nothing
forces(d::Dat) = haskey(d.D, FORCES) ? devec_obs(Val(:F), d.D[FORCES]) : nothing
virial(d::Dat) = haskey(d.D, VIRIAL) ? devec_obs(Val(:V), d.D[VIRIAL]) : nothing

function read_energy(atpy)
   for key in keys(atpy.info)
      if lowercase(key) == "dft_energy"
         return atpy.info[key]
      end
   end
   try
      return atpy.get_potential_energy()
   catch
   end
   return nothing
end

function read_forces(atpy)
   for key in keys(atpy.arrays)
      if lowercase(key) == "dft_force"
         return atpy.arrays[key]' |> vecs
      end
   end
   try
      return atpy.get_array("force")' |> vecs
   catch
   end
   return nothing
end

function read_virial(atpy)
   for key in keys(atpy.info)
      if lowercase(key) == "dft_virial"
         return JMat(atpy.info[key]...)
      end
   end
   if haskey(atpy.info, "virial")
      return JMat(atpy.info["virial"]...)
   end
   return nothing
end

function read_configtype(atpy)
   if haskey(atpy.info, "config_type")
      return atpy.info["config_type"]
   elseif haskey(atpy.info, "configtype")
      return atpy.info["configtype"]
   end
   return nothing
end

read_Atoms(atpy) = Atoms( vecs(atpy.get_positions()'),
                          vecs(atpy.get_momenta()'),
                          atpy.get_masses(),
                          atpy.get_atomic_numbers(),
                          atpy.get_cell(),
                          tuple(atpy.get_pbc()...) )

"""
```
function read_xyz(fname; verbose=true, index = ":",
                         include = nothing, exclude = nothing)
```
Loads the atoms objects contained in an xyz file, attempts to read the
DFT data stored inside and returns a `Vector{Dat}`.
"""
function read_xyz(fname; verbose=true, index = ":",
                         include = nothing, exclude = nothing)
   if verbose
      println("Reading in $fname ...")
   end
   at_list = ase_io.read(fname, index=index)
   data = Vector{Dat}(undef, length(at_list))
   idx = 0
   if verbose
      println("Processing data ...")
      # tic()
   end
   dt = verbose ? 1.0 : 0.0
   @showprogress dt for atpy in at_list

      # get the config type and decide whether to keep or skip this config
      config_type = read_configtype(atpy)
      if config_type == nothing
         verbose && @warn("$(idx+1) has no config_type")
         config_type = "nothing"
      end
      if exclude != nothing
         if config_type in exclude
            continue
         end
      end
      if include != nothing
         if !(config_type in include)
            continue
         end
      end

      idx += 1
      at = read_Atoms(atpy)
      E = read_energy(atpy)
      F = read_forces(atpy)
      V = read_virial(atpy)
      EFV = ""
      (E != nothing) && (EFV *= "E")
      (F != nothing) && (EFV *= "F")
      (V != nothing) && (EFV *= "V")

      data[idx] = Dat( at,
                       config_type;
                       E = E, F = F, V = V )
   end
   # verbose && toc()
   return data[1:idx]
end

function load_data(fname; kwargs...)
   if fname[end-3:end] == ".xyz"
      return read_xyz(fname; kwargs...)
   elseif fname[end-3:end] == ".jld" || fname[end-4:end] == ".jld2"
      return load(fname)
   end
   error("unknown file format $(fname[end-3:end])")
end

end


text:
using TiledIteration, OffsetArrays
using Test

@testset "tiled iteration" begin
    sz = (3,5)
    for i1 = -3:2, i2 = -1:5
        for l1 = 2:13, l2 = 1:16
            inds = (i1:i1+l1-1, i2:i2+l2-1)
            A = fill!(OffsetArray{Int}(undef, inds), 0)
            k = 0
            for tileinds in TileIterator(inds, sz)
                tile = A[tileinds...]
                @test !isempty(tile)
                @test all(tile .== 0)
                A[tileinds...] .= (k+=1)
            end
            @test minimum(A) == 1
            @test eltype(collect(TileIterator(inds, sz))) == Tuple{UnitRange{Int}, UnitRange{Int}}
        end
    end
end

@testset "edge iteration" begin
    iter = EdgeIterator(CartesianIndices((-1:4,0:3)), CartesianIndices((1:3,1:2)))
    @test collect(iter) == [CartesianIndex((-1,0)),
                            CartesianIndex(( 0,0)),
                            CartesianIndex(( 1,0)),
                            CartesianIndex(( 2,0)),
                            CartesianIndex(( 3,0)),
                            CartesianIndex(( 4,0)),
                            CartesianIndex((-1,1)),
                            CartesianIndex(( 0,1)),
                            CartesianIndex(( 4,1)),
                            CartesianIndex((-1,2)),
                            CartesianIndex(( 0,2)),
                            CartesianIndex(( 4,2)),
                            CartesianIndex((-1,3)),
                            CartesianIndex(( 0,3)),
                            CartesianIndex(( 1,3)),
                            CartesianIndex(( 2,3)),
                            CartesianIndex(( 3,3)),
                            CartesianIndex(( 4,3))]
    iter = EdgeIterator((0:3,0:3), (1:3,1:2))
    @test collect(iter) == [CartesianIndex(( 0,0)),
                            CartesianIndex(( 1,0)),
                            CartesianIndex(( 2,0)),
                            CartesianIndex(( 3,0)),
                            CartesianIndex(( 0,1)),
                            CartesianIndex(( 0,2)),
                            CartesianIndex(( 0,3)),
                            CartesianIndex(( 1,3)),
                            CartesianIndex(( 2,3)),
                            CartesianIndex(( 3,3))]
    iter = EdgeIterator((1:4,0:3), (1:3,1:2))
    @test collect(iter) == [CartesianIndex(( 1,0)),
                            CartesianIndex(( 2,0)),
                            CartesianIndex(( 3,0)),
                            CartesianIndex(( 4,0)),
                            CartesianIndex(( 4,1)),
                            CartesianIndex(( 4,2)),
                            CartesianIndex(( 1,3)),
                            CartesianIndex(( 2,3)),
                            CartesianIndex(( 3,3)),
                            CartesianIndex(( 4,3))]
    iter = EdgeIterator((-1:4,1:3), (1:3,1:2))
    @test collect(iter) == [CartesianIndex((-1,1)),
                            CartesianIndex(( 0,1)),
                            CartesianIndex(( 4,1)),
                            CartesianIndex((-1,2)),
                            CartesianIndex(( 0,2)),
                            CartesianIndex(( 4,2)),
                            CartesianIndex((-1,3)),
                            CartesianIndex(( 0,3)),
                            CartesianIndex(( 1,3)),
                            CartesianIndex(( 2,3)),
                            CartesianIndex(( 3,3)),
                            CartesianIndex(( 4,3))]
    iter = EdgeIterator((-1:4,0:2), (1:3,1:2))
    @test collect(iter) == [CartesianIndex((-1,0)),
                            CartesianIndex(( 0,0)),
                            CartesianIndex(( 1,0)),
                            CartesianIndex(( 2,0)),
                            CartesianIndex(( 3,0)),
                            CartesianIndex(( 4,0)),
                            CartesianIndex((-1,1)),
                            CartesianIndex(( 0,1)),
                            CartesianIndex(( 4,1)),
                            CartesianIndex((-1,2)),
                            CartesianIndex(( 0,2)),
                            CartesianIndex(( 4,2))]
    iter = EdgeIterator((-1:4,1:2), (1:3,1:2))
    @test collect(iter) == [CartesianIndex((-1,1)),
                            CartesianIndex(( 0,1)),
                            CartesianIndex(( 4,1)),
                            CartesianIndex((-1,2)),
                            CartesianIndex(( 0,2)),
                            CartesianIndex(( 4,2))]
    iter = EdgeIterator((1:3,0:3), (1:3,1:2))
    @test collect(iter) == [CartesianIndex(( 1,0)),
                            CartesianIndex(( 2,0)),
                            CartesianIndex(( 3,0)),
                            CartesianIndex(( 1,3)),
                            CartesianIndex(( 2,3)),
                            CartesianIndex(( 3,3))]
    iter = EdgeIterator((1:3,1:2), (1:3,1:2))
    @test collect(iter) == []
    @test_throws DimensionMismatch EdgeIterator((1:3,1:1), (1:3,1:2))
    @test_throws DimensionMismatch EdgeIterator((1:3,1:2), (1:4,1:2))
    iter = EdgeIterator(CartesianIndices((0:4,)), CartesianIndices(1:3))
    @test collect(iter) == [CartesianIndex(0,),
                            CartesianIndex(4,)]
    iter = EdgeIterator((Base.OneTo(2),Base.OneTo(3)),(2:2,1:3))
    for it in iter
        @test it ∈ iter.outer
    end
    iter = EdgeIterator(CartesianIndices((1:4,)),CartesianIndices((2:4,)))
    for it in iter
        @test it ∈ iter.outer
    end
end

@testset "padded sizes" begin
    @test @inferred(padded_tilesize(UInt8, (1,))) == (2^14,)
    @test @inferred(padded_tilesize(UInt16, (1,))) == (2^13,)
    @test @inferred(padded_tilesize(Float64, (1,))) == (2^11,)
    @test @inferred(padded_tilesize(Float64, (1,1))) == (2^11, 1)
    @test @inferred(padded_tilesize(Float64, (2,1))) == (2^11, 1)
    shp = @inferred(padded_tilesize(Float64, (2,2)))
    @test all(x->x>2, shp)
    @test 2^13 <= prod(shp)*8 <= 2^14
    shp = @inferred(padded_tilesize(Float64, (3,3,3)))
    @test all(x->x>3, shp)
    @test 2^13 <= prod(shp)*8 <= 2^14
end

@testset "threads" begin
    function sumtiles(A, sz)
        indsA = axes(A)
        iter = TileIterator(indsA, sz)
        sums = zeros(eltype(A), length(iter))
        for (i,tileinds) in enumerate(iter)
            v = view(A, tileinds...)
            if sums[i] == 0
                sums[i] = sum(v)
            else
                sums[i] = -sum(v)
            end
        end
        sums
    end
    function sumtiles_threaded(A, sz)
        indsA = axes(A)
        iter = TileIterator(indsA, sz)
        allinds = collect(iter)
        sums = zeros(eltype(A), length(iter))
        Threads.@threads for i = 1:length(allinds)
            tileinds = allinds[i]
            v = view(A, tileinds...)
            if sums[i] == 0
                sums[i] = sum(v)
            else
                sums[i] = -sum(v)
            end
        end
        sums
    end

    Asz, tilesz = Base.JLOptions().can_inline == 1 ? ((1000,1000), (100,100)) : ((100,100), (10,10))
    A = rand(Float64, Asz)
    snt = sumtiles(A, tilesz)
    st = sumtiles_threaded(A, tilesz)
    @test snt == st
    @test all(st .> 0)
end

@testset "TileBuffer" begin
    a = fill!(Array{Int}(undef,5,5), 0)
    v = @inferred(TileBuffer(a, (2:3, 97:99)))
    @test ndims(v) == 2
    @test eltype(v) == Int
    @test axes(v) == (2:3, 97:99)
    v[2,97] = 1
    @test a[1] == 1
    p = pointer(v)
    @test parent(v) === v.buf
    v = @inferred(TileBuffer(v, (-1:1, 1:1)))
    @test pointer(v) == p
    @test axes(v) == (-1:1, 1:1)
    @test v[-1,1] == 1
    @test v[0,1] == v[1,1] == 0
    v[0,1] = 2
    @test a[2] == 2
    v = @inferred(TileBuffer(v, (0:23,)))
    @test pointer(v) == p
    @test eltype(v) == Int
    @test ndims(v) == 1
    @test axes(v) == (0:23,)
    @test v[1] == 2
    @test_throws BoundsError v[24]
    opts = Base.JLOptions()
    if opts.can_inline == 1 && opts.check_bounds == 0
        @inbounds v[24] = 7
        @test a[25] == 7
        @test (@inbounds v[24]) == 7
    end
    @test_throws DimensionMismatch TileBuffer(a, (1:6,1:5))
    @test_throws DimensionMismatch TileBuffer(v, (1:5,1:6))
    @test_throws DimensionMismatch TileBuffer(a, (0:25,))
    b = TileBuffer(Float64, (1:16,1:4))
    @test eltype(b) == Float64
    @test axes(b) == (1:16,1:4)
    @test pointer(b) != p
    p = pointer(b)
    b = TileBuffer(b, (17:32,1:4))
    @test pointer(b) == p
    @inbounds begin
        b[17,2] = 5.2
        @test b[17,2] == 5.2
    end
end

nothing


text:
using FractionalDiffEq, Plots

α = 1.8; h = 1e-2

# Analytical solution
analytical(x) = x.^1.8 .*mittleff(1.8, 2.8, -x.^1.8)
# Numerical solution
fun(x, y) = 1-y
#prob = SingleTermFODEProblem(fun, 1.8, [0, 0], (0, 20))
prob = SingleTermFODEProblem(fun, α, [0, 0], (0, 20))
sol1 = solve(prob, h, PECE())
sol2 = solve(prob, h, GL())
sol3 = solve(prob, h, PIEX())

tspan = collect(0:0.01:20)
target = analytical.(tspan)

plot(sol1)
plot!(sol2)
plot!(sol3)
#plot!(tspan, target, lw=3, ls=:dash, label="Analytical")