text:
function Base.show(io::IO, ::MIME"text/plain", org::OrgDoc)
    if get(io, :compact, false)
        print(io, "OrgDoc(", length(org), " children)")
    else
        termwidth = displaysize(io)[2]
        narrowedio = IOContext(io, :displaysize => (displaysize(io)[1], min(80, termwidth)))
        term(narrowedio, org)
    end
end

function term(io::IO, o::OrgDoc, indent::Integer=2)
    term(io, o, o.contents, indent)
    termfootnotes(io, o, indent)
end

function term(io::IO, o::OrgDoc, component::Component, indent::Integer)
    print(io, ' '^indent)
    term(io, o, component)
end

term(io::IO, ::OrgDoc, component::Component) =
    term(io, component)

function term(io::IO, o::OrgDoc, components::Vector{<:Component}, indent::Integer=2)
    for component in components
        (component isa Heading && component !== first(components)) && print(io, '\n')
        term(io, o, component, indent)
        component === last(components) || print(io, '\n')
    end
end

term(o::OrgDoc) = term(stdout, o, 2)
term(c::Component) = term(stdout, OrgDoc(), c, 2)
term(p::Paragraph) = (term(stdout, p, 2); print('\n'))
term(o::Object) = (term(stdout, OrgDoc(), o, 2); print('\n'))

# ---------------------
# Sections
# ---------------------

const HeadingKeywordColors = Dict("TODO" => :green,
                                  "PROJ" => :light_black,
                                  "LOOP" => :green,
                                  "STRT" => :magenta,
                                  "WAIT" => :yellow,
                                  "HOLD" => :yellow,
                                  "IDEA" => :green,
                                  "DONE" => :light_black,
                                  "KILL" => :red,
                                  "[ ]" => :green,
                                  "[?]" => :yellow,
                                  "[-]" => :magenta,
                                  "[X]" => :light_black)

function termheadingonly(io::IO, heading::Heading)
    printstyled(io, '*'^heading.level, ' ', bold=true, color=:blue)
    if !isnothing(heading.keyword)
        kcolor = if heading.keyword in keys(HeadingKeywordColors)
            HeadingKeywordColors[heading.keyword]
        else
            :green
        end
        printstyled(io, heading.keyword, ' ', color=kcolor)
    end
    if !isnothing(heading.priority)
        printstyled(io, "[#", heading.priority, "] ", color=:light_red)
    end
    print(io, termstyle("34"))
    for obj in heading.title
        term(io, obj, ["34"])
    end
    print(io, termstyle())
    if length(heading.tags) > 0
        printstyled(io, " :", join(heading.tags, ":"), ":", color=:light_black)
    end
end

function term(io::IO, o::OrgDoc, heading::Heading, indent::Integer=0)
    print(io, ' '^indent)
    termheadingonly(io, heading)
    if !isnothing(heading.section)
        print(io, '\n')
        if all(isnothing, (heading.section.planning,
                           heading.section.properties))
            print(io, '\n')
        end
        term(io, o, heading.section, indent)
    end
end

function term(io::IO, o::OrgDoc, section::Section, indent::Integer=0)
    if !isnothing(section.planning)
        term(io, o, section.planning, indent)
        print(io, "\n\n")
    end
    # Don't show properties
    for component in section.contents
        component isa FootnoteDefinition && continue
        term(io, o, component, indent)
        component === last(section.contents) || print(io, "\n\n")
    end
end

# Extras

function tableofcontents(io::IO, org::OrgDoc, depthrange::UnitRange=1:9, indent::Integer=2)
    for h in org.headings
        if h.level in depthrange
            print(io, ' '^indent)
            termheadingonly(io, h)
            print(io, '\n')
        end
    end
end

tableofcontents(org::OrgDoc, depthrange::UnitRange=1:9, indent::Integer=2) =
    tableofcontents(stdout, org, depthrange, indent)

tableofcontents(io::IO, org::OrgDoc, depth::Integer, indent::Integer=2) =
    tableofcontents(io, org, depth:depth, indent)

tableofcontents(org::OrgDoc, depth) = tableofcontents(stdout, org, depth)

function termfootnotes(io::IO, o::OrgDoc, indent::Integer=0)
    footnotes = collect(o.footnotes)
    if length(footnotes) > 0
        sort!(footnotes, by=f->f.second[1])
        print(io, "\n\n")
        for (i, fn) in map(f->f.second, footnotes)
            if fn isa FootnoteReference
                term(io, o, FootnoteDefinition(string(i), [Paragraph(fn.definition)]), indent)
            else
                term(io, o, FootnoteDefinition(string(i), fn.definition), indent)
            end
            i == length(footnotes) || println(io, '\n')
        end
    end
end

function term(io::IO, o::OrgDoc, afkw::AffiliatedKeywordsWrapper, indent::Integer=0)
    @nospecialize afkw
    for afk in afkw.keywords
        if !startswith(afk.key, "attr_")
            term(io, o, Keyword(afk.key, afk.value), indent)
            print(io, '\n')
        end
    end
    term(io, o, afkw.element, indent)
end

# ---------------------
# Greater Elements
# ---------------------

function term(io::IO, o::OrgDoc, specialblock::SpecialBlock, indent::Integer=0)
    printstyled(io, ' '^indent, "#+begin_", specialblock.name, '\n', color=:light_black)
    for el in specialblock.contents
        term(io, o, el, indent)
        print(io, '\n')
    end
    printstyled(io, ' '^indent, "#+end_", specialblock.name, color=:light_black)
end

function term(io::IO, o::OrgDoc, centerblock::CenterBlock, indent::Integer=0)
    width = displaysize(io)[2] - indent
    contentbuf = IOContext(IOBuffer(), :color => get(io, :color, false),
                           :displaysize => (displaysize(io)[1], width))
    for el in centerblock.contents
        term(contentbuf, o, el, indent)
    end
    for line in split(String(take!(contentbuf.io)), '\n')
        print(io, ' '^(indent + max(0, (width - textwidth(line))÷2)), line)
    end
end

function term(io::IO, o::OrgDoc, quoteblock::QuoteBlock, indent::Integer=0)
    contentbuf = IOContext(IOBuffer(), :color => get(io, :color, false),
                           :displaysize => (displaysize(io)[1],
                                            displaysize(io)[2] - indent - 2))
    for el in quoteblock.contents
        term(contentbuf, o, el, 0)
    end
    lines = split(String(take!(contentbuf.io)), '\n')
    for line in lines
        print(io, ' '^indent)
        printstyled(io, "┃ ", color=:light_black)
        print(io, line)
        line === last(lines) || print(io, '\n')
    end
end

function term(io::IO, o::OrgDoc, drawer::Drawer, indent::Integer=0)
    for component in drawer.contents
        component isa FootnoteDefinition && continue
        term(io, o, component, indent)
        component === last(drawer.contents) || print(io, '\n')
    end
end

function term(io::IO, o::OrgDoc, dynblock::DynamicBlock, indent::Integer=0)
    for el in dynblock.contents
        term(io, o, el, indent)
    end
end

function term(io::IO, o::OrgDoc, fn::FootnoteDefinition, indent::Integer=0)
    printstyled(io, ' '^indent, "[", fn.label, "] ", color=:yellow)
    contentbuf = IOContext(IOBuffer(), :color => get(io, :color, false),
                           :displaysize => (displaysize(io)[1],
                                            displaysize(io)[2] - indent - 2))
    parlines = if fn.definition[1] isa Paragraph
        for obj in fn.definition[1]; term(contentbuf, o, obj) end
        contents = String(take!(contentbuf.io))
        wraplines(contents, displaysize(io)[2] - indent, 6 + ncodeunits(fn.label))
    else
        [""]
    end
    components = @view fn.definition[if fn.definition[1] isa Paragraph 2 else 1 end:end]
    for component in components
        term(contentbuf, o, component, indent)
        component === last(components) || print(contentbuf, '\n')
    end
    otherlines = split(String(take!(contentbuf.io)), '\n')
    lines = vcat(parlines, if otherlines == [""]; [] else otherlines end)
    for line in lines
        print(io, line)
        line === last(lines) || print(io, '\n', ' '^indent)
    end
end

# InlineTask

function term(io::IO, o::OrgDoc, item::Item, ordered::Bool=false, indent::Integer=0, depth::Integer=0)
    print(io, ' '^indent)
    offset = indent
    if ordered
        printstyled(io, item.bullet, color=:blue)
    else
        printstyled(io, if depth % 2 == 0 '•' else '➤' end, color=:blue)
    end
    offset += length(item.bullet)
    if !isnothing(item.checkbox)
        printstyled(io, " [", item.checkbox, ']',
                    color=Dict(' ' => :green, '-' => :magenta, 'X' => :light_black)[item.checkbox])
        offset += 4
    end
    if !isnothing(item.tag)
        print(io, ' ', termstyle("34"))
        tagbuf = IOContext(IOBuffer(), :color => get(io, :color, false),
                           :displaysize => (displaysize(io)[1],
                                            displaysize(io)[2] - indent - 2))
        for obj in item.tag
            term(tagbuf, o, obj, ["34"])
        end
        taglines = wraplines(String(take!(tagbuf.io)),
                             displaysize(io)[2] - indent - 2, offset)
        for line in taglines
            print(io, line)
            line === last(taglines) || print(io, '\n', ' '^(indent+2))
        end
        print(io, " ::", termstyle())
        offset += textwidth(taglines[end]) -
            ansi_escape_textwidth_offset(taglines[end]) + 3
    end
    if length(item.contents) > 0
        print(io, ' ')
        offset += 1
        contentbuf = IOContext(IOBuffer(), :color => get(io, :color, false),
                               :displaysize => (displaysize(io)[1],
                                                displaysize(io)[2] - indent - 2))
        parlines = if item.contents[1] isa Paragraph
            for obj in item.contents[1]; term(contentbuf, o, obj) end
            contents = String(take!(contentbuf.io))
            wraplines(contents, displaysize(io)[2] - indent - 2, offset)
        else
            ["\n"]
        end
        components = @view item.contents[if item.contents[1] isa Paragraph 2 else 1 end:end]
        for component in components
            if component isa List
                term(contentbuf, o, component, indent, depth+1)
            else
                term(contentbuf, o, component, indent)
            end
            component === last(components) || print(contentbuf, '\n')
        end
        otherlines = split(String(take!(contentbuf.io)), '\n')
        lines = vcat(parlines, if otherlines == [""]; [] else otherlines end)
        for line in lines
            print(io, line)
            line === last(lines) || print(io, '\n', ' '^indent)
        end
    end
end

function term(io::IO, o::OrgDoc, list::List, indent::Integer=0, depth::Integer=0)
    @nospecialize list
    for item in list.items
        term(io, o, item, list isa OrderedList, indent, depth)
        item === last(list.items) || print(io, '\n')
    end
end

term(::IO, ::PropertyDrawer, _::Integer=0) = nothing

const table_charset_boxdraw =
    Dict('|' => '│',
         '>' => '├',
         '<' => '┤',
         '[' => ' ',
         ']' => ' ',
         '-' => '─',
         '+' => '┼')
const table_charset_boxdraw_slim =
    Dict('|' => ' ',
         '>' => ' ',
         '<' => ' ',
         '[' => "",
         ']' => "",
         '-' => '─',
         '+' => '─')

function term(io::IO, o::OrgDoc, table::Table, indent::Integer=0)
    printer = (io, c) -> term(io, o, c)
    layouttable(io, printer, table, table_charset_boxdraw, indent)
end

# ---------------------
# Elements
# ---------------------

term(::IO, ::BabelCall) = nothing

function printblockcontent(io, prefix::String, prefixcolor::Symbol, lines::Vector{<:SubString{String}}, contentcolor::Symbol=:default)
    printstyled(io, prefix, color=prefixcolor)
    if length(lines) > 0
        printstyled(io, lines[1], color=contentcolor)
        if length(lines) > 1
            for line in lines[2:end]
                printstyled(io, '\n', prefix, color=prefixcolor)
                printstyled(io, line, color=contentcolor)
            end
        end
    end
end

term(::IO, ::CommentBlock) = nothing

function term(io::IO, block::Block, indent::Integer=0)
    name, data = if block isa VerseBlock
        ("verse", nothing)
    elseif block isa ExportBlock
        ("example", block.backend)
    end
    printstyled(io, ' '^indent, "#+begin_", name, color=:light_black)
    if !isnothing(data)
        print(io, ' ', data)
    end
    print(io, '\n')
    if block isa VerseBlock
        print(io, "Oh noes! A verse block...\n")
    else
        for line in block.contents
            print(io, ' '^indent)
            if startswith(line, '*')
                print(io, ',')
            end
            print(io, line, '\n')
        end
    end
    printstyled(io, ' '^indent, "#+end_", name, color=:light_black)
end

term(io::IO, ::OrgDoc, block::ExampleBlock, indent::Integer=0) =
    printblockcontent(io, ' '^indent * "║ ", :light_black, block.contents, :cyan)

term(::IO, ::OrgDoc, ::ExportBlock) = nothing

function term(io::IO, ::OrgDoc, srcblock::SourceBlock, indent::Integer=0)
    printstyled(io, ' '^indent, "╭", color=:light_black)
    if !isnothing(srcblock.lang)
        printstyled(io, '╴', srcblock.lang, '\n', color=:light_black)
    else
        print(io, '\n')
    end
    printblockcontent(io, ' '^indent * "│ ", :light_black, srcblock.contents, :cyan)
    printstyled(io, '\n', ' '^indent,"╰", color=:light_black)
end

function term(io::IO, clock::Clock{TimestampInactive})
    printstyled(io, "clock: ", color=:light_black)
    term(io, clock.timestamp)
end

function term(io::IO, clock::Clock{TimestampInactiveRange})
    printstyled(io, "clock: ", color=:light_black)
    term(io, clock.timestamp)
    printstyled(io, " for ",
                clock.duration[1], "h ", clock.duration[2], 'm',
                color=:yellow)
end

term(::IO, ::DiarySexp) = nothing

function term(io::IO, ::OrgDoc, planning::Planning)
    values = [(type, getproperty(planning, type))
              for type in (:deadline, :scheduled, :closed)] |>
                  vals -> filter(v -> !isnothing(v[2]), vals)
    for val in values
        printstyled(io, uppercase(string(val[1])), ' ', bold=true, color=:light_black)
        term(io, val[2])
        val === last(values) || print(io, ' ')
    end
end

term(::IO, ::Comment, _::Integer=0) = nothing

term(io::IO, fw::FixedWidth, indent::Integer=0) =
    printblockcontent(io, ' '^indent * "║ ", :light_black, fw.contents, :cyan)

term(io::IO, ::HorizontalRule) =
    printstyled(io, ' ', '─'^(displaysize(io)[2]-2), '\n', color=:light_black)

const DocumentInfoKeywords = ["title", "subtitle", "author"]

term(io::IO, ::OrgDoc, keyword::Keyword{Nothing}) =
    printstyled(io, "#+", keyword.key, ':', color = :light_black)

function term(io::IO, o::OrgDoc, keyword::Keyword{V}) where {V}
    printstyled(io, "#+", keyword.key, ':', color = :light_black)
    print(io, ' ')
    valuecolor = if keyword.key in DocumentInfoKeywords; ["35"] else ["90"] end
    print(io, termstyle(valuecolor))
    if V == Vector{Object}
        for obj in keyword.value
            term(io, o, obj, valuecolor)
        end
    else
        print(io, keyword.value)
    end
    print(io, termstyle())
end

function term(io::IO, ::OrgDoc, env::LaTeXEnvironment, indent::Integer=0)
    printstyled(io, ' '^indent, "\\begin", color=:light_blue)
    print(io, '{')
    printstyled(io, env.name, color=:magenta)
    print(io, '}')
    printstyled(io, env.contents[1], '\n', color=:light_blue)
    for line in env.contents[2:end]
        printstyled(io, ' '^(2+indent), line, '\n', color=:light_magenta)
    end
    printstyled(io, ' '^indent, "\\end", color=:light_blue)
    print(io, '{')
    printstyled(io, env.name, color=:magenta)
    print(io, '}')
end

term(io::IO, node::NodeProperty) =
    print(io, ':', node.name, if node.additive "+:" else ":" end, node.value)

function term(io::IO, o::OrgDoc, objs::Vector{Object})
    for obj in objs
        term(io, o, obj)
    end
end

function term(io::IO, o::OrgDoc, par::Paragraph, indent::Integer=0)
    contentbuf = IOContext(IOBuffer(), :color => get(io, :color, false))
    term(contentbuf, o, par.contents)
    contents = String(take!(contentbuf.io))
    lines = wraplines(contents, displaysize(io)[2] - indent)
    for line in lines
        print(io, ' '^indent, line)
        line === last(lines) || print(io, '\n')
    end
end

# Table Row

# ---------------------
# Objects
# ---------------------

# Terminal styling

termstyle(codes::Vector{String}) = if !get(stdout, :color, false)
    ""
else
    if length(codes) > 0
        string("\e[0;", join(codes, ';'), "m")
    else
        "\e[0m"
    end
end

termstyle(code::String) = if !get(stdout, :color, false)
    ""
else
    "\e[$(code)m"
end

termstyle() = termstyle(String[])

term(io::IO, o::OrgDoc, obj::Object, _::Vector{String}) =
    term(io::IO, o::OrgDoc, obj::Object)
term(io::IO, obj::Object, _::Vector{String}) =
    term(io::IO, obj::Object)

# Now onto the objects

term(io::IO, entity::Entity) = print(io, Entities[entity.name].utf8)

function term(io::IO, latex::LaTeXFragment)
    if isnothing(latex.delimiters)
        printstyled(io, latex.contents, color=:magenta)
    else
        printstyled(io, latex.delimiters[1], latex.contents,
                    latex.delimiters[2], color=:magenta)
    end
end

term(::IO, ::ExportSnippet) = nothing

const FootnoteUnicodeSuperscripts =
    Dict('1' => '¹',
         '2' => '²',
         '3' => '³',
         '4' => '⁴',
         '5' => '⁵',
         '6' => '⁶',
         '7' => '⁷',
         '8' => '⁸',
         '9' => '⁹',
         '0' => '⁰')

function term(io::IO, o::OrgDoc, fn::FootnoteReference, stylecodes::Vector{String}=String[])
    if haskey(o.footnotes, something(fn.label, fn))
        index = o.footnotes[something(fn.label, fn)][1]
        printstyled(io, join([FootnoteUnicodeSuperscripts[c] for c in string(index)]);
            color=:yellow)
    else
        printstyled(io, "[#undefined#]", color=:yellow)
    end
    print(io, termstyle(stylecodes))
end

function term(io::IO, o::OrgDoc, keycite::CitationReference)
    term(io, o, keycite.prefix)
    printstyled(io, '@', keycite.key, bold=true, color=:magenta)
    term(io, o, keycite.suffix)
end

function term(io::IO, o::OrgDoc, cite::Citation, stylecodes::Vector{String}=String[])
    printstyled(io, "[", color=:magenta)
    # if !isnothing(cite.style[1])
    #     printstyled(io, '/', cite.style[1], color=:blue)
    # end
    # if !isnothing(cite.style[2])
    #     printstyled(io, '/', cite.style[2], color=:light_blue)
    # end
    # printstyled(io, ':', color=:light_black)
    if !isempty(cite.globalprefix)
        term(io, o, cite.globalprefix)
        printstyled(io, ';', color=:light_magenta)
    end
    for keycite in cite.citerefs
        term(io, o, keycite)
        keycite === last(cite.citerefs) || printstyled(io, ';', color=:light_magenta)
    end
    if !isempty(cite.globalsuffix)
        printstyled(io, ';', color=:light_magenta)
        term(io, o, cite.globalsuffix)
    end
    printstyled(io, ']', color=:magenta)
    print(io, termstyle(stylecodes))
end

term(::IO, ::InlineBabelCall) = nothing

function term(io::IO, src::InlineSourceBlock)
    printstyled(io, src.body, color=:light_cyan)
end

term(io::IO, ::LineBreak) = print(io, '\n')

const term_stylecodes_link = ["4", "34"]

function term(io::IO, link::RadioLink, stylecodes::Vector{String}=String[])
    print(io, termstyle(term_stylecodes_link))
    for obj in link.radio.contents
        term(io, obj, [stylecodes; term_stylecodes_link])
    end
    print(io, termstyle(stylecodes))
end

const link_uri_schemes =
    Dict("https" => p -> "https://$p",
         "file" => p -> "file://$(abspath(p))")

function term(io::IO, path::LinkPath)
    if path.protocol in keys(link_uri_schemes)
        pathuri = link_uri_schemes[path.protocol](path.path)
        print(io, "\e]8;;", pathuri, "\e\\")
        "\e[0;31mꜛ\e[0;0m\e]8;;\e\\"
    else
        ""
    end
end

function term(io::IO, link::Union{PlainLink, AngleLink}, stylecodes::Vector{String}=String[])
    print(io, termstyle(term_stylecodes_link))
    pathlink = term(io, link.path)
    print(io, string(link.path))
    print(io, pathlink, termstyle(stylecodes))
end

function term(io::IO, o::OrgDoc, link::RegularLink, stylecodes::Vector{String}=String[])
    print(io, termstyle(term_stylecodes_link))
    pathlink = term(io, link.path)
    if isnothing(link.description) || length(link.description) == 0
        print(io, string(link.path))
    else
        for obj in link.description
            term(io, o, obj, [stylecodes; term_stylecodes_link])
        end
    end
    print(io, pathlink, termstyle(stylecodes))
end

function term(io::IO, o::OrgDoc, mac::Macro)
    expanded = macroexpand(o, mac)
    if isnothing(expanded)
        printstyled(io, "{{{", mac.name, '(', join(mac.arguments, ","), ")}}}", color=:light_black)
    else
        term.(Ref(io), parseorg(expanded, org_object_matchers, org_object_fallbacks))
    end
end

function term(io::IO, radio::RadioTarget, stylecodes::Vector{String}=String[])
    print(io, termstyle("4"))
    for obj in radio.contents
        term(io, obj, [stylecodes; "4"])
    end
    print(io, termstyle(stylecodes))
end

term(::IO, ::Target) = nothing

term(io::IO, statscookie::StatisticsCookiePercent) =
    printstyled(io, '[', statscookie.percentage, "%]",
                color=if statscookie.percentage == "100"; :light_black else :green end)
term(io::IO, statscookie::StatisticsCookieFraction) =
    printstyled(io, '[', if !isnothing(statscookie.complete) string(statscookie.complete) else "" end,
                '/', if !isnothing(statscookie.total) string(statscookie.total) else "" end, ']',
                color=if statscookie.complete == statscookie.total; :light_black else :green end)

term(io::IO, script::Superscript) = print(io, script.char, '^', script.script)
term(io::IO, script::Subscript) = print(io, script.char, '_', script.script)

term(io::IO, cell::TableCell) = printstyled(io, "| ", cell.contents, " |", color=:magenta)

function term(io::IO, tsrod::TimestampRepeaterOrDelay)
    timeunits = Dict('h' => "hour",
                     'd' => "day",
                     'w' => "week",
                     'm' => "month",
                     'y' => "year")
    if tsrod.type in (:cumulative, :catchup, :restart)
        printstyled(io, "every ", tsrod.value, ' ', timeunits[tsrod.unit],
                    if tsrod.value == 1 "" else 's' end, " thereafter",
                    color=:light_yellow)
    else
        printstyled(io, "warning ", tsrod.value, ' ', timeunits[tsrod.unit],
                    if tsrod.value == 1 "" else 's' end, " before",
                    color=:light_yellow)
    end
end

term(io::IO, tsd::TimestampDiary) = print(io, "<%%", tsd.sexp, '>')

function term(io::IO, ts::TimestampInstant)
    if !isnothing(ts.time)
        printstyled(io, hour(ts.time), ':', minute(ts.time), ' ', color=:yellow)
    end
    printstyled(io, Dates.format(ts.date, dateformat"e d u Y"), color=:yellow)
    if !isnothing(ts.repeater)
        printstyled(io, " and ", color=:light_yellow)
        term(io, ts.repeater)
    end
    if !isnothing(ts.warning)
        print(io, ' ')
        term(io, ts.warning)
    end
end

function term(io::IO, tsr::TimestampRange)
    if tsr.start.date == tsr.stop.date &&
        tsr.start.repeater == tsr.stop.repeater
        printstyled(io, tsr.start.date, ' ', dayabbr(tsr.start.date), color=:yellow)
        printstyled(io, ' ', hour(tsr.start.time), ':', minute(tsr.start.time),
                    " – ", hour(tsr.stop.time), ':', minute(tsr.stop.time), color=:yellow)
        if !isnothing(tsr.start.repeater)
            printstyled(io, " and ", color=:light_yellow)
            term(io, tsr.start.repeater)
        end
        if !isnothing(tsr.start.warning)
            print(io, ' ')
            term(io, tsr.start.warning)
        end
    else
        term(io, tsr.start)
        printstyled(io, " – ", color=:yellow)
        term(io, tsr.stop)
    end
end

const markup_term_codes =
    Dict(:bold => "1",
         :italic => "3",
         :strikethrough => "9",
         :underline => "4",
         :verbatim => "32", # green
         :code => "36") # cyan

function term(io::IO, o::OrgDoc, markup::TextMarkup, stylecodes::Vector{String}=String[])
    markuptermcode = markup_term_codes[markup.formatting]
    print(io, termstyle(markuptermcode))
    if markup.contents isa SubString{String}
        print(io, markup.contents)
    else
        for obj in markup.contents
            term(io, o, obj, [stylecodes; markuptermcode])
        end
    end
    print(io, termstyle(stylecodes))
end

function term(io::IO, text::TextPlain)
    tsub = replace(replace(replace(replace(text.text,
                                           "..." => "…"),
                                   r"---([^-])" => s"—\1"),
                           r"--([^-])" => s"–\1"),
                   r"\\-" => "-")
    print(io, tsub)
end

# ---------------------
# Catchall
# ---------------------

function term(io::IO, component::Component)
    @warn "No method for converting $(typeof(component)) to a term representation currently exists"
    print(io, component, '\n')
end


text:
function mergesort(arr)
    function merge(m1, m2)
        j = 1
        k = 1
        result = Int64[]
        while true
            if m1[j] > m2[k]
                append!(result, [m2[k]])
                k += 1
            else
                append!(result, [m1[j]])
                j += 1
            end
            if j == length(m1) + 1
                append!(result, m2[k:end])
                break
            end
            if k == length(m2) + 1
                append!(result, m1[j:end])
                break
            end
        end
        return result
    end

    n = length(arr)
    if n < 2
        return arr
    elseif n == 2
        if arr[1] > arr[2]
            temp = arr[1]
            arr[1] = arr[2]
            arr[2] = temp
        end
        return arr
    else
        lhs = mergesort(arr[1 : div(n, 2)])
        rhs = mergesort(arr[div(n, 2) + 1 : end])
        return merge(lhs, rhs)
    end
end

v = [5,9,1,3,4,6,6,3,2]
println(mergesort(v))

ext: jl


text:
include("spharm.jl")

function test_main()

  Ng = 5
  lmax = 2

  Gvec = zeros(3,Ng)

  for ig = 1:Ng
    Gvec[:,ig] = [1.3, 1.1, 2.1]*(ig-1)
  end

  ylm = zeros( Float64, Ng, (lmax+1)^2 )

  ilm = 0
  for l = 0:lmax
    @printf("l = %d\n", l)
    # m = 0
    ilm = ilm + 1
    ylm[:,ilm] = spharm( l, 0, Gvec )
    println(ilm)
    println(ilm, " ", l, " ", 0)
    # m > 0 and m < 0
    for m = 1:l
      ilm = ilm + 1
      ylm[:,ilm] = spharm( l, m, Gvec )*(-1.0)^m
      println(ilm, " ", l, " ", m)
      #
      ilm = ilm + 1
      ylm[:,ilm] = spharm( l, -m, Gvec )*(-1.0)^m
      println(ilm)
      println(ilm, " ", l, " ", -m)
    end
  end

  for lm = 1:(lmax+1)^2
    @printf("\n")
    @printf("lm = %5d\n", lm)
    for ig = 1:Ng
      @printf("%5d %18.10f\n", ig, ylm[ig,lm])
    end
  end

end

test_main()


text:
using Documenter
using AtomicGraphNets

# The DOCSARGS environment variable can be used to pass additional arguments to make.jl.
# This is useful on CI, if you need to change the behavior of the build slightly but you
# can not change the .travis.yml or make.jl scripts any more (e.g. for a tag build).
if haskey(ENV, "DOCSARGS")
    for arg in split(ENV["DOCSARGS"])
        (arg in ARGS) || push!(ARGS, arg)
    end
end

pages = Any[
    "Home"=>"index.md",
    "Basic Graph Theory"=>"graph_theory.md",
    "GCNNs"=>"gcnns.md",
    "Comparison with cgcnn.py"=>"comparison.md",
    "Examples"=>Any["Example 1"=>"examples/example_1.md",],
    "Functions"=>Any["Layers"=>"functions/layers.md", "Models"=>"functions/models.md"],
    "Changelog"=>"changelog.md",
]

makedocs(
    sitename = "AtomicGraphNets.jl",
    modules = [AtomicGraphNets],
    pages = pages,
    format = Documenter.HTML(
        # Use clean URLs, unless built as a "local" build
        prettyurls = !("local" in ARGS),
        canonical = "https://chemellia.github.io/AtomicGraphNets.jl/stable/",
        edit_link = "main",
    ),
    linkcheck = "linkcheck" in ARGS,
)
deploydocs(
    repo = "github.com/Chemellia/AtomicGraphNets.jl.git",
    target = "build",
    branch = "gh-pages",
    devbranch = "main",
    push_preview = true,
)

# for local build
"""
makedocs(
    sitename = "AtomicGraphNets.jl",
    modules = [AtomicGraphNets],
    pages = pages,
    format = Documenter.HTML(
        # Use clean URLs, unless built as a "local" build
        prettyurls = false,
        canonical = "https://chemellia.github.io/AtomicGraphNets.jl/stable/",
        edit_link = "main",
    ),
    linkcheck = "linkcheck" in ARGS,
)
"""


text:
#### DomainIdx

export DomainIdx, subdomains, alldomains, eachdomain, allcombinations

"""
    DomainIdx{GM,EN,UD}

Decomposition of domain indexes, including indexes for
 - `i_gm` grid-mean domain
 - `i_en` environment sub-domain
 - `i_ud` updraft sub-domains

Note that the index ordering logic is defined here.
"""
struct DomainIdx{GM,EN,UD} end

function get_idx(gm,en,ud)
  i_gm,i_en,i_ud = 0,0,(0,)
  ud>0 && (i_ud = Tuple([i for i in 1:ud]))
  en>0 && (i_en = max(i_ud...)+1)
  gm>0 && en>0 && (i_gm = i_en+1)
  gm>0 && !(en>0) && (i_gm = max(i_ud...)+1)
  return i_gm,i_en,i_ud
end

""" Constructor for DomainDecomp """
function DomainIdx(dd::DomainDecomp)
  i_gm,i_en,i_ud = get_idx(get_param(dd)...)
  return DomainIdx{i_gm,i_en,i_ud}()
end

gridmean(   ::DomainIdx{GM,EN,UD}) where {GM,EN,UD} = GM
environment(::DomainIdx{GM,EN,UD}) where {GM,EN,UD} = EN
updraft(    ::DomainIdx{GM,EN,UD}) where {GM,EN,UD} = UD

has_gridmean(   ::DomainIdx{GM,EN,UD}) where {GM,EN,UD} = !(GM==0)
has_environment(::DomainIdx{GM,EN,UD}) where {GM,EN,UD} = !(EN==0)
has_updraft(    ::DomainIdx{GM,EN,UD}) where {GM,EN,UD} = !(UD==(0,))

# TODO: write a state-vector wrapper for the exported functions
"""
    subdomains(idx::DomainIdx)

Tuple of sub-domain indexes, including environment and updrafts
"""
subdomains(idx::DomainIdx)      = (environment(idx),updraft(idx)...)

"""
    alldomains(idx::DomainIdx)

Tuple of all sub-domain indexes, including grid-mean, environment and updrafts
"""
alldomains(idx::DomainIdx)      = (gridmean(idx),environment(idx),updraft(idx)...)

"""
    eachdomain(idx::DomainIdx)

Tuple of indexes including
 - grid-mean
 - environment
 - Tuple of updraft indexes
"""
eachdomain(idx::DomainIdx)      = (gridmean(idx),environment(idx),updraft(idx))

"""
    allcombinations(idx::DomainIdx)

Tuple of indexes including
 - grid-mean
 - environment
 - Tuple of updraft indexes
 - Tuple of all sub-domains
 - Tuple of all domains
"""
allcombinations(idx::DomainIdx) = (gridmean(idx),environment(idx),updraft(idx),subdomains(idx),alldomains(idx))

function DomainIdx(dd::DomainDecomp, dss::DomainSubSet{BGM,BEN,BUD}) where {BGM,BEN,BUD}
  i_gm,i_en,i_ud = get_idx(get_param(dd,dss)...)
  return DomainIdx{i_gm,i_en,i_ud}()
end

@inline get_i_state_vec(vm, a_map::AbstractArray, ϕ::Symbol, i) = vm[ϕ][a_map[i]]
@inline get_i_var(a_map::AbstractArray, i) = a_map[i]

function var_suffix(vm, idx::DomainIdx, idx_ss::DomainIdx, ϕ::Symbol, i)
  if i == gridmean(idx)
    return "_gm"
  elseif i == environment(idx)
    return "_en"
  elseif i in updraft(idx)
    return "_ud_"*string(i)
  else
    throw(BoundsError(vm[ϕ], i))
  end
end

function var_string(vm, idx::DomainIdx, idx_ss::DomainIdx, ϕ::Symbol, i)
  string(ϕ)*var_suffix(vm, idx, idx_ss, ϕ, i)
end

max_stars_repo_name: akshaysridhar/CLIMA

max_issues_repo_name: akshaysridhar/CLIMA

max_forks_repo_name: akshaysridhar/CLIMA


text:
abstract AbstractSRID

# when we don't know
immutable UnknownSRID <: AbstractSRID end

# SRID as a type (so we can multiple disbatch based on it)
# auth is a symbol, code is an integer
immutable SRID{auth, code} <: AbstractSRID end  # good to have it as a subtype of datum?
show{auth, code}(io::IO, ::Type{SRID{auth, code}}) = print(io, "$(auth)$(code)")

# get the template components
get_auth{auth, code}(::Type{SRID{auth, code}}) = auth
get_code{auth, code}(::Type{SRID{auth, code}}) = code

# grab the datum as well
get_datum{T <: AbstractSRID}(::Union{Type{T}, T}) = UnknownDatum     # default answer when called on the appropriate thing

#=
# Ideally an SRID would be this but the below can't be use as a parameter of another type for reasons, while a (Symbol, Int) tupple can be a parameter zzz
immutable SRID <: AbstractSRID
    auth::Symbol
    code::Int
end
=#


text:
module CommunalHelperChainedFallingBlock

using ..Ahorn, Maple
using Cairo

@mapdef Entity "CommunalHelper/ChainedFallingBlock" ChainedFallingBlock(
    x::Integer,
    y::Integer,
    width::Integer=Maple.defaultBlockWidth,
    height::Integer=Maple.defaultBlockWidth,
    tiletype::String="3",
    climbFall::Bool=true,
    behind::Bool=false,
    fallDistance::Integer=64,
    centeredChain::Bool=false,
    chainOutline::Bool=true,
    indicator::Bool=false,
    indicatorAtStart::Bool=false,
)

const placements = Ahorn.PlacementDict(
    "Falling Block (Chained) (Communal Helper)" => Ahorn.EntityPlacement(
        ChainedFallingBlock,
        "rectangle",
        Dict{String, Any}(),
        Ahorn.tileEntityFinalizer,
    ),
)

Ahorn.editingOptions(entity::ChainedFallingBlock) = Dict{String, Any}(
    "tiletype" => Ahorn.tiletypeEditingOptions()
)

Ahorn.minimumSize(entity::ChainedFallingBlock) = 8, 8
Ahorn.resizable(entity::ChainedFallingBlock) = true, true

Ahorn.selection(entity::ChainedFallingBlock) = Ahorn.getEntityRectangle(entity)

function Ahorn.renderAbs(ctx::Ahorn.Cairo.CairoContext, entity::ChainedFallingBlock, room::Maple.Room)
    x, y = Ahorn.position(entity)
    w = Int(get(entity.data, "width", 8))
    h = Int(get(entity.data, "height", 8)) + Int(get(entity.data, "fallDistance", 64))

    save(ctx)

    set_dash(ctx, [0.6, 0.2])
    set_antialias(ctx, 1)
    set_line_width(ctx, 1)

    # width & height extend up and left for some reason.
    Ahorn.drawRectangle(ctx, x + 1, y + 1, w - 1, h - 1, (0.0, 0.0, 0.0, 0.0), (1.0, 1.0, 1.0, 0.5))

    restore(ctx)

    Ahorn.drawTileEntity(ctx, room, entity)
end

end


text:
@testset "7.2 Inverse hyperbolic cosine" begin
    include("(d+e x)^p (-d+e x)^q (a+b arccosh(c x))^n.jl")
    include("7.2.2 (d x)^m (a+b arccosh(c x))^n.jl")
    include("7.2.4 (f x)^m (d+e x^2)^p (a+b arccosh(c x))^n.jl")
    include("7.2.5 Inverse hyperbolic cosine functions.jl")
end

max_stars_repo_path: test/7 Inverse hyperbolic functions/7.2 Inverse hyperbolic cosine/.jl


text:
module Users

struct Team
    databaseid::Int
    name::String
    icon::String
end

struct User
    databaseid::Int
    userid::String
    displayname::String
    team::Team
end

Base.print(io::IO, user::User) = print(io, user.displayname)

export User, Team

end


text:
module DevEnvConfig

"""
    @enum ActionStatus Success Warning Error

Return type of configuration actions
"""
@enum ActionStatus Success Warning Error

# The path the "src" directory of the package
function devEnvConfig_src_path()
    dirname(pathof(DevEnvConfig))
end
function devEnvConfig_pkg_path()
    dirname(devEnvConfig_src_path())
end

include("tools/RuntimeEnv.jl")
include("tools/RuntimeContext.jl")
include("tools/CmdTools.jl")
include("tools/GitTools.jl")
include("sysimages/SysImageBuilder.jl")
include("pkg/PkgCreate.jl")

"""
    function newpkg(pkname::String;
        private         :: Bool,
        dir             :: String|∅ = nothing,
        docrepo         :: String|∅ = nothing,
        useextjl        :: Bool|∅   = nothing,
        generalregistry :: Bool|∅   = nothing,
        license         :: String|∅ = nothing) -> ActionStatus

Create a new package. This will use your GitHub account to:
* setup documentation generation and deployment,
* setup unit testing and badge status,
* setup code coverage on CodeCov and badge statu

This template handles private package repo, with doc deployment in another (public) repo.
Also provides guided setup for code coverage reporting for private repo.

# Arguments

* `pkname`: the name of the new Julia Package
* `private`: set to `true` is this package is hosted in a private GitHub repository
* `dir`: the directory is which to create the package, defaul to `JULIA_PKG_DEVDIR`
* `docrepo`: the name of a GitHub repo used to publish the documentation, default to the package repo.
* `useextjl`: set t`o `true` if the GitHub repository is named `PackageName.jl`, default to `!private`
* `generalregistry`: set to `true` if this package will be registered in General, default to `!private`
* `license`: name of the LICENSE file, default to `MIT` for public package
"""
const newpkg = PkgCreate.create
export newpkg

end # module DevEnvConfig


text:
######################################################################
# eif.jl
# Extended information filter
######################################################################

type EIF
	eta::Vector{Float64}
	Omega::Matrix{Float64}
	theta::NTuple{2, Float64}

	function EIF(m::SearchDomain)
		Omega = 1e-8 * eye(2)
		eta = inv(Omega) * ones(2) * m.length / 2

		return new(eta, Omega, m.theta)
	end
end

# have to include search domain because jammer location factors in
# Really, I should just fold that into the state
# TODO: just subtracting is not ok, need circle distance (can be negative)
function update!(eif::EIF, x::Vehicle, o::Float64)
	if eif.Omega == zeros(2,2)
		eif.Omega = [1e-8 0; 0 1e-8]
	end
	mu_t = inv(eif.Omega) * eif.eta

	# compute Omega_t
	xr = m.theta[1] - x.x
	yr = m.theta[2] - x.y
	Ht = [yr, -xr]' * (180.0 / pi) / (xr^2 + yr^2)
	Omega_t = eif.Omega + dot(vec(Ht),vec(Ht)) / 100.0

	# compute eta_t
	eta_t = eif.eta + Ht' * (o - true_bearing((x.x,x.y),eif.theta) + Ht*mu_t) / 100.0

	eif.eta = vec(eta_t)
	eif.Omega = Omega_t
end


text:
using PyPlot
using DelimitedFiles

# specify workspace directory
ws_dir = pwd() * "/";

out_file = ws_dir * "Emulation-SW/x86simulator_output/output.dat";	# impulse response from AI engine simulation

# read the file
aie_out = readdlm(out_file);

# plot the difference
plot(aie_out);
grid("on");
title("AI Engine Output");
xlabel("Sampling Index");
ylabel("Amplitude");

max_stars_repo_name: jlamperez/Vitis-Tutorials

max_issues_repo_name: jlamperez/Vitis-Tutorials

max_forks_repo_name: jlamperez/Vitis-Tutorials


text:
using GraphNeuralNetworks
using Statistics

"""
  GraphSAGEHP

Hyperparameters for the gin architecture.

"""
@kwdef struct GraphSAGEHP
  depth_common :: Int = 12
  depth_phead :: Int = 3
  depth_vhead :: Int = 3
  hidden_size :: Int = 40
end

"""
    Gin <: TwoHeadGraphNeuralNetwork

A simple two-headed GNN architecture with only dense layers.
"""
mutable struct GraphSAGE <: TwoHeadGraphNeuralNetwork
  gspec
  hyper
  common
  vhead
  phead
end

function GraphSAGE(gspec::AbstractGameSpec, hyper::GraphSAGEHP)
  indim, n_nodes  = GI.state_dim(gspec)
  SAGE_layers(depth) = [GNNChain(SAGEConv(((i==1) ? indim : hyper.hidden_size) => hyper.hidden_size, relu, aggr=mean),
                                BatchNorm(hyper.hidden_size, relu)) for i in 1:depth]
  Dense_layers(size, depth) = [Chain(Dense(size, size, relu), BatchNorm(size)) for _ in 1:depth]
  common = GNNChain(SAGE_layers(hyper.depth_common)...)
  vhead = GNNChain(GlobalPool(mean),
                   Dense_layers(hyper.hidden_size, hyper.depth_vhead)...,
                   Dense(hyper.hidden_size, 1, identity))
  phead = GNNChain(Parallel(vcat, GNNChain(GlobalPool(mean), x -> repeat(x, 1, n_nodes)), identity),
                  Dense_layers(hyper.hidden_size*2, hyper.depth_phead)...,
                  Dense(hyper.hidden_size*2, 1),
                  x->reshape(x, n_nodes,:),
                  softmax)
  return GraphSAGE(gspec, hyper, common, vhead, phead)
end

Network.HyperParams(::Type{GraphSAGE}) = GraphSAGEHP

function Base.copy(nn::GraphSAGE)
  return GraphSAGE(
    nn.gspec,
    nn.hyper,
    deepcopy(nn.common),
    deepcopy(nn.vhead),
    deepcopy(nn.phead)
  )
end


text:
# BLAST+ Wrapper
# ==============
#
# Wrapper for BLAST+ command line functions.
#
# This file is a part of BioJulia.
# License is MIT: https://github.com/BioJulia/Bio.jl/blob/master/LICENSE.md

struct BLASTResult
    bitscore::Float64
    expect::Float64
    queryname::String
    hitname::String
    hittaxid::String
    hitid::String
    hitaccession::String
    hitlen::Int64
    hit::LongSequence
    identity::Int64
    positive::Int64
    gaps::Int64
    queryfrom::Int64
    queryto::Int64
    hitfrom::Int64
    hitto::Int64
    alignment::AlignedSequence
end

"""
    readblastXML2(blastrun::AbstractString)
Parse XML2 output of a blast run (blastn format #16). Input is an XML string eg:
```julia
results = read(open("blast_results.xml"), String)
readblastXML(results)
```
Returns Vector{BLASTResult} with the sequence of the hit, the Alignment with query sequence, bitscore and expect value
"""
function readblastXML2(blastrun::AbstractString; seqtype="nucl")
    results = BLASTResult[]
    xdoc = parse_string(blastrun)
    xroot = LightXML.root(xdoc)
    blast_outputs = get_elements_by_tagname(xroot, "BlastOutput2")
    for blast_output in blast_outputs
        report = get_elements_by_tagname(blast_output, "report")[1]
        Report = get_elements_by_tagname(report, "Report")[1]
        Search = Report["results"][1]["Results"][1]["search"][1]["Search"][1]
        queryname = content(Search["query-title"][1])
        for hit in Search["hits"][1]["Hit"]
            #println(hit["num"])
            hitdescr = hit["description"][1]["HitDescr"][1]
            hitname = content(hitdescr["title"][1])
            hitid = content(hitdescr["id"][1])
            hitaccession = content(hitdescr["accession"][1])
            hittaxid = content(hitdescr["taxid"][1])
            hitlen = parse(Int64,content(hit["len"][1]))
            for hsp in hit["hsps"][1]["Hsp"]
                gaps = parse(Int64,content(hsp["gaps"][1]))
                qseq = content(hsp["qseq"][1])
                hseq = content(hsp["hseq"][1])
                if seqtype == "nucl"
                    qseq = LongSequence{DNAAlphabet{4}}(qseq)
                    hseq = LongSequence{DNAAlphabet{4}}(hseq)
                    positive = 0
                elseif seqtype == "prot"
                    qseq = LongSequence{AminoAcidAlphabet}(qseq)
                    hseq = LongSequence{AminoAcidAlphabet}(hseq)
                    positive = parse(Int64,content(hsp["positive"][1]))
                else
                    throw(error("Please use \"nucl\" or \"prot\" for seqtype"))
                end
                aln = AlignedSequence(qseq, hseq)
                queryfrom = parse(Int64,content(hsp["query-from"][1]))
                queryto = parse(Int64,content(hsp["query-to"][1]))
                hitfrom = parse(Int64,content(hsp["hit-from"][1]))
                hitto = parse(Int64,content(hsp["hit-to"][1]))
                bitscore = parse(Float64,content(hsp["bit-score"][1]))
                score = parse(Int64,content(hsp["score"][1]))
                expect = parse(Float64,content(hsp["evalue"][1]))
                identity = parse(Int64,content(hsp["identity"][1]))
                gaps = parse(Int64,content(hsp["gaps"][1]))
                push!(results, BLASTResult(bitscore, expect, queryname, hitname,hittaxid, hitid, hitaccession, hitlen, hseq, identity, positive, gaps, queryfrom, queryto, hitfrom, hitto, aln))
            end

        end
    end
    return results
end

"""
    readblastXML(blastrun::AbstractString)
Parse XML output of a blast run. Input is an XML string eg:
```julia
results = read(open("blast_results.xml"), String)
readblastXML(results)
```
Returns Vector{BLASTResult} with the sequence of the hit, the Alignment with query sequence, bitscore and expect value
"""
function readblastXML(blastrun::AbstractString; seqtype="nucl")
    dc = EzXML.parsexml(blastrun)
    rt = EzXML.root(dc)
    results = BLASTResult[]
    for iteration in findall("/BlastOutput/BlastOutput_iterations/Iteration", rt)
        queryname = EzXML.nodecontent(findfirst("Iteration_query-def", iteration))
        for hit in findall("Iteration_hits", iteration)
            if EzXML.countelements(hit) > 0
                hitname = EzXML.nodecontent(findfirst("./Hit/Hit_def", hit))
                hitid = EzXML.nodecontent(findfirst("./Hit/Hit_id", hit))
                hitaccession = EzXML.nodecontent(findfirst("./Hit/Hit_accession", hit))
                hitlen = parse(Int64,EzXML.nodecontent(findfirst("./Hit/Hit_len", hit)))
                hsps_section = EzXML.nodecontent(findfirst("./Hit/Hit_hsps", hit))
                hsps = findall("./Hit/Hit_hsps/Hsp",hit)
                for hsp in hsps
                    if seqtype == "nucl"
                        qseq = LongSequence{DNAAlphabet{4}}(EzXML.nodecontent(findfirst("./Hsp_qseq", hsp)))
                        hseq = LongSequence{DNAAlphabet{4}}(EzXML.nodecontent(findfirst("./Hsp_hseq", hsp)))
                    elseif seqtype == "prot"
                        qseq = LongSequence{AminoAcidAlphabet}(EzXML.nodecontent(findfirst("./Hsp_qseq", hsp)))
                        hseq = LongSequence{AminoAcidAlphabet}(EzXML.nodecontent(findfirst("./Hsp_hseq", hsp)))
                    else
                        throw(error("Please use \"nucl\" or \"prot\" for seqtype"))
                    end
                    aln = AlignedSequence(qseq, hseq)
                    queryfrom = parse(Int64, EzXML.nodecontent(findfirst("./Hsp_query-from", hsp)))
                    queryto = parse(Int64, EzXML.nodecontent(findfirst("./Hsp_query-to", hsp)))
                    hitfrom = parse(Int64, EzXML.nodecontent(findfirst("./Hsp_hit-from", hsp)))
                    hitto = parse(Int64, EzXML.nodecontent(findfirst("./Hsp_hit-to", hsp)))
                    bitscore = parse(Float64, EzXML.nodecontent(findfirst("./Hsp_bit-score", hsp)))
                    expect = parse(Float64, EzXML.nodecontent(findfirst("./Hsp_evalue", hsp)))
                    identity = parse(Int64, EzXML.nodecontent(findfirst("./Hsp_identity", hsp)))
                    positive = parse(Int64, EzXML.nodecontent(findfirst("./Hsp_positive", hsp)))
                    gaps = parse(Int64, EzXML.nodecontent(findfirst("./Hsp_gaps", hsp)))
                    push!(results, BLASTResult(bitscore, expect, queryname,hitname,"0",hitid, hitaccession, hitlen, hseq, identity, positive, gaps, queryfrom, queryto, hitfrom, hitto, aln))
                end
            end
        end
    end
    return results
end

"""
`readblastXML(blastrun::Cmd)`
Parse command line blast query with XML output. Input is the blast command line command, eg:
```julia
blastresults = `blastn -query seq1.fasta -db some_database -outfmt 5`
readblastXML(blastresults)
```
Returns Vector{BLASTResult} with the sequence of the hit, the Alignment with query sequence, bitscore and expect value
"""
function readblastXML(blastrun::Cmd; seqtype="nucl")
    return readblastXML(read(blastrun, String), seqtype=seqtype)
end

"""
`blastn(query, subject, flags...)``
Runs blastn on `query` against `subject`.
    Subjects and queries may be file names (as strings), LongSequence{DNAAlphabet{4}} type or
    Array of LongSequence{DNAAlphabet{4}}.
    May include optional `flag`s such as `["-perc_identity", 95,]`. Do not use `-outfmt`.
"""
function blastn(query::AbstractString, subject::AbstractString, flags=[]; db::Bool=false)
    if db
        results = readblastXML(`blastn -query $query -db $subject $flags -outfmt 5`)
    else
        results = readblastXML(`blastn -query $query -subject $subject $flags -outfmt 5`)
    end
    return results
end

function blastn(query::LongSequence{DNAAlphabet{4}}, subject::LongSequence{DNAAlphabet{4}}, flags=[])
    querypath, subjectpath = makefasta(query), makefasta(subject)
    return blastn(querypath, subjectpath, flags)
end

function blastn(query::LongSequence{DNAAlphabet{4}}, subject::Vector{LongSequence{DNAAlphabet{4}}}, flags=[])
    querypath, subjectpath = makefasta(query), makefasta(subject)
    blastn(querypath, subjectpath, flags)
end

function blastn(query::LongSequence{DNAAlphabet{4}}, subject::AbstractString, flags=[]; db::Bool=false)
    querypath = makefasta(query)
    if db
        return blastn(querypath, subject, flags, db=true)
    else
        return blastn(querypath, subject, flags)
    end
end

function blastn(query::Vector{LongSequence{DNAAlphabet{4}}}, subject::Vector{LongSequence{DNAAlphabet{4}}}, flags=[])
    querypath, subjectpath = makefasta(query), makefasta(subject)
    return blastn(querypath, subjectpath, flags)
end

function blastn(query::Vector{LongSequence{DNAAlphabet{4}}}, subject::AbstractString, flags=[]; db::Bool=false)
    querypath = makefasta(query)
    if db
        return blastn(querypath, subject, flags, db=true)
    else
        return blastn(querypath, subject, flags)
    end
end

function blastn(query::AbstractString, subject::Vector{LongSequence{DNAAlphabet{4}}}, flags=[])
    subjectpath = makefasta(subject)
    return blastn(query, subjectpath, flags)
end

"""
`blastp(query, subject, flags...)``
Runs blastn on `query` against `subject`.
    Subjects and queries may be file names (as strings), `BioSequence{LongSequence{AminoAcidAlphabet}}` type or
    Array of `BioSequence{LongSequence{AminoAcidAlphabet}}`.
    May include optional `flag`s such as `["-perc_identity", 95,]`. Do not use `-outfmt`.
"""
function blastp(query::AbstractString, subject::AbstractString, flags=[]; db::Bool=false)
    if db
        results = readblastXML(`blastp -query $query -db $subject $flags -outfmt 5`, seqtype = "prot")
    else
        results = readblastXML(`blastp -query $query -subject $subject $flags -outfmt 5`, seqtype = "prot")
    end
    return results
end

function blastp(query::LongSequence{AminoAcidAlphabet}, subject::LongSequence{AminoAcidAlphabet}, flags=[])
    querypath, subjectpath = makefasta(query), makefasta(subject)
    return blastp(querypath, subjectpath, flags)
end

function blastp(query::LongSequence{AminoAcidAlphabet}, subject::Vector{LongSequence{AminoAcidAlphabet}}, flags=[])
    querypath, subjectpath = makefasta(query), makefasta(subject)
    return blastp(querypath, subjectpath, flags)
end

function blastp(query::LongSequence{AminoAcidAlphabet}, subject::AbstractString, flags=[]; db::Bool=false)
    querypath = makefasta(query)
    if db
        return blastp(querypath, subject, flags, db=true)
    else
        return blastp(querypath, subject, flags)
    end
end

function blastp(query::Vector{LongSequence{AminoAcidAlphabet}}, subject::Vector{LongSequence{AminoAcidAlphabet}}, flags=[])
    querypath, subjectpath = makefasta(query), makefasta(subject)
    return blastp(querypath, subjectpath, flags)
end

function blastp(query::Vector{LongSequence{AminoAcidAlphabet}}, subject::AbstractString, flags=[]; db::Bool=false)
    querypath = makefasta(query)
    if db
        return blastp(querypath, subject, flags, db=true)
    else
        return blastp(querypath, subject, flags)
    end
end

function blastp(query::AbstractString, subject::Vector{LongSequence{AminoAcidAlphabet}}, flags=[])
    subjectpath = makefasta(subject)
    return blastp(query, subjectpath, flags)
end

# Create temporary fasta-formated file for blasting.
function makefasta(sequence::BioSequence)
    path, io = mktemp()
    write(io, ">$path\n$(convert(String, sequence))\n")
    close(io)
    return path
end

# Create temporary multi fasta-formated file for blasting.
function makefasta(sequences::Vector{T}) where T <: BioSequence
    path, io = mktemp()
    counter = 1
    for sequence in sequences
        write(io, ">$path$counter\n$(convert(String, sequence))\n")
        counter += 1
    end
    close(io)
    return path
end


text:
"""
    AbstractCandidate

Abstract base type for candidates
"""
abstract type AbstractCandidate end

"""
    AbstractFitness

Abstract type for fitness functions
"""
abstract type AbstractFitness end

Base.Broadcast.broadcastable(c::AbstractCandidate) = Ref(c)

release!(::AbstractCandidate) = nothing
hold!(::AbstractCandidate) = nothing

"""
    model(c::AbstractCandidate; [default])

Return the model of candidate `c` if `c` has a model, `default` (which defaults to `nothing`) otherwise.
"""
model(::AbstractCandidate; default=nothing) = default

"""
    model(f, c::AbstractCandidate; [default])

Return the result of `f(`[`model(c; default)`]`)`.
"""
model(f, c::AbstractCandidate; kwargs...) = f(model(c; kwargs...))

"""
    opt(c::AbstractCandidate; [default])

Return the optimizer of candidate `c` if `c` has an optimizer, `default` (which defaults to `nothing`) otherwise.
"""
opt(::AbstractCandidate; default=nothing) = default

"""
    lossfun(c::AbstractCandidate; [default])

Return the loss function of candidate `c` if `c` has a lossfunction, `default` (which defaults to `nothing`) otherwise.
"""
lossfun(::AbstractCandidate; default=nothing) = default
fitness(::AbstractCandidate; default=nothing) = default
generation(::AbstractCandidate; default=nothing) = default

wrappedcand(::T) where T <: AbstractCandidate = error("$T does not wrap any candidate! Check your base case!")

"""
    AbstractWrappingCandidate <: AbstractCandidate

Abstract base type for candidates which wrap other candidates.

Should implement `wrappedcand(c)` to get lots of stuff handled automatically.
"""
abstract type AbstractWrappingCandidate <: AbstractCandidate end

wrappedcand(c::AbstractWrappingCandidate) = c.c

release!(c::AbstractWrappingCandidate) = release!(wrappedcand(c))
hold!(c::AbstractWrappingCandidate) = hold!(wrappedcand(c))

model(c::AbstractWrappingCandidate) = model(wrappedcand(c))
# This is mainly for FileCandidate to allow for writing the graph back to disk after f is done
model(f, c::AbstractWrappingCandidate; kwargs...) = model(f, wrappedcand(c); kwargs...)
opt(c::AbstractWrappingCandidate; kwargs...) = opt(wrappedcand(c); kwargs...)
lossfun(c::AbstractWrappingCandidate; kwargs...) = lossfun(wrappedcand(c); kwargs...)
fitness(c::AbstractWrappingCandidate; kwargs...) = fitness(wrappedcand(c); kwargs...)
generation(c::AbstractWrappingCandidate; kwargs...) = generation(wrappedcand(c); kwargs...)

"""
    CandidateModel <: Candidate
    CandidateModel(model)

A candidate model which can be accessed by [`model(c)`](@ref) for `CandidateModel c`.
"""
struct CandidateModel{G} <: AbstractCandidate
    model::G
end

@functor CandidateModel

model(c::CandidateModel; kwargs...) = c.model

newcand(c::CandidateModel, mapfield) = CandidateModel(map(mapfield, getproperty.(c, fieldnames(CandidateModel)))...)

"""
    CandidateOptModel <: AbstractCandidate
    CandidateOptModel(candidate::AbstractCandidate, optimizer)

A candidate adding an optimizer to another candidate. The optimizer is accessed by [`opt(c)`] for `CandidateOptModel c`.
"""
struct CandidateOptModel{O, C <: AbstractCandidate} <: AbstractWrappingCandidate
    opt::O
    c::C
end
CandidateOptModel(opt, g::CompGraph) = CandidateOptModel(opt, CandidateModel(g))

function Functors.functor(::Type{<:CandidateOptModel}, c)
    return (opt=c.opt, c=c.c), function ((newopt, newc),)
        # Optimizers are stateful and having multiple candidates pointing to the same instance is downright scary
        # User would need to go out of its way to make it the same instance (e.g. by using a wrapper type and dispatch on it in CandidateOptModel)
        # Hope that we get stateless optimizers soon
        if newopt === c.opt
            newopt = deepcopy(cleanopt!(newopt))
        end
        CandidateOptModel(newopt, newc)
    end
end

opt(c::CandidateOptModel; kwargs...) = c.opt

newcand(c::CandidateOptModel, mapfield) = CandidateOptModel(mapfield(c.opt), newcand(wrappedcand(c), mapfield))

"""
    FileCandidate <: AbstractWrappingCandidate
    FileCandidate(c::AbstractCandidate)

Keeps `c` on disk when not in use and just maintains its [`DRef`](@ref).

Experimental feature. May not work as intended!
"""
mutable struct FileCandidate{C, R<:Real, L<:Base.AbstractLock} <: AbstractWrappingCandidate
    c::MemPool.DRef
    movedelay::R
    movetimer::Timer
    writelock::L
    hold::Bool
    function FileCandidate(c::C, movedelay::R, hold=false) where {C, R}
        cref = MemPool.poolset(c)
        writelock = ReentrantLock()
        movetimer = hold ? asynctodisk(cref, movedelay, writelock) : Timer(movedelay)
        fc = new{C, R, typeof(writelock)}(cref, movedelay, movetimer, writelock, hold)
        finalizer(gfc -> MemPool.pooldelete(gfc.c), fc)
        return fc
     end
end
FileCandidate(c::AbstractCandidate) = FileCandidate(c, 0.5)

function callcand(f, c::FileCandidate, args...; kwargs...)
    # If timer is running we just stop and restart
    close(c.movetimer)

    # writelock means that the candidate is being moved to disk. We need to wait for it or risk data corruption
    islocked(c.writelock) && @warn "Try to access FileCandidate which is being moved to disk. Consider retuning of movedelay!"
    ret= lock(c.writelock) do
        f(MemPool.poolget(c.c), args...; kwargs...)
    end
    if !c.hold
        c.movetimer = asynctodisk(c.c, c.movedelay, c.writelock)
    end
    return ret
end

candinmem(c::FileCandidate) = candinmem(c.c)
candinmem(r::MemPool.DRef) =  MemPool.with_datastore_lock() do
    haskey(MemPool.datastore, r.id) && MemPool.isinmemory(MemPool.datastore[r.id])
end

function asynctodisk(r::MemPool.DRef, delay, writelock)
    return Timer(delay) do _
        candtodisk(r, writelock)
    end
end
# Function exists outside of timer for testing purposes basically
function candtodisk(r::MemPool.DRef, writelock)
    lock(writelock) do
        # Not sure why this can even happen, but it does. Bug lurking...
        candinmem(r) || return
        # Remove file if it exists or else MemPool won't move it
        rm(MemPool.default_path(r); force=true)
        MemPool.movetodisk(r)
    end
end

function release!(c::FileCandidate)
    c.hold = false
    release!(wrappedcand(c))
    close(c.movetimer)
    c.movetimer = asynctodisk(c.c, c.movedelay, c.writelock)
    return nothing
end

# wrappedcand will do the work for us to actually hold
hold!(c::FileCandidate) = hold!(wrappedcand(c))

function Serialization.serialize(s::AbstractSerializer, c::FileCandidate)
    Serialization.writetag(s.io, Serialization.OBJECT_TAG)
    serialize(s, FileCandidate)
    callcand(cc -> serialize(s,cc), c)
end

function Serialization.deserialize(s::AbstractSerializer, ::Type{FileCandidate})
    wrapped = deserialize(s)
    return FileCandidate(wrapped)
end

function Functors.functor(::Type{<:FileCandidate}, c)
    # we can allow the wrapped candidate to be moved to disk while user decides what to do with the
    return (c=callcand(identity, c), movedelay=c.movedelay), function(xs)
        FileCandidate(xs..., c.hold)
    end
end

function wrappedcand(c::FileCandidate)
    c.hold = true
    callcand(identity, c)
end
# Could also implement getproperty using wrappedcand/callcand, but there is no need for it so not gonna bother now

model(f, c::FileCandidate; kwargs...) = callcand(c) do cand
    model(f, cand; kwargs...)
end

newcand(c::FileCandidate, mapfield) = FileCandidate(callcand(newcand, c, mapfield), c.movedelay)

"""
    FittedCandidate{F, C} <: AbstractWrappingCandidate
    FittedCandidate(c::AbstractCandidate, fitnessvalue, generation)
    FittedCandidate(c::AbstractCandidate, fitnessfun::AbstractFitness, generation)

An `AbstractCandidate` with a computed fitness value. Will compute the fitness value if provided an `AbstractFitness`.

Basically a container for results so that fitness does not need to be recomputed to e.g. check stopping conditions.

Also useful for fitness smoothing, e.g. with `EwmaFitness` as it gives access to previous fitness value.
"""
struct FittedCandidate{F, C <: AbstractCandidate} <: AbstractWrappingCandidate
    gen::Int
    fitness::F
    c::C
end
FittedCandidate(c::AbstractCandidate, f::AbstractFitness, gen) = FittedCandidate(gen, fitness(f, c), c)
FittedCandidate(c::FittedCandidate, f::AbstractFitness, gen) = FittedCandidate(gen, fitness(f, c), wrappedcand(c))

@functor FittedCandidate

fitness(c::FittedCandidate; default=nothing) = c.fitness
generation(c::FittedCandidate; default=nothing) = c.gen

# Some fitness functions make use of gen and fitness value :/
# This is a bit of an ugly inconsistency that I hope to fix one day is it is not beautiful that the fitness of a
# new candidate is that same as its ancestor. It is the wanted behaviour for e.g. EwmaFitness though and
# as of version 0.8.0 fitness does not longer carry any state.
# Maybe I need to come up with a mechanism for that. As of now, alot of fitness strategies will not work properly
# if they are not passed a FittedCandidate. Perhaps having some kind of fitness state container in each candidate?
newcand(c::FittedCandidate, mapfield) = FittedCandidate(c.gen, c.fitness, newcand(wrappedcand(c), mapfield))

nparams(c::AbstractCandidate) = model(nparams, c)
nparams(x) = mapreduce(prod ∘ size, +, params(x).order; init=0)

"""
    evolvemodel(m::AbstractMutation{CompGraph}, mapothers=deepcopy)
    evolvemodel(m::AbstractMutation{CompGraph}, om::AbstractMutation{FluxOptimizer}, mapothers=deepcopy)

Return a function which maps a `AbstractCandidate c1` to a new `AbstractCandidate c2` where any `CompGraph`s `g` in `c1` will be m(deepcopy(g))` in `c2`. Same principle is applied to any optimisers if `om` is present.

All other fields are mapped through the function `mapothers` (default `deepcopy`).

Intended use is together with [`EvolveCandidates`](@ref).
"""
function evolvemodel(m::AbstractMutation{CompGraph}, mapothers=deepcopy)
    function copymutate(g::CompGraph)
        ng = deepcopy(g)
        m(ng)
        return ng
    end
    mapcandidate(copymutate, mapothers)
end
evolvemodel(m::AbstractMutation{CompGraph}, om::AbstractMutation{FluxOptimizer}, mapothers=deepcopy) = evolvemodel(m, optmap(om, mapothers))

"""
    evolvemodel(m::AbstractCrossover{CompGraph}, mapothers1=deepcopy, mapothers2=deepcopy)
    evolvemodel(m::AbstractCrossover{CompGraph}, om::AbstractCrossover{FluxOptimizer}, mapothers1=deepcopy, mapothers2=deepcopy)

Return a function which maps a tuple of `AbstractCandidate`s `(c1,c2)` to two new candidates `c1', c2'` where any `CompGraph`s `g1` and `g2` in `c1` and `c2` respectively will be `g1', g2' = m((deepcopy(g1), deepcopy(g2)))` in `c1'` and `c2'` respectively. Same principle applies to any optimisers if `om` is present.

All other fields in `c1` will be mapped through the function `mapothers1` and likewise for `c2` and `mapothers2`.

Intended use is together with [`PairCandidates`](@ref) and [`EvolveCandidates`](@ref).
"""
evolvemodel(m::AbstractCrossover{CompGraph}, mapothers1=deepcopy, mapothers2=deepcopy) = (c1, c2)::Tuple -> begin
    # This allows FileCandidate to write the graph back to disk as we don't want to mutate the orignal candidate.
    # Perhaps align single individual mutation to this pattern for consistency?
    g1 = model(c1)
    g2 = model(c2)

    release!(c1)
    release!(c2)

    g1, g2 = m((deepcopy(g1), deepcopy(g2)))

    return mapcandidate(g -> g1, mapothers1)(c1), mapcandidate(g -> g2, mapothers2)(c2)
end

evolvemodel(m::AbstractCrossover{CompGraph}, om::AbstractCrossover{FluxOptimizer}, mapothers1=deepcopy, mapothers2=deepcopy) = (c1,c2)::Tuple -> begin
    o1 = opt(c1)
    o2 = opt(c2)

    o1n, o2n = om((o1, o2))

    return evolvemodel(m, optmap(o -> o1n, mapothers1), optmap(o -> o2n, mapothers2))((c1,c2))
end

function mapcandidate(mapgraph, mapothers=deepcopy)
    mapfield(g::CompGraph) = mapgraph(g)
    mapfield(f) = mapothers(f)
    # TODO: Replace with fmap now that we fully support Functors?
    return c -> newcand(c, mapfield)
end

"""
    randomlrscale(rfun = BoundedRandomWalk(-1.0, 1.0))

Return a function which scales the learning rate based on the output of `rfun`.

Intended use is to apply the same learning rate scaling for a whole population of models, e.g to have a global learning rate schedule.
"""
randomlrscale(rfun = BoundedRandomWalk(-1.0, 1.0)) = function(x...)
    newopt = ShieldedOpt(Flux.Descent(10^rfun(x...)))
    return AddOptimizerMutation(o -> newopt)
end

"""
    global_optimizer_mutation(pop, optfun)

Changes the optimizer of all candidates in `pop`.

The optimizer of each candidate in pop will be changed to `om(optc)` where `optc` is the current optimizer and `om = optfun(pop)`.

Intended to be used with `AfterEvolution` to create things like global learning rate schedules.

See `https://github.com/DrChainsaw/NaiveGAExperiments/blob/master/lamarckism/experiments.ipynb` for some hints as to why this might be needed.
"""
function global_optimizer_mutation(pop, optfun)
    om = optfun(pop)
    map(c -> newcand(c, optmap(om)), pop)
end


text:
# Automatically generated using Clang.jl wrap_c, version 0.0.0
@static if VERSION < v"0.7-"
  using Compat: Nothing
end

const OBJC_NEW_PROPERTIES = 1

# Skipping MacroDefinition: NULL ( ( void * ) 0 )
# Skipping MacroDefinition: offsetof ( t , d ) __builtin_offsetof ( t , d )

# Skipping MacroDefinition: INT8_C ( v ) ( v )
# Skipping MacroDefinition: INT16_C ( v ) ( v )
# Skipping MacroDefinition: INT32_C ( v ) ( v )
# Skipping MacroDefinition: INT64_C ( v ) ( v ## LL )
# Skipping MacroDefinition: UINT8_C ( v ) ( v ## U )
# Skipping MacroDefinition: UINT16_C ( v ) ( v ## U )
# Skipping MacroDefinition: UINT32_C ( v ) ( v ## U )
# Skipping MacroDefinition: UINT64_C ( v ) ( v ## ULL )
# Skipping MacroDefinition: INTMAX_C ( v ) ( v ## L )
# Skipping MacroDefinition: UINTMAX_C ( v ) ( v ## UL )

const uiPi = 3.141592653589793

# Skipping MacroDefinition: uiControl ( this ) ( ( uiControl * ) ( this ) )
# Skipping MacroDefinition: uiWindow ( this ) ( ( uiWindow * ) ( this ) )
# Skipping MacroDefinition: uiButton ( this ) ( ( uiButton * ) ( this ) )
# Skipping MacroDefinition: uiBox ( this ) ( ( uiBox * ) ( this ) )
# Skipping MacroDefinition: uiCheckbox ( this ) ( ( uiCheckbox * ) ( this ) )
# Skipping MacroDefinition: uiEntry ( this ) ( ( uiEntry * ) ( this ) )
# Skipping MacroDefinition: uiLabel ( this ) ( ( uiLabel * ) ( this ) )
# Skipping MacroDefinition: uiTab ( this ) ( ( uiTab * ) ( this ) )
# Skipping MacroDefinition: uiGroup ( this ) ( ( uiGroup * ) ( this ) )
# Skipping MacroDefinition: uiSpinbox ( this ) ( ( uiSpinbox * ) ( this ) )
# Skipping MacroDefinition: uiSlider ( this ) ( ( uiSlider * ) ( this ) )
# Skipping MacroDefinition: uiProgressBar ( this ) ( ( uiProgressBar * ) ( this ) )
# Skipping MacroDefinition: uiSeparator ( this ) ( ( uiSeparator * ) ( this ) )
# Skipping MacroDefinition: uiCombobox ( this ) ( ( uiCombobox * ) ( this ) )
# Skipping MacroDefinition: uiEditableCombobox ( this ) ( ( uiEditableCombobox * ) ( this ) )
# Skipping MacroDefinition: uiRadioButtons ( this ) ( ( uiRadioButtons * ) ( this ) )
# Skipping MacroDefinition: uiDateTimePicker ( this ) ( ( uiDateTimePicker * ) ( this ) )
# Skipping MacroDefinition: uiMultilineEntry ( this ) ( ( uiMultilineEntry * ) ( this ) )
# Skipping MacroDefinition: uiMenuItem ( this ) ( ( uiMenuItem * ) ( this ) )
# Skipping MacroDefinition: uiMenu ( this ) ( ( uiMenu * ) ( this ) )
# Skipping MacroDefinition: uiArea ( this ) ( ( uiArea * ) ( this ) )

const uiDrawDefaultMiterLimit = 10.0

# Skipping MacroDefinition: uiFontButton ( this ) ( ( uiFontButton * ) ( this ) )
# Skipping MacroDefinition: uiColorButton ( this ) ( ( uiColorButton * ) ( this ) )
# Skipping MacroDefinition: uiForm ( this ) ( ( uiForm * ) ( this ) )
# Skipping MacroDefinition: uiGrid ( this ) ( ( uiGrid * ) ( this ) )

const uiTableModelColumnNeverEditable = -1
const uiTableModelColumnAlwaysEditable = -2

# Skipping MacroDefinition: uiTable ( this ) ( ( uiTable * ) ( this ) )

const uiForEach = UInt32

# begin enum ANONYMOUS_1
const ANONYMOUS_1 = UInt32
const uiForEachContinue = (UInt32)(0)
const uiForEachStop = (UInt32)(1)
# end enum ANONYMOUS_1

mutable struct uiInitOptions
	Size::Csize_t
end

mutable struct uiControl
	Signature::UInt32
	OSSignature::UInt32
	TypeSignature::UInt32
	Destroy::Ptr{Nothing}
	Handle::Ptr{Nothing}
	Parent::Ptr{Nothing}
	SetParent::Ptr{Nothing}
	Toplevel::Ptr{Nothing}
	Visible::Ptr{Nothing}
	Show::Ptr{Nothing}
	Hide::Ptr{Nothing}
	Enabled::Ptr{Nothing}
	Enable::Ptr{Nothing}
	Disable::Ptr{Nothing}
end

mutable struct uiWindow
end

mutable struct uiButton
end

mutable struct uiBox
end

mutable struct uiCheckbox
end

mutable struct uiEntry
end

mutable struct uiLabel
end

mutable struct uiTab
end

mutable struct uiGroup
end

mutable struct uiSpinbox
end

mutable struct uiSlider
end

mutable struct uiProgressBar
end

mutable struct uiSeparator
end

mutable struct uiCombobox
end

mutable struct uiEditableCombobox
end

mutable struct uiRadioButtons
end

mutable struct tm
end

mutable struct uiDateTimePicker
end

mutable struct uiMultilineEntry
end

mutable struct uiMenuItem
end

mutable struct uiMenu
end

mutable struct uiArea
end

mutable struct uiAreaHandler
	Draw::Ptr{Nothing}
	MouseEvent::Ptr{Nothing}
	MouseCrossed::Ptr{Nothing}
	DragBroken::Ptr{Nothing}
	KeyEvent::Ptr{Nothing}
end

mutable struct uiDrawContext
end

mutable struct uiAreaDrawParams
	Context::Ptr{uiDrawContext}
	AreaWidth::Cdouble
	AreaHeight::Cdouble
	ClipX::Cdouble
	ClipY::Cdouble
	ClipWidth::Cdouble
	ClipHeight::Cdouble
end

const uiModifiers = UInt32

mutable struct uiAreaMouseEvent
	X::Cdouble
	Y::Cdouble
	AreaWidth::Cdouble
	AreaHeight::Cdouble
	Down::Cint
	Up::Cint
	Count::Cint
	Modifiers::uiModifiers
	Held1To64::UInt64
end

const uiExtKey = UInt32

mutable struct uiAreaKeyEvent
	Key::UInt8
	ExtKey::uiExtKey
	Modifier::uiModifiers
	Modifiers::uiModifiers
	Up::Cint
end

const uiWindowResizeEdge = UInt32

# begin enum ANONYMOUS_2
const ANONYMOUS_2 = UInt32
const uiWindowResizeEdgeLeft = (UInt32)(0)
const uiWindowResizeEdgeTop = (UInt32)(1)
const uiWindowResizeEdgeRight = (UInt32)(2)
const uiWindowResizeEdgeBottom = (UInt32)(3)
const uiWindowResizeEdgeTopLeft = (UInt32)(4)
const uiWindowResizeEdgeTopRight = (UInt32)(5)
const uiWindowResizeEdgeBottomLeft = (UInt32)(6)
const uiWindowResizeEdgeBottomRight = (UInt32)(7)
# end enum ANONYMOUS_2

mutable struct uiDrawPath
end

const uiDrawBrushType = UInt32

mutable struct uiDrawBrushGradientStop
	Pos::Cdouble
	R::Cdouble
	G::Cdouble
	B::Cdouble
	A::Cdouble
end

mutable struct uiDrawBrush
	Type::uiDrawBrushType
	R::Cdouble
	G::Cdouble
	B::Cdouble
	A::Cdouble
	X0::Cdouble
	Y0::Cdouble
	X1::Cdouble
	Y1::Cdouble
	OuterRadius::Cdouble
	Stops::Ptr{uiDrawBrushGradientStop}
	NumStops::Csize_t
end

const uiDrawLineCap = UInt32
const uiDrawLineJoin = UInt32

mutable struct uiDrawStrokeParams
	Cap::uiDrawLineCap
	Join::uiDrawLineJoin
	Thickness::Cdouble
	MiterLimit::Cdouble
	Dashes::Ptr{Cdouble}
	NumDashes::Csize_t
	DashPhase::Cdouble
end

mutable struct uiDrawMatrix
	M11::Cdouble
	M12::Cdouble
	M21::Cdouble
	M22::Cdouble
	M31::Cdouble
	M32::Cdouble
end

# begin enum ANONYMOUS_3
const ANONYMOUS_3 = UInt32
const uiDrawBrushTypeSolid = (UInt32)(0)
const uiDrawBrushTypeLinearGradient = (UInt32)(1)
const uiDrawBrushTypeRadialGradient = (UInt32)(2)
const uiDrawBrushTypeImage = (UInt32)(3)
# end enum ANONYMOUS_3

# begin enum ANONYMOUS_4
const ANONYMOUS_4 = UInt32
const uiDrawLineCapFlat = (UInt32)(0)
const uiDrawLineCapRound = (UInt32)(1)
const uiDrawLineCapSquare = (UInt32)(2)
# end enum ANONYMOUS_4

# begin enum ANONYMOUS_5
const ANONYMOUS_5 = UInt32
const uiDrawLineJoinMiter = (UInt32)(0)
const uiDrawLineJoinRound = (UInt32)(1)
const uiDrawLineJoinBevel = (UInt32)(2)
# end enum ANONYMOUS_5

const uiDrawFillMode = UInt32

# begin enum ANONYMOUS_6
const ANONYMOUS_6 = UInt32
const uiDrawFillModeWinding = (UInt32)(0)
const uiDrawFillModeAlternate = (UInt32)(1)
# end enum ANONYMOUS_6

mutable struct uiAttribute
end

const uiAttributeType = UInt32

# begin enum ANONYMOUS_7
const ANONYMOUS_7 = UInt32
const uiAttributeTypeFamily = (UInt32)(0)
const uiAttributeTypeSize = (UInt32)(1)
const uiAttributeTypeWeight = (UInt32)(2)
const uiAttributeTypeItalic = (UInt32)(3)
const uiAttributeTypeStretch = (UInt32)(4)
const uiAttributeTypeColor = (UInt32)(5)
const uiAttributeTypeBackground = (UInt32)(6)
const uiAttributeTypeUnderline = (UInt32)(7)
const uiAttributeTypeUnderlineColor = (UInt32)(8)
const uiAttributeTypeFeatures = (UInt32)(9)
# end enum ANONYMOUS_7

const uiTextWeight = UInt32

# begin enum ANONYMOUS_8
const ANONYMOUS_8 = UInt32
const uiTextWeightMinimum = (UInt32)(0)
const uiTextWeightThin = (UInt32)(100)
const uiTextWeightUltraLight = (UInt32)(200)
const uiTextWeightLight = (UInt32)(300)
const uiTextWeightBook = (UInt32)(350)
const uiTextWeightNormal = (UInt32)(400)
const uiTextWeightMedium = (UInt32)(500)
const uiTextWeightSemiBold = (UInt32)(600)
const uiTextWeightBold = (UInt32)(700)
const uiTextWeightUltraBold = (UInt32)(800)
const uiTextWeightHeavy = (UInt32)(900)
const uiTextWeightUltraHeavy = (UInt32)(950)
const uiTextWeightMaximum = (UInt32)(1000)
# end enum ANONYMOUS_8

const uiTextItalic = UInt32

# begin enum ANONYMOUS_9
const ANONYMOUS_9 = UInt32
const uiTextItalicNormal = (UInt32)(0)
const uiTextItalicOblique = (UInt32)(1)
const uiTextItalicItalic = (UInt32)(2)
# end enum ANONYMOUS_9

const uiTextStretch = UInt32

# begin enum ANONYMOUS_10
const ANONYMOUS_10 = UInt32
const uiTextStretchUltraCondensed = (UInt32)(0)
const uiTextStretchExtraCondensed = (UInt32)(1)
const uiTextStretchCondensed = (UInt32)(2)
const uiTextStretchSemiCondensed = (UInt32)(3)
const uiTextStretchNormal = (UInt32)(4)
const uiTextStretchSemiExpanded = (UInt32)(5)
const uiTextStretchExpanded = (UInt32)(6)
const uiTextStretchExtraExpanded = (UInt32)(7)
const uiTextStretchUltraExpanded = (UInt32)(8)
# end enum ANONYMOUS_10

const uiUnderline = UInt32

# begin enum ANONYMOUS_11
const ANONYMOUS_11 = UInt32
const uiUnderlineNone = (UInt32)(0)
const uiUnderlineSingle = (UInt32)(1)
const uiUnderlineDouble = (UInt32)(2)
const uiUnderlineSuggestion = (UInt32)(3)
# end enum ANONYMOUS_11

const uiUnderlineColor = UInt32

# begin enum ANONYMOUS_12
const ANONYMOUS_12 = UInt32
const uiUnderlineColorCustom = (UInt32)(0)
const uiUnderlineColorSpelling = (UInt32)(1)
const uiUnderlineColorGrammar = (UInt32)(2)
const uiUnderlineColorAuxiliary = (UInt32)(3)
# end enum ANONYMOUS_12

mutable struct uiOpenTypeFeatures
end

const uiOpenTypeFeaturesForEachFunc = Ptr{Nothing}

mutable struct uiAttributedString
end

const uiAttributedStringForEachAttributeFunc = Ptr{Nothing}

mutable struct uiFontDescriptor
	Family::Cstring
	Size::Cdouble
	Weight::uiTextWeight
	Italic::uiTextItalic
	Stretch::uiTextStretch
end

mutable struct uiDrawTextLayout
end

const uiDrawTextAlign = UInt32

# begin enum ANONYMOUS_13
const ANONYMOUS_13 = UInt32
const uiDrawTextAlignLeft = (UInt32)(0)
const uiDrawTextAlignCenter = (UInt32)(1)
const uiDrawTextAlignRight = (UInt32)(2)
# end enum ANONYMOUS_13

mutable struct uiDrawTextLayoutParams
	String::Ptr{uiAttributedString}
	DefaultFont::Ptr{uiFontDescriptor}
	Width::Cdouble
	Align::uiDrawTextAlign
end

mutable struct uiFontButton
end

# begin enum ANONYMOUS_14
const ANONYMOUS_14 = UInt32
const uiModifierCtrl = (UInt32)(1)
const uiModifierAlt = (UInt32)(2)
const uiModifierShift = (UInt32)(4)
const uiModifierSuper = (UInt32)(8)
# end enum ANONYMOUS_14

# begin enum ANONYMOUS_15
const ANONYMOUS_15 = UInt32
const uiExtKeyEscape = (UInt32)(1)
const uiExtKeyInsert = (UInt32)(2)
const uiExtKeyDelete = (UInt32)(3)
const uiExtKeyHome = (UInt32)(4)
const uiExtKeyEnd = (UInt32)(5)
const uiExtKeyPageUp = (UInt32)(6)
const uiExtKeyPageDown = (UInt32)(7)
const uiExtKeyUp = (UInt32)(8)
const uiExtKeyDown = (UInt32)(9)
const uiExtKeyLeft = (UInt32)(10)
const uiExtKeyRight = (UInt32)(11)
const uiExtKeyF1 = (UInt32)(12)
const uiExtKeyF2 = (UInt32)(13)
const uiExtKeyF3 = (UInt32)(14)
const uiExtKeyF4 = (UInt32)(15)
const uiExtKeyF5 = (UInt32)(16)
const uiExtKeyF6 = (UInt32)(17)
const uiExtKeyF7 = (UInt32)(18)
const uiExtKeyF8 = (UInt32)(19)
const uiExtKeyF9 = (UInt32)(20)
const uiExtKeyF10 = (UInt32)(21)
const uiExtKeyF11 = (UInt32)(22)
const uiExtKeyF12 = (UInt32)(23)
const uiExtKeyN0 = (UInt32)(24)
const uiExtKeyN1 = (UInt32)(25)
const uiExtKeyN2 = (UInt32)(26)
const uiExtKeyN3 = (UInt32)(27)
const uiExtKeyN4 = (UInt32)(28)
const uiExtKeyN5 = (UInt32)(29)
const uiExtKeyN6 = (UInt32)(30)
const uiExtKeyN7 = (UInt32)(31)
const uiExtKeyN8 = (UInt32)(32)
const uiExtKeyN9 = (UInt32)(33)
const uiExtKeyNDot = (UInt32)(34)
const uiExtKeyNEnter = (UInt32)(35)
const uiExtKeyNAdd = (UInt32)(36)
const uiExtKeyNSubtract = (UInt32)(37)
const uiExtKeyNMultiply = (UInt32)(38)
const uiExtKeyNDivide = (UInt32)(39)
# end enum ANONYMOUS_15

mutable struct uiColorButton
end

mutable struct uiForm
end

const uiAlign = UInt32

# begin enum ANONYMOUS_16
const ANONYMOUS_16 = UInt32
const uiAlignFill = (UInt32)(0)
const uiAlignStart = (UInt32)(1)
const uiAlignCenter = (UInt32)(2)
const uiAlignEnd = (UInt32)(3)
# end enum ANONYMOUS_16

const uiAt = UInt32

# begin enum ANONYMOUS_17
const ANONYMOUS_17 = UInt32
const uiAtLeading = (UInt32)(0)
const uiAtTop = (UInt32)(1)
const uiAtTrailing = (UInt32)(2)
const uiAtBottom = (UInt32)(3)
# end enum ANONYMOUS_17

mutable struct uiGrid
end

mutable struct uiImage
end

mutable struct uiTableValue
end

const uiTableValueType = UInt32

# begin enum ANONYMOUS_18
const ANONYMOUS_18 = UInt32
const uiTableValueTypeString = (UInt32)(0)
const uiTableValueTypeImage = (UInt32)(1)
const uiTableValueTypeInt = (UInt32)(2)
const uiTableValueTypeColor = (UInt32)(3)
# end enum ANONYMOUS_18

mutable struct uiTableModel
end

mutable struct uiTableModelHandler
	NumColumns::Ptr{Nothing}
	ColumnType::Ptr{Nothing}
	NumRows::Ptr{Nothing}
	CellValue::Ptr{Nothing}
	SetCellValue::Ptr{Nothing}
end

mutable struct uiTableTextColumnOptionalParams
	ColorModelColumn::Cint
end

mutable struct uiTableParams
	Model::Ptr{uiTableModel}
	RowBackgroundColorModelColumn::Cint
end

mutable struct uiTable
end


text:
@doc raw"""
    LinearScalarAdvectionEquation2D

The linear scalar advection equation
```math
\partial_t u + a_1 \partial_1 u + a_2 \partial_2 u = 0
```
in two space dimensions with constant velocity `a`.
"""
struct LinearScalarAdvectionEquation2D <: AbstractLinearScalarAdvectionEquation{2, 1}
  sources::String
  advectionvelocity::SVector{2, Float64}
end

function LinearScalarAdvectionEquation2D()
  sources = parameter("sources", "none")
  a = convert(SVector{2,Float64}, parameter("advectionvelocity"))
  LinearScalarAdvectionEquation2D(sources, a)
end

get_name(::LinearScalarAdvectionEquation2D) = "LinearScalarAdvectionEquation2D"
varnames_cons(::LinearScalarAdvectionEquation2D) = SVector("scalar")
varnames_prim(::LinearScalarAdvectionEquation2D) = SVector("scalar")

# Set initial conditions at physical location `x` for time `t`
function initial_conditions_gauss(x, t, equation::LinearScalarAdvectionEquation2D)
  # Store translated coordinate for easy use of exact solution
  x_trans = x - equation.advectionvelocity * t

  return @SVector [exp(-(x_trans[1]^2 + x_trans[2]^2))]
end

function initial_conditions_convergence_test(x, t, equation::LinearScalarAdvectionEquation2D)
  # Store translated coordinate for easy use of exact solution
  x_trans = x - equation.advectionvelocity * t

  c = 1.0
  A = 0.5
  L = 2
  f = 1/L
  omega = 2 * pi * f
  scalar = c + A * sin(omega * sum(x_trans))
  return @SVector [scalar]
end

function initial_conditions_sin_sin(x, t, equation::LinearScalarAdvectionEquation2D)
  # Store translated coordinate for easy use of exact solution
  x_trans = x - equation.advectionvelocity * t

  scalar = sin(2 * pi * x_trans[1]) * sin(2 * pi * x_trans[2])
  return @SVector [scalar]
end

function initial_conditions_constant(x, t, equation::LinearScalarAdvectionEquation2D)
  # Store translated coordinate for easy use of exact solution
  x_trans = x - equation.advectionvelocity * t

  return @SVector [2.0]
end

function initial_conditions_linear_x_y(x, t, equation::LinearScalarAdvectionEquation2D)
  # Store translated coordinate for easy use of exact solution
  x_trans = x - equation.advectionvelocity * t

  return @SVector [sum(x_trans)]
end

function initial_conditions_linear_x(x, t, equation::LinearScalarAdvectionEquation2D)
  # Store translated coordinate for easy use of exact solution
  x_trans = x - equation.advectionvelocity * t

  return @SVector [x_trans[1]]
end

function initial_conditions_linear_y(x, t, equation::LinearScalarAdvectionEquation2D)
  # Store translated coordinate for easy use of exact solution
  x_trans = x - equation.advectionvelocity * t

  return @SVector [x_trans[2]]
end

# Apply boundary conditions
function boundary_conditions_gauss(u_inner, orientation, direction, x, t, surface_flux_function,
                                   equation::LinearScalarAdvectionEquation2D)
  u_boundary = initial_conditions_gauss(x, t, equation)

  # Calculate boundary flux
  if direction in (2, 4) # u_inner is "left" of boundary, u_boundary is "right" of boundary
    flux = surface_flux_function(u_inner, u_boundary, orientation, equation)
  else # u_boundary is "left" of boundary, u_inner is "right" of boundary
    flux = surface_flux_function(u_boundary, u_inner, orientation, equation)
  end

  return flux
end

function boundary_conditions_linear_x_y(u_inner, orientation, direction, x, t,
                                              surface_flux_function,
                                              equation::LinearScalarAdvectionEquation2D)
  u_boundary = initial_conditions_linear_x_y(x, t, equation)

  # Calculate boundary flux
  if direction in (2, 4) # u_inner is "left" of boundary, u_boundary is "right" of boundary
    flux = surface_flux_function(u_inner, u_boundary, orientation, equation)
  else # u_boundary is "left" of boundary, u_inner is "right" of boundary
    flux = surface_flux_function(u_boundary, u_inner, orientation, equation)
  end

  return flux
end

function boundary_conditions_linear_x(u_inner, orientation, direction, x, t,
                                              surface_flux_function,
                                              equation::LinearScalarAdvectionEquation2D)
  u_boundary = initial_conditions_linear_x(x, t, equation)

  # Calculate boundary flux
  if direction in (2, 4) # u_inner is "left" of boundary, u_boundary is "right" of boundary
    flux = surface_flux_function(u_inner, u_boundary, orientation, equation)
  else # u_boundary is "left" of boundary, u_inner is "right" of boundary
    flux = surface_flux_function(u_boundary, u_inner, orientation, equation)
  end

  return flux
end

function boundary_conditions_linear_y(u_inner, orientation, direction, x, t,
                                              surface_flux_function,
                                              equation::LinearScalarAdvectionEquation2D)
  u_boundary = initial_conditions_linear_y(x, t, equation)

  # Calculate boundary flux
  if direction in (2, 4) # u_inner is "left" of boundary, u_boundary is "right" of boundary
    flux = surface_flux_function(u_inner, u_boundary, orientation, equation)
  else # u_boundary is "left" of boundary, u_inner is "right" of boundary
    flux = surface_flux_function(u_boundary, u_inner, orientation, equation)
  end

  return flux
end

# Pre-defined source terms should be implemented as
# function source_terms_WHATEVER(ut, u, x, element_id, t, n_nodes, equation::LinearScalarAdvectionEquation2D)

# Calculate 1D flux in for a single point
@inline function calcflux(u, orientation, equation::LinearScalarAdvectionEquation2D)
  a = equation.advectionvelocity[orientation]
  return a * u
end

function flux_lax_friedrichs(u_ll, u_rr, orientation, equation::LinearScalarAdvectionEquation2D)
  a = equation.advectionvelocity[orientation]
  return 0.5 * ( a * (u_ll + u_rr) - abs(a) * (u_rr - u_ll) )
end

# Determine maximum stable time step based on polynomial degree and CFL number
function calc_max_dt(u, element_id, invjacobian, cfl,
                     equation::LinearScalarAdvectionEquation2D, dg)
  λ_max = maximum(abs, equation.advectionvelocity)
  return cfl * 2 / (nnodes(dg) * invjacobian * λ_max)
end

# Convert conservative variables to primitive
@inline cons2prim(u, equation::LinearScalarAdvectionEquation2D) = u

# Convert conservative variables to entropy variables
@inline cons2entropy(u, equation::LinearScalarAdvectionEquation2D) = u

# Calculate entropy for a conservative state `cons`
@inline entropy(u::Real, ::LinearScalarAdvectionEquation2D) = 0.5 * u^2
@inline entropy(u, equation::LinearScalarAdvectionEquation2D) = entropy(u[1], equation)

# Calculate total energy for a conservative state `cons`
@inline energy_total(u::Real, ::LinearScalarAdvectionEquation2D) = 0.5 * u^2
@inline energy_total(u, equation::LinearScalarAdvectionEquation2D) = energy_total(u[1], equation)


text:
import SpecialFunctions
function func_delta(loc_globaldata, loc_ghost_holder, cfl, numPoints)

    # updateLocalGhost(loc_ghost_holder, globaldata)
    dist_length = length(loc_globaldata)
    # reduction = dist_length * (myid() - 2)
    for idx in 1:dist_length
        # TODO - Possible problem?
        # print(" ", idx," ")

        min_delt = one(Float64)
        for itm in loc_globaldata[idx].conn
            if itm <= dist_length
                globaldata_itm = loc_globaldata[itm]
            else
                globaldata_itm = loc_ghost_holder[1][itm]
            end
            x_i = loc_globaldata[idx].x
            y_i = loc_globaldata[idx].y
            x_k = globaldata_itm.x
            y_k = globaldata_itm.y
            dist = hypot((x_k - x_i),(y_k - y_i))
            mod_u = hypot(globaldata_itm.prim[2],globaldata_itm.prim[3])
            delta_t = dist/(mod_u + 3*sqrt(globaldata_itm.prim[4]/globaldata_itm.prim[1]))
            delta_t *= cfl
            if min_delt > delta_t
                min_delt = delta_t
            end
        end
        loc_globaldata[idx].delta = min_delt
        @. loc_globaldata[idx].prim_old = loc_globaldata[idx].prim
    end
    return nothing
end

function state_update(loc_globaldata, loc_globaldata_mutable, Mach, gamma, pr_inf, rho_inf, theta, iter, res_old, res_new, rk, numPoints)
    max_res = zero(Float64)
    sum_res_sqr = zeros(Float64, 1)
    U = zeros(Float64, 4)
    Uold = zeros(Float64, 4)
    # println("Prim1.01a")
    # println(IOContext(stdout, :compact => false), globaldata[1].prim)
    for (itm, _) in enumerate(loc_globaldata)
        if loc_globaldata[itm].flag_1 == 0
            fill!(U, 0.0)
            state_update_wall(loc_globaldata, loc_globaldata_mutable, itm, max_res, sum_res_sqr, U, Uold, rk)
        elseif loc_globaldata[itm].flag_1 == 2
            fill!(U, 0.0)
            state_update_outer(loc_globaldata, loc_globaldata_mutable, Mach, gamma, pr_inf, rho_inf, theta, itm, max_res, sum_res_sqr, U, Uold, rk)
        elseif loc_globaldata[itm].flag_1 == 1
            fill!(U, 0.0)
            state_update_interior(loc_globaldata, loc_globaldata_mutable, itm, max_res, sum_res_sqr, U, Uold, rk)
        end
    end
    # println(sum_res_sqr[1])
    # println("The length is ", length(globaldata))
    # res_new = sqrt(sum_res_sqr[1])/ length(globaldata)
    res_new[1] = sum_res_sqr[1]
    if iter <= 2
        res_old[1] = res_new[1]
    end
    # residue = 0
    # # println(res_old)
    # if iter <= 2
    #     res_old[1] = res_new
    #     residue = 0
    # else
    #     residue = log10(res_new/res_old[1])
    # end
    # if rk == 4
    #     print(" ", residue, " ")
    # end
    # open("residue_" * string(numPoints) * ".txt", "a+") do residue_io
    #     @printf(residue_io, "%d %s\n", iter, residue)
    # end

    # res_old = 0

    return  nothing
end

function state_update_wall(globaldata, loc_globaldata_mutable, itm, max_res, sum_res_sqr, U, Uold, rk)
    nx = globaldata[itm].nx
    ny = globaldata[itm].ny
    # if itm == 2
    #     println("Prim1.01a2.1")
    #     println(IOContext(stdout, :compact => false), globaldata[1].prim)
    # end
    primitive_to_conserved(globaldata, itm, nx, ny, U)
    # if itm == 2
    #     println("Prim1.01a2.2")
    #     println(IOContext(stdout, :compact => false), globaldata[1].prim)
    # end
    temp = U[1]
    @. U = U - 0.5 * (globaldata[itm].delta * @views loc_globaldata_mutable[5:8, itm])
    if rk == 3
        primitive_to_conserved_old(globaldata, itm, nx, ny, Uold)
        @. U = U * 1/3 + Uold * 2/3
    end
    U[3] = zero(Float64)
    U2_rot = U[2]
    U3_rot = U[3]
    U[2] = U2_rot*ny + U3_rot*nx
    U[3] = U3_rot*ny - U2_rot*nx
    res_sqr = (U[1] - temp)*(U[1] - temp)
    # if itm == 2
    #     println("Prim1.01a2.3")
    #     println(IOContext(stdout, :compact => false), globaldata[1].prim)
    # end
    # if res_sqr > max_res
    #     max_res = res_sqr
    #     max_res_point = itm
    # end
    sum_res_sqr[1] += res_sqr
    globaldata[itm].prim[1] = U[1]
    temp = 1.0 / U[1]
    globaldata[itm].prim[2] = U[2]*temp
    globaldata[itm].prim[3] = U[3]*temp
    globaldata[itm].prim[4] = (0.4*U[4]) - ((0.2 * temp) * (U[2] * U[2] + U[3] * U[3]))
    # if itm == 2
    #     println("Prim1.01a2.5")
    #     println(IOContext(stdout, :compact => false), globaldata[1].prim)
    # end
end

@inline function state_update_outer(globaldata, loc_globaldata_mutable, Mach, gamma, pr_inf, rho_inf, theta, itm, max_res, sum_res_sqr, U, Uold, rk)
    nx = globaldata[itm].nx
    ny = globaldata[itm].ny
    conserved_vector_Ubar(globaldata, itm, nx, ny, Mach, gamma, pr_inf, rho_inf, theta, U)
    temp = U[1]
    @. U = U - 0.5 * globaldata[itm].delta * @views loc_globaldata_mutable[5:8, itm]
    if rk == 3
        conserved_vector_Ubar_old(globaldata, itm, nx, ny, Mach, gamma, pr_inf, rho_inf, theta, Uold)
        @. U = U * 1/3 + Uold * 2/3
    end
    U2_rot = U[2]
    U3_rot = U[3]
    U[2] = U2_rot*ny + U3_rot*nx
    U[3] = U3_rot*ny - U2_rot*nx
    globaldata[itm].prim[1] = U[1]
    temp = 1.0 / U[1]
    globaldata[itm].prim[2] = U[2]*temp
    globaldata[itm].prim[3] = U[3]*temp
    globaldata[itm].prim[4] = (0.4*U[4]) - (0.2*temp)*(U[2]*U[2] + U[3]*U[3])
end

@inline function state_update_interior(globaldata, loc_globaldata_mutable, itm, max_res, sum_res_sqr, U, Uold, rk)
    nx = globaldata[itm].nx
    ny = globaldata[itm].ny
    primitive_to_conserved(globaldata, itm, nx, ny, U)
    # if itm == 1
    #     println("Prim1.11")
    #     println(IOContext(stdout, :compact => false), globaldata[itm].prim)
    # end
    # if itm == 1
    #     println(IOContext(stdout, :compact => false), U)
    #     # println(IOContext(stdout, :compact => false), temp)
    # end
    temp = U[1]
    @. U = U - 0.5 * globaldata[itm].delta * @views loc_globaldata_mutable[5:8, itm]
    if rk == 3
        primitive_to_conserved_old(globaldata, itm, nx, ny, Uold)
        @. U =U * 1/3 + Uold * 2/3
    end
    U2_rot = U[2]
    U3_rot = U[3]
    U[2] = U2_rot*ny + U3_rot*nx
    U[3] = U3_rot*ny - U2_rot*nx
    res_sqr = (U[1] - temp)*(U[1] - temp)
    # if itm == 2
    #     println("Prim1.01a2.3")
    #     println(IOContext(stdout, :compact => false), globaldata[1].prim)
    # end
    # if res_sqr > max_res
    #     max_res = res_sqr
    #     max_res_point = itm
    # end
    sum_res_sqr[1] += res_sqr
    # if itm == 1
    #     println(IOContext(stdout, :compact => false), U)
    #     println(IOContext(stdout, :compact => false), temp)
    # end
    globaldata[itm].prim[1] = U[1]
    temp = 1.0 / U[1]
    globaldata[itm].prim[2] = U[2]*temp
    globaldata[itm].prim[3] = U[3]*temp
    globaldata[itm].prim[4] = (0.4*U[4]) - (0.2*temp)*(U[2]*U[2] + U[3]*U[3])
end

@inline function primitive_to_conserved(globaldata, itm, nx, ny, U)
    # if itm == 1
    #     println("Prim1.1")
    #     println(IOContext(stdout, :compact => false), globaldata[itm].prim)
    # end
    rho = globaldata[itm].prim[1]
    U[1] = rho
    temp1::Float64 = rho * globaldata[itm].prim[2]
    temp2::Float64 = rho * globaldata[itm].prim[3]
    U[2] = temp1*ny - temp2*nx
    U[3] = temp1*nx + temp2*ny
    U[4] = 2.5*globaldata[itm].prim[4] + 0.5*(temp1^2 + temp2^2)/rho
    # if itm == 1
    #     println("U")
    #     println(IOContext(stdout, :compact => false), U)
    # end
end

@inline function primitive_to_conserved_old(globaldata, itm, nx, ny, U)
    # if itm == 1
    #     println("Prim1.1")
    #     println(IOContext(stdout, :compact => false), globaldata[itm].prim)
    # end
    rho = globaldata[itm].prim_old[1]
    U[1] = rho
    temp1::Float64 = rho * globaldata[itm].prim_old[2]
    temp2::Float64 = rho * globaldata[itm].prim_old[3]
    U[2] = temp1*ny - temp2*nx
    U[3] = temp1*nx + temp2*ny
    U[4] = 2.5*globaldata[itm].prim_old[4] + 0.5*(temp1^2 + temp2^2)/rho
    # if itm == 1
    #     println("U")
    #     println(IOContext(stdout, :compact => false), U)
    # end
end

@inline function conserved_vector_Ubar(globaldata, itm, nx, ny, Mach, gamma, pr_inf, rho_inf, theta, Ubar)

    u1_inf::Float64 = Mach*cos(theta)
    u2_inf::Float64 = Mach*sin(theta)

    tx = ny
    ty = -nx

    u1_inf_rot = u1_inf*tx + u2_inf*ty
    u2_inf_rot = u1_inf*nx + u2_inf*ny

    temp1 = (u1_inf_rot * u1_inf_rot + u2_inf_rot*u2_inf_rot)
    e_inf = (pr_inf/(rho_inf*(gamma-1))) + 0.5 * (temp1)

    beta = (0.5 * rho_inf)/pr_inf
    S2 = u2_inf_rot * sqrt(beta)
    B2_inf = exp(-S2*S2)/(2*sqrt(Float64(pi)*beta))
    A2n_inf = 0.5 * (1 - SpecialFunctions.erf(S2))

    rho = globaldata[itm].prim[1]
    u1 = globaldata[itm].prim[2]
    u2 = globaldata[itm].prim[3]
    pr = globaldata[itm].prim[4]

    u1_rot = u1*tx + u2*ty
    u2_rot = u1*nx + u2*ny

    temp1 = (u1_rot*u1_rot + u2_rot*u2_rot)
    e = (pr/(rho*(gamma-1))) + 0.5*(temp1)

    beta = (rho)/(2*pr)
    S2 = u2_rot*sqrt(beta)
    B2 = exp(-S2*S2)/(2*sqrt(Float64(pi)*beta))
    A2p = 0.5*(1 + SpecialFunctions.erf(S2))

    Ubar[1] = (rho_inf*A2n_inf) + (rho*A2p)

    Ubar[2] = (rho_inf*u1_inf_rot*A2n_inf) + (rho*u1_rot*A2p)

    temp1 = rho_inf*(u2_inf_rot*A2n_inf - B2_inf)
    temp2 = rho*(u2_rot*A2p + B2)
    Ubar[3] = (temp1 + temp2)

    temp1 = (rho_inf*A2n_inf* e_inf - 0.5*rho_inf*u2_inf_rot*B2_inf)
    temp2 = (rho*A2p*e + 0.5*rho*u2_rot*B2)

    Ubar[4] = (temp1 + temp2)
end

@inline function conserved_vector_Ubar_old(globaldata, itm, nx, ny, Mach, gamma, pr_inf, rho_inf, theta, Ubar)

    u1_inf::Float64 = Mach*cos(theta)
    u2_inf::Float64 = Mach*sin(theta)

    tx = ny
    ty = -nx

    u1_inf_rot = u1_inf*tx + u2_inf*ty
    u2_inf_rot = u1_inf*nx + u2_inf*ny

    temp1 = (u1_inf_rot * u1_inf_rot + u2_inf_rot*u2_inf_rot)
    e_inf = (pr_inf/(rho_inf*(gamma-1))) + 0.5 * (temp1)

    beta = (0.5 * rho_inf)/pr_inf
    S2 = u2_inf_rot * sqrt(beta)
    B2_inf = exp(-S2*S2)/(2*sqrt(Float64(pi)*beta))
    A2n_inf = 0.5 * (1 - SpecialFunctions.erf(S2))

    rho = globaldata[itm].prim_old[1]
    u1 = globaldata[itm].prim_old[2]
    u2 = globaldata[itm].prim_old[3]
    pr = globaldata[itm].prim_old[4]

    u1_rot = u1*tx + u2*ty
    u2_rot = u1*nx + u2*ny

    temp1 = (u1_rot*u1_rot + u2_rot*u2_rot)
    e = (pr/(rho*(gamma-1))) + 0.5*(temp1)

    beta = (rho)/(2*pr)
    S2 = u2_rot*sqrt(beta)
    B2 = exp(-S2*S2)/(2*sqrt(Float64(pi)*beta))
    A2p = 0.5*(1 + SpecialFunctions.erf(S2))

    Ubar[1] = (rho_inf*A2n_inf) + (rho*A2p)

    Ubar[2] = (rho_inf*u1_inf_rot*A2n_inf) + (rho*u1_rot*A2p)

    temp1 = rho_inf*(u2_inf_rot*A2n_inf - B2_inf)
    temp2 = rho*(u2_rot*A2p + B2)
    Ubar[3] = (temp1 + temp2)

    temp1 = (rho_inf*A2n_inf* e_inf - 0.5*rho_inf*u2_inf_rot*B2_inf)
    temp2 = (rho*A2p*e + 0.5*rho*u2_rot*B2)

    Ubar[4] = (temp1 + temp2)
end

max_stars_repo_name: TestSubjector/HybridMeshfreeSolver

max_issues_repo_name: TestSubjector/HybridMeshfreeSolver

max_forks_repo_name: TestSubjector/HybridMeshfreeSolver