text:
module Example

using Twinkle, Twinkle.FlexUI
using Colors
using StaticArrays

println("Start [$(splitext(basename(@__FILE__))[1])]")

# ---------------------------------------------------------------
# some default styles
# ---------------------------------------------------------------
card_style = "margin:0.2em; border: 1px solid lightgray!important; border-radius: 30px !important;"

expansion_panel_style = "margin:0.2em;"
expansion_panel_header_style = "" # "border: 1px solid lightgray!important;"
expansion_panel_subtitle_style = "position: absolute; padding-left: 30%;"

# ---------------------------------------------------------------
# utility functions
# ---------------------------------------------------------------
# returns the syntaxt and the result of an expression
function syntax(e::String)
    d = Meta.parse(e)
    a = eval(d)

    # b = MDJulia(e)
    b = CodeSnip(text=e)
    return (a, b)
end

# returns a Card control
function ExampleCard(e::String)
    return Card(
        style=card_style,
        content=VContainer(
            syntax(e)...,
        ),
    )
end
current_module = @__MODULE__

# ---------------------------------------------------------------
# Create the Application Object and the 3D viewer
# ---------------------------------------------------------------
app = App()
FlexUI.prop!(app, :title, "Twinkle Example - Controls Gallery")

# scene = Scene(openWindow = false)
# set_Z_up!(scene)
# grid!(scene, false)
# cameraTransform!(scene, lookAt(SVector(0.0, 10.0, 200.0), zero3()))
# cameraPlanes!(scene, 0.1, 1000.0)

# ---------------------------------------------------------------
# Define Variables
# ---------------------------------------------------------------

labelText = addVariable!(app, Variable(name="labelText", type="string", value="This text comes from a variable"))
firstName = addVariable!(app, Variable(name="firstName", type="string", value=""))
height = addVariable!(app, Variable(name="height", type="flota64", value="176"))

option = addVariable!(app, Variable(name="option", type="string", value="Four"))

range1 = addVariable!(app, Variable(name="range1", type="flota64", value=0))
range2 = addVariable!(app, Variable(name="range2", type="flota64", value=0.5))

image1 = addVariable!(app, Variable(name="image1", type="image", value="https://julialang.org/assets/infra/onlinestats.gif"))

toggle1 = addVariable!(app, Variable(name="toggle1", type="bool", value=false))

option1 = addVariable!(app, Variable(name="option1", type="string", value="first"))

# ---------------------------------------------------------------
# Define Controls
# ---------------------------------------------------------------

ui = VContainer(
    # Markdown(
    #     content = "# Ran Gal\n## AAA\n",
    # ),
#     Markdown(
#         content =
# raw"""

# ## Markdown __rulez__!
# ---

# ### Syntax highlight
# ## Syntax highlight
# # __Syntax__ highlight

# ```typescript
# const language = 'typescript';
# const language = 'typescript';
# const language = 'typescript';
# const language = 'typescript';
# ````

# ```julia
# a::Float64 = 1.0
# for i in 1:10
#     println("This is a string interpolation $i")
# end
# @info "some info"
# ```

# this is __some__ ~~normal~~ text
# Basic inline HTML may be supported.

# ### Lists
# 1. Ordered list with a [Link to google](http://www.google.com)
# 2. Another bullet point
#   - Unordered __list__
#   - Another unordered bullet point

# ### Blockquote
# > Blockquote to the max

# """,
#     ),

    Accordion(
        panels=[

            # Labels
            ExpansionPanel(
                title="Label",
                subtitle="labels are non-interactive elements used to display text",
                style=expansion_panel_style,
                headerStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        ExampleCard("""Label(text="A Normal Label")"""),
                        ExampleCard("""Label(text="Label with style", style="color: red;")"""),
                        ExampleCard("""Label(text="Label with style and class H1", class="h1", style="color: red;")"""),
                        ExampleCard("""Label(text="Label with style and class H2", class="h2", style="color: blue;")"""),
                        ExampleCard("""Label(text="Label with style and class H3", class="h3", style="background-color:rgb(255, 99, 71);")"""),
                        ExampleCard("""Label(text="Label with style and class H4", class="h4", style="background-color:#ff6347;")"""),
                        ExampleCard("""Label(text="Allow HTML tags in text.", isHTML=true)"""),
                        Card(
                            style=card_style,
                            content=VContainer(
                                syntax("""Label(variable="labelText", isHTML=true)""")...,
                                Label(text="""You can change the content of the label using the Julia REPL:"""),
                                CodeSnipJulia("""$(current_module).labelText[] = "This text is from Julia" """),
                                Label(text="""or even include HTML tags (isHTML=true)"""),
                                CodeSnipJulia("""$(current_module).labelText[] = "Do somthing BOLD" """),

                            ),
                        ),
                    ],
                ),
            ),

            # Fields
            ExpansionPanel(
                title="Field",
                subtitle="fields allow user input",
                style=expansion_panel_style,
                headerStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="String Field",
                            style=card_style,
                            content=VContainer(
                                syntax("""Field(
                                    input="text",
                                    label="First Name",
                                    hint="Please Enter your first name",
                                    variable="firstName",
                                )""")...,
                                Label(text="""You can change the content of the field using the Julia REPL:"""),
                                CodeSnipJulia("""$(current_module).firstName[] = "Robert" """),
                            ),

                        ),

                        Card(
                            title="Numeric Field",
                            style=card_style,
                            content=VContainer(
                                syntax("""Field(
                                    input="number",
                                    label="Height",
                                    hint="in centimeters",
                                    variable="height",
                                )""")...,
                                Label(text="""You can change the content of the field using the Julia REPL:"""),
                                CodeSnipJulia("""$(current_module).height[] = 183.1"""),
                            ),

                        ),

                        Card(
                            title="Combobox Field (options)",
                            style=card_style,
                            content=VContainer(
                                syntax("""Field(
                                    input="select",
                                    label="A Simple ComboBox",
                                    hint="Please select an option",
                                    variable="option",
                                    options=[
                                        Dict(:key => "One", :value => "First Option"),
                                        Dict(:key => "Two", :value => "Second Option"),
                                        Dict(:key => "Three", :value => "Third Option"),
                                        Dict(:key => "Four", :value => "Fourth Option"),
                                    ]
                                )""")...,
                                Label(text="""You can change the content of the field using the Julia REPL:"""),
                                CodeSnipJulia("""$(current_module).option[] = "Two" """),
                            ),

                        ),

                    ],
                ),
            ),

            # Sliders
            ExpansionPanel(
                title="Slider",
                subtitle="sliders allow range type update of values",
                style=expansion_panel_style,
                headerStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Simple Slider",
                            style=card_style,
                            content=VContainer(
                                syntax("""Slider(
                                    min=0,
                                    max=100,
                                    value=10,
                                    variable="range1"
                                )""")...,
                                Label(text="""You can change the content of the field using the Julia REPL:"""),
                                CodeSnipJulia("""$(current_module).range1[] = 55 """),
                            ),

                        ),

                        Card(
                            title="Slider with text and embedded value",
                            style=card_style,
                            content=VContainer(
                                syntax(raw"""Slider(
                                    text="Embedded Value [\$()]",
                                    trailing_text="[\$()cm]",
                                    min=0,
                                    max=100,
                                    value=10,
                                    variable="range1"
                                )""")...,
                                Label(text="""You can change the content of the field using the Julia REPL:"""),
                                CodeSnipJulia("""$(current_module).range1[] = 55 """),
                            ),

                        ),

                        Card(
                            title="Step Size",
                            style=card_style,
                            content=VContainer(
                                syntax(raw"""Slider(
                                    text="Step Size",
                                    trailing_text="current value is \$()",
                                    min=0,
                                    max=1,
                                    value=0.5,
                                    step=0.01,
                                    variable="range2"
                                )""")...,
                                Label(text="""You can change the content of the field using the Julia REPL:"""),
                                CodeSnipJulia("""$(current_module).range2[] = 0.5 """),
                            ),

                        ),

                    ],
                ),
            ),

            # Buttons
            ExpansionPanel(
                title="Button",
                subtitle="buttons are activators that can run functions in the Julia backend",
                style=expansion_panel_style,
                headerStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Simple Button",
                            style=card_style,
                            content=VContainer(
                                syntax("""HContainer(
                                    Button(
                                        text = "Basic",
                                    ),
                                    Button(
                                        text = "Primary",
                                        color = "primary",
                                    ),
                                    Button(
                                        text = "Accent",
                                        color = "accent",
                                    ),
                                    Button(
                                        text = "Warn",
                                        color = "warn",
                                    ),
                                )""")...,
                            ),

                        ),

                        Card(
                            title="Raised Button",
                            style=card_style,
                            content=VContainer(
                                syntax("""HContainer(
                                    Button(
                                        text = "Basic",
                                        buttonType = "raised"
                                    ),
                                    Button(
                                        text = "Primary",
                                        color = "primary",
                                        buttonType = "raised"
                                    ),
                                    Button(
                                        text = "Accent",
                                        color = "accent",
                                        buttonType = "raised"
                                    ),
                                    Button(
                                        text = "Warn",
                                        color = "warn",
                                        buttonType = "raised"
                                    ),
                                )""")...,
                            ),

                        ),

                        Card(
                            title="Stroked Button",
                            style=card_style,
                            content=VContainer(
                                syntax("""HContainer(
                                    Button(
                                        text = "Basic",
                                        buttonType = "stroked"
                                    ),
                                    Button(
                                        text = "Primary",
                                        color = "primary",
                                        buttonType = "stroked"
                                    ),
                                    Button(
                                        text = "Accent",
                                        color = "accent",
                                        buttonType = "stroked"
                                    ),
                                    Button(
                                        text = "Warn",
                                        color = "warn",
                                        buttonType = "stroked"
                                    ),
                                )""")...,
                            ),

                        ),

                        Card(
                            title="Flat Button",
                            style=card_style,
                            content=VContainer(
                                syntax("""HContainer(
                                    Button(
                                        text = "Basic",
                                        buttonType = "flat"
                                    ),
                                    Button(
                                        text = "Primary",
                                        color = "primary",
                                        buttonType = "flat"
                                    ),
                                    Button(
                                        text = "Accent",
                                        color = "accent",
                                        buttonType = "flat"
                                    ),
                                    Button(
                                        text = "Warn",
                                        color = "warn",
                                        buttonType = "flat"
                                    ),
                                )""")...,
                            ),

                        ),

                        Card(
                            title="Icon Button",
                            style=card_style,
                            content=VContainer(
                                syntax("""HContainer(
                                    Button(
                                        text = "more_vert",
                                        buttonType = "icon"
                                    ),
                                    Button(
                                        text = "home",
                                        color = "primary",
                                        buttonType = "icon"
                                    ),
                                    Button(
                                        text = "menu",
                                        color = "accent",
                                        buttonType = "icon"
                                    ),
                                    Button(
                                        text = "favorite",
                                        color = "warn",
                                        buttonType = "icon"
                                    ),
                                )""")...,
                            ),

                        ),

                        Card(
                            title="FAB Button",
                            style=card_style,
                            content=VContainer(
                                syntax("""HContainer(
                                    Button(
                                        text = "delete",
                                        buttonType = "fab"
                                    ),
                                    Button(
                                        text = "bookmark",
                                        color = "primary",
                                        buttonType = "fab"
                                    ),
                                    Button(
                                        text = "home",
                                        color = "accent",
                                        buttonType = "fab"
                                    ),
                                    Button(
                                        text = "favorite",
                                        color = "warn",
                                        buttonType = "fab"
                                    ),
                                )""")...,
                            ),

                        ),

                        Card(
                            title="Mini FAB Button",
                            style=card_style,
                            content=VContainer(
                                syntax("""HContainer(
                                    Button(
                                        text = "menu",
                                        buttonType = "mini-fab"
                                    ),
                                    Button(
                                        text = "plus_one",
                                        color = "primary",
                                        buttonType = "mini-fab"
                                    ),
                                    Button(
                                        text = "filter_list",
                                        color = "accent",
                                        buttonType = "mini-fab"
                                    ),
                                    Button(
                                        text = "dashboard",
                                        color = "warn",
                                        buttonType = "mini-fab"
                                    ),
                                )""")...,
                            ),

                        ),

                        Card(
                            title="General",
                            style=card_style * "max-width: 400px",
                            content=VContainer(
                                Markdown(
                                    content="""
                                    For button types __icon__, __fab__ and __mini-fab__, the button text contains the icon name to be displayed.\n
                                    You can find the full list of available icons at:
                                    ```HTML
                                    https://fonts.google.com/icons
                                    ```

                                    """,
                                ),
                                Label(
                                    text="""(link)""",
                                    isHTML=true,
                                ),
                            ),

                        ),

                    ],
                ),
            ),

            # Images and Pan-Zoom
            ExpansionPanel(
                title="Image and PanZoom",
                subtitle="controls for displaying images",
                style=expansion_panel_style,
                headerStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Simple Image",
                            style=card_style,
                            content=VContainer(
                                syntax("""Image(
                                    source="https://julialang.org/assets/infra/waves.gif",
                                    style="width: 250px;"
                                )""")...,
                            ),

                        ),

                        Card(
                            title="Image using a Variable source",
                            style=card_style,
                            content=VContainer(
                                syntax("""Image(
                                    source="\\\$(image1)",
                                    style="width: 250px;"
                                )""")...,
                                Label(text="""You can change the image source:"""),
                                CodeSnipJulia("""$(current_module).image1[] = "https://microsoft.github.io/OpticSim.jl/dev/assets/tele.png" """),
                                Label(text="""To a local file:"""),
                                CodeSnipJulia("""$(current_module).image1[] = "file://" * joinpath(dirname(pathof(Twinkle)), "data", "ExampleImage.png") """),
                                Label(text="""Or to an imaged created on the fly (note the type notation - png and svg are supported):"""),
                                CodeSnipJulia("""# using Makie
                                                 Makie.inline!(true)
                                                 $(current_module).image1["png"] = Makie.scatter(rand(100)) """),
                            ),

                        ),

                        Card(
                            title="PanZoom component that allow, well, pan and zoom duh!",
                            style=card_style * "max-width: 600px",
                            content=VContainer(
                                Label(
                                    text="(note: i'm still looking for a better image viewer component that handle the mouse wheel without scrolling the page. if you know of such a component, please let me know...)"
                                ),
                                syntax("""PanZoom(
                                    style="width: 100%; height: 400px",
                                    content = VContainer(
                                        Image(
                                            source="\\\$(image1)",
                                            # style="width: 250px;"
                                        ),
                                    ),
                                )""")...,

                            ),

                        ),

                    ],
                ),
            ),

            # Checkboxes
            ExpansionPanel(
                title="CheckBox",
                subtitle="toggler",
                style=expansion_panel_style,
                headerStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Simple checkbox",
                            style=card_style,
                            content=VContainer(
                                syntax("""CheckBox(
                                    label="Always save before closing",
                                    variable="toggle1",
                                )""")...,
                                Label(text="Adding a label to debug the toggle value:"),
                                syntax("""Label(
                                    text="Current value of toggle1 is [\\\$(toggle1)]",
                                )""")...,
                                Label(text="""You can update the toggle value from the REPL:"""),
                                CodeSnipJulia("""$(current_module).toggle1[] = true """),
                            ),
                        ),
                    ],
                ),
            ),

            # RadioGroup and ButtonToggle
            ExpansionPanel(
                title="RadioGroup and ButtonToggle",
                subtitle="option selectors",
                style=expansion_panel_style,
                headerStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Horizontal Radio Group",
                            style=card_style,
                            content=VContainer(
                                syntax("""RadioGroup(
                                    variable="option1",
                                    direction="horizontal",
                                    options=[
                                        Dict(:key=>"first", :value=>"First Option"),
                                        Dict(:key=>"second", :value=>"Second Option"),
                                        Dict(:key=>"third", :value=>"Third Option"),
                                        Dict(:key=>"fourth", :value=>"Fourth Option")
                                    ]
                                )""")...,
                                Label(text="""You can update the toggle value from the REPL:"""),
                                CodeSnipJulia("""$(current_module).option1[] = "third" """),
                            ),
                        ),

                        Card(
                            title="Vertical Radio Group",
                            style=card_style,
                            content=VContainer(
                                syntax("""RadioGroup(
                                    variable="option1",
                                    direction="vertical",
                                    options=[
                                        Dict(:key=>"first", :value=>"First Option"),
                                        Dict(:key=>"second", :value=>"Second Option"),
                                        Dict(:key=>"third", :value=>"Third Option"),
                                        Dict(:key=>"fourth", :value=>"Fourth Option")
                                    ]
                                )""")...,
                                Label(text="""You can update the toggle value from the REPL:"""),
                                CodeSnipJulia("""$(current_module).option1[] = "third" """),
                            ),
                        ),

                        Card(
                            title="Button Toggle",
                            style=card_style,
                            content=VContainer(
                                syntax("""ButtonToggle(
                                    variable="option1",
                                    options = [
                                        Dict(:key=>"first", :value=>"First Option"),
                                        Dict(:key=>"second", :value=>"Second Option"),
                                        Dict(:key=>"third", :value=>"Third Option"),
                                        Dict(:key=>"fourth", :value=>"Fourth Option")
                                    ]
                                )""")...,
                                Label(text="""You can update the toggle value from the REPL:"""),
                                CodeSnipJulia("""$(current_module).option1[] = "third" """),
                            ),
                        ),

                    ],
                ),
            ),

            # ExpansionPanel and Accordion
            ExpansionPanel(
                title="ExpansionPanel and Accordion",
                subtitle="provides an expandable details-summary view",
                style=expansion_panel_style,
                headerStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Expansion Panel",
                            style=card_style,
                            content=VContainer(
                                syntax("""ExpansionPanel(
                                    title = "Good Stuff",
                                    subtitle = "please press to expand",
                                    content = VContainer(       # vertical container
                                        Label(text="We are inside an expansion label now"),
                                        Label(text="The value of the checkbox below if [\\\$(toggle1)]"),
                                        CheckBox(
                                            label="Always save before closing",
                                            variable="toggle1",
                                        ),
                                        HContainer(
                                            Button(
                                                text = "Button1",
                                                color = "primary",
                                                buttonType = "raised"
                                            ),
                                            Button(
                                                text = "Button2",
                                                color = "primary",
                                                buttonType = "raised"
                                            ),
                                        )
                                    ),
                                )""")...,
                            ),
                        ),

                        Card(
                            title="Accordion",
                            style=card_style,
                            content=VContainer(
                                syntax("""Accordion(
                                    panels = [
                                        ExpansionPanel(
                                            title="My First Expansion Panel",
                                            style=card_style,
                                            content = VContainer(
                                                H2Label("Inside the FIRST expansion panel"),
                                                H4Label("Try to expand other panels"),
                                            ),
                                        ),

                                        ExpansionPanel(
                                            title="My First Expansion Panel",
                                            style=card_style,
                                            content = VContainer(
                                                H2Label("Inside the SECOND expansion panel"),
                                                H4Label("Try to expand other panels"),
                                            ),
                                        ),

                                        ExpansionPanel(
                                            title="My First Expansion Panel",
                                            style=card_style,
                                            content = VContainer(
                                                H2Label("Inside the THIRD expansion panel"),
                                                H4Label("Try to expand other panels"),
                                            ),
                                        ),
                                    ],
                                )""")...,
                            ),
                        ),

                    ],
                ),
            ),

            # Tabs
            ExpansionPanel(
                title="Tabs",
                subtitle="ganize content into separate views where only one view can be visible at a time",
                style=expansion_panel_style,
                headerStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Tabs",
                            style=card_style,
                            content=VContainer(

                                syntax("""Tabs(
                                    style="min-height: 300px;",
                                    tabs=[
                                        Tab(                        # First Tab Definition
                                            label="First Tab",
                                            content=VContainer(
                                                Image(
                                                    source="https://julialang.org/assets/infra/waves.gif",
                                                    style="width: 350px;"
                                                ),
                                                Button(
                                                    text="Just a button",
                                                ),
                                            ),
                                        ),
                                        Tab(                        # Second Tab Definition
                                            label="Second Tab",
                                            content=HContainer(
                                                Image(
                                                    source="\\\$(image1)",
                                                    style="width: 350px;"
                                                ),
                                                Button(
                                                    text="Just a button",
                                                ),
                                            ),
                                        ),

                                        Tab(                        # Third Tab Definition
                                            label="Third Tab",
                                            content=VContainer(
                                                ExpansionPanel(
                                                    title = "Good Stuff",
                                                    subtitle = "please press to expand",
                                                    style=card_style,
                                                    content = VContainer(       # vertical container
                                                        Label(text="We are inside an expansion label now"),
                                                        Label(text="The value of the checkbox below if [\\\$(toggle1)]"),
                                                        CheckBox(
                                                            label="Always save before closing",
                                                            variable="toggle1",
                                                        ),
                                                        HContainer(
                                                            Button(
                                                                text = "Button1",
                                                                color = "primary",
                                                                buttonType = "raised"
                                                            ),
                                                            Button(
                                                                text = "Button2",
                                                                color = "primary",
                                                                buttonType = "raised"
                                                            ),
                                                        )
                                                    ),
                                                )
                                            ),
                                        ),

                                    ],
                                )""")...,
                            ),
                        ),

                    ],
                ),
            ),

            # Markdown
            ExpansionPanel(
                title="Markdown and CodeSnip",
                subtitle="support a basic implementation of the markdown language",
                style=expansion_panel_style,
                headerStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            style=card_style,
                            content=VContainer(
                                # Markdown(
                                #     content =
                                #         raw"""
                                #         ## Markdown __rulez__!
                                #         ---

                                #         # __Syntax__ highlight
                                #         ## Syntax highlight
                                #         ### Syntax highlight

                                #         ## inline code blocks in typescript and Julia with highlights
                                #         ```typescript
                                #         const language = 'typescript';
                                #         const language = 'typescript';
                                #         ````

                                #         ```julia
                                #         a::Float64 = 1.0
                                #         for i in 1:10
                                #             println("String interpolation $i")
                                #         end
                                #         @info "Blah Blah" a
                                #         ```

                                #         This is __some__ ~~normal~~ text.

                                #         Basic inline HTML may be supported.

                                #         ### Lists
                                #         1. Ordered list with a [Link](https://github.com/galran/Twinkle.jl) - you won't be able to go back to this page
                                #         2. Another bullet point
                                #         - Unordered __list__
                                #         - Another unordered bullet point

                                #         ### Blockquote
                                #         > Blockquote to the max
                                #         """,
                                # ),

                                syntax("""Markdown(
                                        content=
                                            "
                                            ## Markdown __rulez__!
                                            ---

                                            # __Syntax__ highlight
                                            ## Syntax highlight
                                            ### Syntax highlight

                                            ## inline code blocks in typescript and Julia with highlights
                                            ```typescript
                                            const language = 'typescript';
                                            const language = 'typescript';
                                            ````

                                            ```julia
                                            length::Float64 = 1.0
                                            for i in 1:10
                                                println(i)
                                            end
                                            @info length
                                            ```

                                            This is __some__ ~~normal~~ text.

                                            Basic inline HTML may be supported.

                                            ### Lists
                                            1. Ordered list with a [Link](https://github.com/galran/Twinkle.jl).
                                            __NOTE__: You won't be able to go back to this page
                                            2. Another bullet point

                                            - Unordered __list__
                                            - Another unordered bullet point

                                            ### Blockquote
                                            > Blockquote to the max
                                            ")""")...,

                            ),
                        ),

                        Card(
                            title="CodeSnip",
                            style=card_style,
                            content=VContainer(
                                H3Label("CodeSnip allow more control over the code block, such as adding line numbers:"),
                                syntax("""CodeSnip(
                                    lineNumbers=true,
                                    text=
                                        "function mandelbrot(a)
                                            z = 0
                                            for i=1:50
                                                z = z^2 + a
                                            end
                                            return z
                                        end

                                        for y=1.0:-0.05:-1.0
                                            for x=-2.0:0.0315:0.5
                                                abs(mandelbrot(complex(x, y))) < 2 ? print('*') : print(' ')
                                            end
                                            println()
                                        end",
                                )""")...,
                                H3Label("or adding a command prompt for all or some lines"),
                                syntax("""CodeSnip(
                                    commandLine=true,
                                    rawLines="",
                                    prompt="julia>",
                                    text="angle = π / 2.1
                                    halfAngle = angle / 2.0
                                    println(halfAngle)",
                                    )""")...,

                                    syntax("""CodeSnip(
                                        commandLine=true,
                                        rawLines="2-999",
                                        prompt="julia>",
                                        text="angle = π / 2.1
                                        halfAngle = angle / 2.0
                                        println(halfAngle)",
                                        )""")...,

                            ),
                        ),

                    ],
                ),
            ),

        ],
    ),

)
FlexUI.controls!(app, ui)

# ---------------------------------------------------------------
# Run the application
# ---------------------------------------------------------------
run(app)

println("End [$(splitext(basename(@__FILE__))[1])]")

end # module


text:
@testset "names" begin

@with_names begin
    a = Equal("a")
    b = Alt(a, Equal("c"))
end

@test a.name == :a
@test b.name == :b

println("names ok")

end

ext: jl


text:
## Auxiliary functions

## checks PLS input data and params
## checks PLS input data and params
function check_data(X::Matrix{T},Y::Union{Vector{T},Matrix{T}}) where T<:AbstractFloat
    !isempty(X) ||
        throw(DimensionMismatch("Empty input data (X)."))
    !isempty(Y) ||
        throw(DimensionMismatch("Empty target data (Y)."))
    size(X, 1) == size(Y, 1) ||
        throw(DimensionMismatch("Incompatible number of rows of input data (X) and target data (Y)."))
end

function check_data(X::Matrix{T},nfeatures::Int) where T<:AbstractFloat
    !isempty(X) ||
        throw(DimensionMismatch("Empty input data (X)."))
    size(X, 2) == nfeatures ||
        throw(DimensionMismatch("Incompatible number of columns of input data (X) and original training X columns."))
end

function check_params(nfactors::Int, ncols::Int, kernel::AbstractString)
    nfactors >= 1 || error("nfactors must be a positive integer.")
    nfactors <= ncols || warn("nfactors greater than ncols of input data (X) must generate numerical problems. However, can improve results if ok.")
    kernel == "rbf" || kernel == "linear" || error("kernel must be kernel='linear' or 'kernel=rbf'")
end

## checks constant columns
check_constant_cols(X::Matrix{T}) where {T<:AbstractFloat} = size(X,1)>1 && !any(all(X .== X[1,:]',dims=1)) || error("You must remove constant columns of input data (X) before train")
check_constant_cols(Y::Vector{T}) where {T<:AbstractFloat} = length(Y)>1 && length(unique(Y)) > 1 || error("Your target values are constant. All values are equal to $(Y[1])")

## Preprocessing data using z-score statistics. this is due to the fact that if X and Y are z-scored, than X'Y returns for W vector a pearson correlation for each element! :)
centralize_data(D::Matrix{T}, m::Matrix{T}, s::Matrix{T}) where {T<:AbstractFloat}  = (D .-m)./s
centralize_data(D::Vector{T}, m::T, s::T)  where {T<:AbstractFloat} = (D .-m)./s

decentralize_data(D::Matrix{T}, m::Matrix{T}, s::Matrix{T}) where {T<:AbstractFloat} = D .*s .+m
decentralize_data(D::Vector{T}, m::T, s::T)  where {T<:AbstractFloat}               = D .*s .+m


text:
using Documenter

push!(LOAD_PATH, joinpath("..", "src"))
using CliOptions

makedocs(sitename = "CliOptions.jl",
         pages = Any[
             "Home" => "index.md",
             "reference.md",
         ])

if "--deploy" in ARGS
    deploydocs(repo = "github.com/sgryjp/CliOptions.git")
end


text:
function dot2csvTotalCollusion(filename)
    println("in dot2csvTotalCollusion")
    matCntryEdges = []

    fileTmp = open(filename)
    linesTmp = readlines(fileTmp)
    linesStr = linesTmp[1]#println(linesStr)#println(typeof(linesStr))
    splits1 = split(linesStr,";")
    for strFrag in splits1

        if(contains(strFrag,"penwidth"))#println(strFrag)
            c1end = search(strFrag,"-")
            c1end = collect(c1end)[1]-1
            c1 = strFrag[1:c1end]#println(c1)
            c2start = search(strFrag,">")
            c2end = search(strFrag," [")
            c2start = collect(c2start)[1]+1
            c2end = collect(c2end)[1]-1
            c2 = strFrag[c2start:c2end]#println(c2)
            pW1end = search(strFrag,"penwidth=")
            pW1end = collect(pW1end)[end]+1
            pW = parse(Int,strFrag[pW1end])#println(pW)
            pW2end = search(strFrag,"penwidth=",collect(search(strFrag,"penwidth="))[end]+1)
            finalEnd = search(strFrag,"]")
            pW2end = collect(pW2end)[end]+1
            finalEnd = collect(finalEnd)[1]-1
            pWmult = parse(Int,strFrag[pW2end:finalEnd])#println(pWmult)
            edgeWeight = pWmult/pW#println(edgeWeight)
            if(isempty(matCntryEdges))
                matCntryEdges = [c1 c2 edgeWeight]
            else
                matCntryEdges = vcat(matCntryEdges,[c1 c2 edgeWeight])
            end
        end
    end
    writedlm(string(filename,".csv"),matCntryEdges,',')#println(matCntryEdges)
    close(fileTmp)
end

function dot2csvOneWayTwoWay(filename)
    println("in dot2csvOneWayTwoWay!")
    matCntryEdges = []

    fileTmp = open(filename)
    linesTmp = readlines(fileTmp)
    linesStr = linesTmp[1]#
    #println(linesStr)#
    #println(typeof(linesStr))
    splits1 = split(linesStr,";")

    for strFrag in splits1

        if(contains(strFrag,"->"))#
            c1end = search(strFrag,"-")
            c1end = collect(c1end)[1]-1
            c1 = strFrag[1:c1end]#println(c1)

            c2start = search(strFrag,">")
            c2start = collect(c2start)[1]+1
            c2end = -1
            way = "oneWay"
            if(isempty(collect(search(strFrag," ["))))
                c2end = length(strFrag)#collect(c2end)[1]-1
            else
                c2end = search(strFrag," [")
                c2end = collect(c2end)[1]-1
                way = "twoWay"
            end
            c2 = strFrag[c2start:c2end]#
            if(isempty(matCntryEdges))
                matCntryEdges = [c1 c2 way]
                if(way == "twoWay")
                    matCntryEdges = vcat(matCntryEdges,[c2 c1 way])
                end
            else
                matCntryEdges = vcat(matCntryEdges,[c1 c2 way])
                if(way == "twoWay")
                    matCntryEdges = vcat(matCntryEdges,[c2 c1 way])
                end
            end
        end
    end
    writedlm(string(filename,".csv"),matCntryEdges,',')#println(matCntryEdges)
    close(fileTmp)
end

#these files have the one ways which may not be balanced
function dot2csvTotalOneWays(filename)
    println("in dot2csvTotalOneWays")
    matCntryEdges = []

    fileTmp = open(filename)
    linesTmp = readlines(fileTmp)
    linesStr = linesTmp[1]#println(linesStr)#println(typeof(linesStr))
    splits1 = split(linesStr,";")
    for strFrag in splits1

        if(contains(strFrag,"penwidth"))#println(strFrag)
            c1end = search(strFrag,"-")
            c1end = collect(c1end)[1]-1
            c1 = strFrag[1:c1end]#println(c1)
            c2start = search(strFrag,">")
            c2end = search(strFrag," [")
            c2start = collect(c2start)[1]+1
            c2end = collect(c2end)[1]-1
            c2 = strFrag[c2start:c2end]#println(c2)

            pW1end = search(strFrag,"penwidth=")
            pW1end = collect(pW1end)[end]+1
            #pW = parse(Int,strFrag[pW1end])#println(pW)
            #pW2end = search(strFrag,"penwidth=",collect(search(strFrag,"penwidth="))[end]+1)
            finalEnd = search(strFrag,"]")
            #pW2end = collect(pW2end)[end]+1
            finalEnd = collect(finalEnd)[1]-1
            pW = parse(Float64,strFrag[pW1end:finalEnd])#println(pWmult)
            edgeWeight = Int(pW/1.5)#println(edgeWeight)
            if(isempty(matCntryEdges))
                matCntryEdges = [c1 c2 edgeWeight]
            else
                matCntryEdges = vcat(matCntryEdges,[c1 c2 edgeWeight])
            end
        end
    end
    writedlm(string(filename,".csv"),matCntryEdges,',')
    #println(matCntryEdges)
    close(fileTmp)
end

#
function dot2csvConvert()
    resultsFile = readdir("./")
    for rf in resultsFile
        extS = search(rf,".dot")
        extC = search(rf,".csv")
        if(!isempty(collect(extS)))
            if(isempty(collect(extC)))
                if((collect(extS)[end]) == (length(rf)))
                    if(rf[1] == 'n')
                        println(rf)
                        if(contains(rf,"network:"))
                            dot2csvOneWayTwoWay(rf)
                            println("dot2csvOneWayTwoWay(filename)")
                        elseif(contains(rf,"networkTotal:"))
                            dot2csvTotalOneWays(rf)
                            println("dot2csvTotalOneWays(filename)")
                        elseif(contains(rf,"networkTotalCollusion:"))
                            dot2csvTotalCollusion(rf)
                            println("dot2csvTotalCollusion(filename)")
                        end
                    end
                end
            end
        end
    end
end
#
#filename = "network:1977-1982.dot"
#dot2csvOneWayTwoWay(filename)

#filename = "networkTotal:1977-2017windowSize5.dot"
#dot2csvTotalOneWays(filename)

#filename = "networkTotalCollusion:1977-2017windowSize5.dot"
#dot2csvTotalCollusion(filename)

    #=
    resultsFile = readdir("./dataTables/")
    yrMin = 100000
    yrMax = -1
    for rf in resultsFile
    fileTmp = open(string("./dataTables/",rf))
    linesTmp = readlines(fileTmp)         #readfile lines
    yrTmp = parse(Int,((split(rf,"."))[1]))
    countryNumTmp = length(split(linesTmp[1],",")) - 1#COLUMN NAME LIST (still the same regarding large set mapping to small set in cols) OF WHO CAN RECEIVE VOTES
    countryYearsNum[yrTmp] = countryNumTmp #NUM that receives votes
    close(fileTmp)
    if(yrTmp < yrMin)
    yrMin = yrTmp
    end
    if(yrTmp > yrMax)
    yrMax = yrTmp
    end
    end
    =#

max_stars_repo_name: mantzaris/eurovision

max_issues_repo_name: mantzaris/eurovision

max_forks_repo_name: mantzaris/eurovision


text:
#includes all relevant "modules"

#path to modules
path = "./core/"

include(string(path,"types.jl"))
include(string(path,"nonlins.jl"))
include(string(path,"helpers.jl"))
include(string(path,"dataimport.jl"))
include(string(path,"forwardprop.jl"))
include(string(path,"backprop_weightupdate.jl"))
include(string(path,"learning.jl"))
include(string(path,"training.jl"))


text:
# This file is a part of AstroLib.jl. License is MIT "Expat".
# Copyright (C) 2016 Mosè Giordano.

function _helio_jd(date::T, ra::T, dec::T, B1950::Bool, diff::Bool) where {T<:AbstractFloat}
    # Because `xyz' uses default B1950 coordinates, we'll convert everything to
    # B1950.
    if ! B1950
        ra, dec = bprecess(ra, dec)
    end
    delta_t = (date - 33282.42345905) / JULIANCENTURY
    epsilon_sec = @evalpoly(delta_t, 44.836, -46.8495, -0.00429, 0.00181)
    epsilon = deg2rad(23.433333 + epsilon_sec/3600)
    sin_ra, cos_ra = sincos(deg2rad(ra))
    sin_dec, cos_dec = sincos(deg2rad(dec))
    x, y, z = xyz(date)
    time = -499.00522*(cos_dec * cos_ra * x +
                       (tan(epsilon) * sin_dec + cos_dec * sin_ra) * y)
    if diff
        return time
    else
        return date + time / 86400
    end
end

"""
    helio_jd(date, ra, dec[, B1950=true, diff=false]) -> jd_helio
    helio_jd(date, ra, dec[, B1950=true, diff=true]) -> time_diff

### Purpose ###

Convert geocentric (reduced) Julian date to heliocentric Julian date.

### Explanation ###

This procedure corrects for the extra light travel time between the Earth and the
Sun.

An online calculator for this quantity is available at
http://www.physics.sfasu.edu/astro/javascript/hjd.html

Users requiring more precise calculations and documentation should look at the
IDL code available at http://astroutils.astronomy.ohio-state.edu/time/

### Arguments ###

* `date`: reduced Julian date (= JD - 2400000).  You can use `juldate()` to calculate the
  reduced Julian date.
* `ra` and `dec`: right ascension and declination in degrees.  Default equinox is J2000.
* `B1950` (optional boolean keyword): if set to `true`, then input coordinates
  are assumed to be in equinox B1950 coordinates.  Default is `false`.
* `diff` (optional boolean keyword): if set to `true`, the function returns the
  time difference (heliocentric JD - geocentric JD) in seconds.  Default is
  `false`.

### Output ###

The return value depends on the value of `diff` optional keywords:

* if `diff` is `false` (default), then the heliocentric reduced Julian date is
  returned.
* if `diff` is `true`, then the time difference in seconds between the
  geocentric and heliocentric Julian date is returned.

### Example ###

What is the heliocentric Julian date of an observation of V402 Cygni (J2000: RA
= 20 9 7.8, Dec = 37 09 07) taken on June 15, 2016 at 11:40 UT?

```jldoctest
julia> using AstroLib

julia> jd = juldate(2016, 6, 15, 11, 40);

julia> helio_jd(jd, ten(20, 9, 7.8) * 15, ten(37, 9, 7))
57554.98808289718
```

### Notes ###

Wayne Warren (Raytheon ITSS) has compared the results of this algorithm with the
FORTRAN subroutines in the STARLINK SLALIB library (see
http://star-www.rl.ac.uk/).

```
                                                 Time Diff (sec)
     Date               RA(2000)   Dec(2000)  STARLINK      IDL

1999-10-29T00:00:00.0  21 08 25.  -67 22 00.  -59.0        -59.0
1999-10-29T00:00:00.0  02 56 33.4 +00 26 55.  474.1        474.1
1940-12-11T06:55:00.0  07 34 41.9 -00 30 42.  366.3        370.2
1992-02-29T03:15:56.2  12 56 27.4 +42 10 17.  350.8        350.9
2000-03-01T10:26:31.8  14 28 36.7 -20 42 11.  243.7        243.7
2100-02-26T09:18:24.2  08 26 51.7 +85 47 28.  104.0        108.8
```

Code of this function is based on IDL Astronomy User's Library.
"""
helio_jd(date::Real, ra::Real, dec::Real;
         B1950::Bool=false, diff::Bool=false) =
             _helio_jd(promote(float(date), float(ra), float(dec))...,
                       B1950, diff)


text:
__precompile__(true)

module DataUtils

# using Requires
using DataFrames
# import Feather

import Base.convert
import Base.serialize
import Base.deserialize
import Base.Dict

include("utils.jl")
include("tsutils.jl")

include("dfutils.jl")
include("dffilters.jl")
# include("tokenize.jl")

# include("dataframes_compat.jl")
# include("featherwrap.jl")

end # module DataUtils


text:
import Base: +,-,/,*,==,!==

mutable struct Measurement
    Name::AbstractString
    Data::Array
    Labbook::Dict{Any,Any}
end

Base.size(m::Measurement) = size(m.Data)
Base.copy(m::Measurement)  = Measurement(copy(m.Name),copy(m.Data),copy(m.Labbook))

==(m1::Measurement,m2::Measurement) = (m1.Name == m2.Name) && (m1.Data == m2.Data)
!==(m1::Measurement,m2::Measurement) = (m1.Name !== m2.Name) || (m1.Data !== m2.Data)
-(m1::Measurement,m2::Measurement) = m1.Data - m2.Data
+(m1::Measurement,m2::Measurement) = m1.Data + m2.Data
*(m::Measurement,n::Number) = m.Data * n
*(m::Measurement,n::Number) = n * m.Data
/(m::Measurement,n::Number) = m.Data /n
/(m::Measurement,n::Number) = n / m.Data

max_stars_repo_name: lambcount/EC

max_issues_repo_name: lambcount/EC

max_forks_repo_name: lambcount/EC


text:
@testset "TSoft file read" begin
	data = readtsf(joinpath(dirname(@__DIR__),"test","input","tsf_data.tsf"));
	@test size(data) == (10,3)
	@test data[:datetime][1] == DateTime(2016,12,16,00,00,00)
	@test sum(data[2]) == 0.
	@test data[:Measurement1][end] == 0.
	@test data[:Measurement2][4] == 10.
	@test isnan(data[:Measurement2][5])
	units = readtsf(joinpath(dirname(@__DIR__),"test","input","tsf_data.tsf"),unitsonly=true);
	@test size(units) == (2,)
	@test units[1] == "units1"
	@test units[2] == "units2"
end

@testset "TSoft file write" begin
	data = DataFrame(temp=[10.,11.,12.,14.],grav=[9.8123,9.9,NaN,9.7],
	       datetime=[DateTime(2010,1,1,0),DateTime(2010,1,1,1),
	           DateTime(2010,1,1,2),DateTime(2010,1,1,4)]);
	writetsf(data,joinpath(dirname(@__DIR__),"test","output","tsf_data.tsf"),units=["degC","nm/s^2"],
				comment=["first line","second line"],decimal=[1,3]);
	data_read = readdlm(joinpath(dirname(@__DIR__),"test","output","tsf_data.tsf"),skipstart=24);
	@test size(data_read) == (4,8)
	@test data_read[1,end] == 9.812
	@test data_read[2,end] == 9.9
	@test data_read[end,7] == 14.
	@test sum(data_read[3,1:6]) == 2010+1+1+2.
end


text:
using Documenter, YaoCompiler

makedocs(;
    modules = [YaoCompiler],
    format = Documenter.HTML(prettyurls = !("local" in ARGS)),
    pages = [
        "Home" => "index.md",
        "Semantics" => "semantics.md",
        "Compilation" => "compilation.md",
        "References" => "references.md",
    ],
    repo = "https://github.com/QuantumBFS/YaoCompiler.jl",
    sitename = "YaoCompiler.jl",
)

deploydocs(; repo = "github.com/QuantumBFS/YaoCompiler.jl")


text:
@testset "Reddening Av=$Av" for Av = [0.5, 1.0, 2.0]
    # Regression usage
    spec = mock_spectrum()
    spec2 = deepcopy(spec)
    reddened = @inferred redden(spec, Av)
    @inferred redden!(spec2, Av)
    @test reddened.flux ≈ spec2.flux
    @inferred deredden!(spec2, Av)
    @test spec.flux ≈ spec2.flux
    dereddened = @inferred deredden(reddened, Av)
    @test dereddened.flux ≈ spec.flux

    # Custom law
    law(λ, Rv) = sin(Rv * λ) / Rv
    expected = @. spec.flux * 10^(-0.4 * Av * law(spec.wave, π))
    @test expected ≈ redden(spec, Av, law = law, Rv=π).flux

    # Bad law
    @test_throws MethodError redden(spec, Av, law = sin)

    # Unitful
    spec = mock_spectrum(use_units=true)
    spec2 = deepcopy(spec)
    reddened = @inferred redden(spec, Av)
    @inferred redden!(spec2, Av)
    @test reddened.flux ≈ spec2.flux
    @inferred deredden!(spec2, Av)
    @test spec.flux ≈ spec2.flux
    dereddened = @inferred deredden(reddened, Av)
    @test dereddened.flux ≈ spec.flux
end

@testset "Reddening Av=0" begin
    # Test no change when Av = 0
    Av = 0.0
    spec = mock_spectrum()
    reddened = redden(spec, Av)
    @test reddened.flux ≈ spec.flux
    dereddened = deredden(reddened, Av)
    @test dereddened.flux ≈ spec.flux
end


text:
# This file contains code that was formerly a part of Julia. License is MIT: http://julialang.org/license

using SpecialFunctions
using Test
using Base.MathConstants: γ

using SpecialFunctions: AmosException, f64

# useful test functions for relative error, which differ from isapprox
# in that relerrc separately looks at the real and imaginary parts
relerr(z, x) = z == x ? 0.0 : abs(z - x) / abs(x)
relerrc(z, x) = max(relerr(real(z), real(x)), relerr(imag(z), imag(x)))
≅(a,b) = relerrc(a, b) ≤ 1e-13

tests = [
    "bessel",
    "beta_inc",
    "betanc",
    "ellip",
    "erf",
    "gamma_inc",
    "gamma",
    "sincosint",
    "other_tests",
    "owens_t"
]

const testdir = dirname(@__FILE__)

for t in tests
    tp = joinpath(testdir, "$(t).jl")
    @testset "$(t)" begin
        include(tp)
    end
end


text:
module GeophysicalFlows

using
  CUDA,
  FourierFlows,
  Statistics,
  SpecialFunctions

using FFTW: irfft

include("utils.jl")
include("twodnavierstokes.jl")
include("singlelayerqg.jl")
include("barotropicqgql.jl")
include("multilayerqg.jl")
include("surfaceqg.jl")

end # module


text:
# Use baremodule to shave off a few KB from the serialized `.ji` file
baremodule gitoxide_jll
using Base
using Base: UUID
import JLLWrappers

JLLWrappers.@generate_main_file_header("gitoxide")
JLLWrappers.@generate_main_file("gitoxide", UUID("7ab50ac8-3a8c-5d28-9910-0d361883217b"))
end  # module gitoxide_jll


text:
import Celeste.Stripe82Score

function test_score_field()
    results_filename = "celeste-004263-5-0119.jld"

    if !isfile(joinpath(datadir, results_filename))
        results_url = "http://portal.nersc.gov/project/dasrepo/celeste/$results_filename"
        run(`wget --quiet -O $datadir/$results_filename $results_url`)
    end

    rcf = RunCamcolField(4263, 5, 119)
    truthfile = joinpath(datadir, "coadd_for_4263_5_119.fit")
    Stripe82Score.score_field_disk(rcf, datadir, truthfile, datadir)
end

test_score_field()


text:
#= We want to visualize neighborhoods as follows:
 For square-neighborhoods, build a grid of cells of dim x dim. Each cell which corresponds to a feasible move is marked with a circle. The color of the circle represents the objective-delta of the corresponding move. A
=#

visualizemoves(n, m, order, draw_vertex) = enumerationorder(n, m, order, draw_vertex, x->x; cell_width = cell_width, cell_height = cell_height, fname = fname)

"""
    enumerationorder(n, m, order, draw_vertex, draw_edge; cell_width = 20, cell_height = 20)

Draw the enumeration order of a quadratic neighborhood structure on an n x m grid, using draw_vertex and draw_edge to draw the parameters and sequence respectively.
"""
function enumerationorder(n, m, order, draw_vertex, draw_edge; cell_width = 20, cell_height = 20, fname = "enum.svg")
    d = Drawing((n+1)*cell_width, (m+1)*cell_height, fname)
    origin()
    sethue("black")
    setfont("STIX Two Math",12)
    background("white")
    t = Table(n+1, m+1, cell_width, cell_height)
    foreach(i -> settext("$(i-1)", t[i,1], valign = "center", halign="left") ,2:n+1)
    foreach(i -> settext("$(i-1)", t[1,i], valign="top", halign="center"), 2:n+1)
    # Drawing
    ordervertices = map(o -> o .+ (1,1), order)
    foreach(v -> draw_vertex(t[v...],v), ordervertices)
    foreach((s,d) -> draw_edge(t[s...], t[d...],s, d), ordervertices[1:end-1], ordervertices[2:end])
    finish()
    preview()
end

function drawgrid(t, cell_height, cell_width)
    rows = Iterators.zip(t[1,:] .- Point(0,cell_height ÷ 2), t[n,:] .+ Point(0, cell_height ÷ 2))
    cols = Iterators.zip(t[:,1] .- Point(cell_width ÷ 2, 0), t[:,m] .+ Point(cell_width ÷ 2, 0))
    sethue("grey")
    setline(1)
    foreach(r -> line(r..., :stroke), rows)
    foreach(c -> line(c..., :stroke), cols)
    sethue("black")
end

function draw_param(p, i; color = "black", action=:fill)
    sethue(color)
    ellipse(p, 3, 3, action)
    sethue("black")
end

function draw_order(p1, p2, s , d; color="black")
    sethue(color)
    arrow(p1, p2, arrowheadlength=7, arrowheadangle=π/10, linewidth=1)
end

##
#=

scaler(xmax, maxval) = x -> x * maxval / xmax

function visualize(N, state, problem; width = 400, height = 400, active = identity(N))
    ΔN = Δ(N, state, problem)
    vmin = abs(minimum(ΔN))
    vmax = abs(maximum(ΔN))
    cellheight, cellwidth = (height, width) ./ dims(ΔN)
    scaled = scaler(max(vmin, vmax), min(cellheight,cellwidth))

    for (i, p) in Table(dims(ΔN)..., width, height)
        if isimproving(ΔN[i], state, objective(problem))
            setcolor("green")
        elseif isequal(ΔN[i], objective(problem))
            setcolor("red")
        end
        circle(p, scaled(ΔN[i]), :fill)
    end
    if !isidentity(active)
        rectangle(t[ϕ(active)...], )
    end
end

# Attention: indexing below is inversed over the operator-parameters. I think this is due to Luxor using a row-major implementation.

function visualize_order(N::AbstractNeighborhood, n_dim; bgcolor="transparent", width = 400, height = 400, filename ="order.png")
    d = Drawing(width, height, filename)
    bgcolor != "transparent" && background(bgcolor)
    origin()
    t = drawgrid(n_dim; width = width, height = height)
    draworder(t, N)
    finish()
    preview()
end

function drawgrid(ndim; width = 400, height = 400, linecolor = "grey", textcolor = "black", fface="Computer Modern", fsize=12)
    maxdim = ndim + 1
    t = Table(maxdim, maxdim, width/maxdim, height/maxdim)
    for i in 2:maxdim
        sethue(linecolor)
        line(t[1,i] + Point(0, fsize/2), t[maxdim, i], :stroke)
        line(t[i,1]+Point(fsize/2, 0), t[i, maxdim], :stroke)
        sethue(textcolor)
        text( "$(i-1)", t[1,i], halign = :center, valign = :middle)
        text( "$(i-1)", t[i,1], halign = :center, valign = :middle)
    end
    return t
end

function draworder(t, iter; arrowcolor = "black")
    sethue(arrowcolor)
    prev = first(iter)
    transform =  m -> (ϕ(m)[2] + 1, ϕ(m)[1] + 1)
    circle(t[transform(prev)...], 5, :fill)
    for (i,m) in enumerate(iter)
        if i > 1
            arrow(t[transform(prev)...], t[transform(m)...], arrowheadangle = π/8, arrowheadlength = 5 )
        end
        prev = m
    end
    circle(t[transform(prev)...], 5, :fill)
end

# Sticking together a couple of neighborhood-orders (The specifics of what is being visualized will have to be abstracted out for later use in other visualizations...)

function visualize_order(neighborhood_set::Array; filename="composite_neighborhood.png", cell_width = 400, cell_height=400)
    images = []
    nmax = maximum(dimension.(neighborhood_set))
    for (i,N) in enumerate(neighborhood_set)
        Nw = dimension(N)/nmax * cell_width
        Nh = dimension(N)/nmax * cell_height
        push!(images, visualize_order(N, dimension(N), filename = "neigh_$(i).png", width = Nw, height = Nh))
    end
    Drawing(cell_width*size(neighborhood_set, 1), cell_height*size(neighborhood_set,2), filename)
    origin()
    t = Table(size(neighborhood_set)..., cell_width, cell_height)
    for (i,cell) in enumerate(t)
        placeimage(readpng(images[i].filename), cell[1].x, cell[1].y; centered = true)
    end
    finish()
    preview()
end
=#

max_stars_repo_name: Michiel-VL/PolyaViz

max_issues_repo_name: Michiel-VL/PolyaViz


text:
using HaloMF
using HCubature
using Plots
Δm = 200
println("Δm = ", Δm)
A(Δm) = 1 + 0.24log10(Δm) * exp(-(4 / log10(Δm))^4)
a(Δm) = 0.44log10(Δm) - 0.88
C(Δm) = 0.019 + 0.107log10(Δm) + 0.19 * exp(-(4 / log10(Δm))^4)
B, b, c = 0.183, 1.5, 2.4
δc = 1.686
bν(lnν) =
   1 - A(Δm) * exp(0.5 * a(Δm) * lnν) / (exp(0.5 * a(Δm) * lnν) + δc^a(Δm)) +
   B * exp(0.5 * b * lnν) +
   C(Δm) * exp(0.5 * c * lnν)
f0(x) = tinker10MF(x, 0, Δm)
norm1, err = hquadrature(f0, -50, 5)
println("Normalisation(MF) = ", norm1)
f1(x) = tinker10MF(x, 0, Δm) * bν(x)
norm2, err = hquadrature(f1, -50, 5)
println("Normalisation(Bias) = ", norm2)
# %% Plot b(ν)
x = -2:0.05:2
Δm = 200
plot(
   log10.(exp.(x)),
   log10.(bν.(x)),
   xlim = [-0.5, 0.6],
   ylim = [-0.5, 1.2],
   xlabel = "log10(ν)",
   ylabel = "log10(b)",
   ls = :dash,
)
Δm = 1600
plot!(log10.(exp.(x)), log10.(bν.(x)))


text:
module ExampleHelpers
##
# This module just collects together random stuff that's helpul
# in creating unit tests and visualisations, such as things to create an example household,
# make someone disabled, unemployed and so on. None of it is very rigorous and likely
# shouldn't be used in a proper model simulation run.
##

using Dates

using ScottishTaxBenefitModel
using .ModelHousehold
using .ExampleHouseholdGetter
using .EquivalenceScales
using .Definitions
using .Utils

export

    add_child!,
    add_non_dependent!,
    add_spouse!,
    age_now,
    blind!,
    carer!,
    crude_construct_hh,
    deafen!,
    delete_child!,
    delete_person!,
    disable_seriously!,
    disable_slightly!,
    employ!,
    enable!,
    get_example,
    get_all_examples,
    make_hh,
    makePID,
    retire!,
    set_childrens_ages!,
    unblind!,
    uncarer!,
    undefen!,
    unemploy!

export SS_Examples, cpl_w_2_children_hh, single_parent_hh, single_hh, childless_couple_hh, mbu

@enum SS_Examples cpl_w_2_children_hh single_parent_hh single_hh childless_couple_hh mbu

"""

"""
function get_ss_examples()::Dict{SS_Examples, Household}
    d = Dict{SS_Examples, Household}()
    @time names = ExampleHouseholdGetter.initialise()
    d[cpl_w_2_children_hh] = ExampleHouseholdGetter.get_household( "example_hh1" )
    d[single_parent_hh] = ExampleHouseholdGetter.get_household( "single_parent_1" )
    d[single_hh] = ExampleHouseholdGetter.get_household( "example_hh2" )
    d[childless_couple_hh] = ExampleHouseholdGetter.get_household("mel_c2_scot")
    d[mbu] =  ExampleHouseholdGetter.get_household("mbu_example")
    return d
end

const EXAMPLES = get_ss_examples()

function get_example( which :: SS_Examples ) :: Household
   return deepcopy(EXAMPLES[ which ])
end

function get_all_examples()
   return deepcopy( EXAMPLES )
end

const SPARE_CHILD = get_example(cpl_w_2_children_hh).people[320190000104]
const SPARE_ADULT = get_head( get_example(single_hh))

function unemploy!( pers::Person )
    pers.usual_hours_worked = 0
    pers.actual_hours_worked = 0
    pers.employment_status = Unemployed
    delete!( pers.income, wages )
    delete!( pers.income, self_employment_income )
 end

 function employ!( pers::Person, wage=600.00 )
    pers.usual_hours_worked = 40
    pers.actual_hours_worked = 40
    pers.employment_status = Full_time_Employee
    pers.income[wages] = wage
 end

 function disable_slightly!( pers::Person )
    pers.employment_status = Permanently_sick_or_disabled
    pers.health_status = Bad
    pers.has_long_standing_illness = true
    pers.adls_are_reduced = reduced_a_little
    pers.how_long_adls_reduced = v_12_months_or_more
    pers.disabilities[mobility] = true
    pers.disabilities[stamina] = true
 end

 function disable_seriously!( pers::Person )
    pers.employment_status = Permanently_sick_or_disabled
    pers.health_status = Very_Bad
    pers.has_long_standing_illness = true
    pers.adls_are_reduced = reduced_a_lot
    pers.how_long_adls_reduced = v_12_months_or_more
    pers.disabilities[mobility] = true
    pers.disabilities[stamina] = true
 end

 function enable!( pers::Person )
    pers.dla_mobility_type = missing_lmh
    pers.dla_self_care_type = missing_lmh
    pers.pip_mobility_type = no_pip
    pers.pip_daily_living_type = no_pip
    pers.health_status = Good
    pers.has_long_standing_illness = false
    pers.adls_are_reduced = not_reduced
    pers.how_long_adls_reduced = Missing_Illness_Length
    pers.disabilities = Disability_Dict{Bool}()
 end

 function blind!( pers :: Person )
    pers.disabilities[vision ] = true
    pers.registered_blind = true
 end

 function unblind!( pers :: Person )
    delete!(pers.disabilities, vision )
    pers.registered_blind = false
 end

 function deafen!( pers :: Person )
    pers.disabilities[ hearing ] = true
    pers.registered_deaf = true
 end

 function undeafen!( pers :: Person )
    delete!(pers.disabilities, hearing )
    pers.registered_deaf = false
 end

 function carer!( pers :: Person )
    pers.income[carers_allowance] = 100.0
    pers.is_informal_carer = true
    pers.hours_of_care_given = 10
    pers.employment_status = Looking_after_family_or_home
 end

 function uncarer!( pers :: Person )
    delete!(pers.income,carers_allowance)
    pers.is_informal_carer = false
    pers.hours_of_care_given = 0
 end

 function retire!( pers :: Person )
    pers.usual_hours_worked = 0
    pers.employment_status = Retired
 end

 # FIXME relationships fixup
 """
 Add a child to the 1st benefit unit
 """
 function add_child!( hh :: Household, age :: Integer, sex :: Sex )::BigInt
    head = get_head(hh)
    np = deepcopy( SPARE_CHILD )
    empty!( np.income )
    np.relationships[head.pid] = Son_or_daughter_incl_adopted
    # TODO fill in other relationships
    np.default_benefit_unit = head.default_benefit_unit
    np.pid = maximum( keys( hh.people ))+1
    np.age = age
    np.sex = sex
    hh.people[ np.pid ] = np
    head.relationships[np.pid] = Parent
    spouse = get_spouse( hh )
    if spouse !== nothing
       spouse.relationships[np.pid] = Parent
       np.relationships[spouse.pid] = Son_or_daughter_incl_adopted
    end
    # FIXME other adults in othe BUS
    make_eq_scales!( hh )
    return np.pid
 end

 function add_non_dependent!(
    hh  :: Household,
    age :: Integer,
    sex :: Sex ) :: BigInt

    head = get_head(hh)
    np = deepcopy( SPARE_ADULT )
    bus = get_benefit_units( hh )
    nbus = size(bus)[1]
    np.pid = maximum( keys( hh.people ))+1
    np.relationships[head.pid] = Son_or_daughter_incl_adopted
    # TODO fill in other relationships
    np.age = age
    np.sex = sex
    np.default_benefit_unit = nbus + 1
    hh.people[ np.pid ] = np
    bus = get_benefit_units( hh )
    nnbus = size(bus)[1]
    @assert nnbus == nbus + 1
    @assert get_head( bus[nnbus] ) == np
    make_eq_scales!( hh )
    return np.pid
 end

 function add_spouse!(
   hh  :: Household,
   age :: Integer,
   sex :: Sex;
   buno :: Int = 1 ) :: BigInt

   np = deepcopy( SPARE_ADULT )
   bus = get_benefit_units( hh )
   bu = bus[buno]
   nbus = size(bus)[1]
   head = get_head(bu)
   @assert get_spouse( bu ) === nothing "Spouse already exists for bu $buno"

   np.pid = maximum( keys( hh.people ))+1
   np.relationships[head.pid] = Spouse
   head.relationships[np.pid] = Spouse
   for pid in bu.children
      ch = bu.people[pid]
      np.relationships[pid] = Parent
      ch.relationships[np.pid] = Son_or_daughter_incl_adopted
   end

   # TODO fill in other relationships

   np.age = age
   np.sex = sex
   np.default_benefit_unit = buno
   hh.people[ np.pid ] = np
   bus = get_benefit_units( hh )
   nnbus = size(bus)[1]
   @assert nnbus == nbus
   make_eq_scales!( hh )
   return np.pid
end

 function delete_person!( hh :: Household, pid :: BigInt )
    delete!( hh.people, pid )
    make_eq_scales!( hh )
 end

 function delete_child!( hh :: Household )
    chpids = child_pids( hh )
    if size(chpids)[1] > 0
       delete_person!( hh, chpids[1])
    end
    make_eq_scales!( hh )
 end

 function set_childrens_ages!( hh :: Household, ages ... )
    nc = length(ages)[1]
    nset = 0
    for (pid, pers) in hh.people
       if is_child(pers)
          nset = min( nc, nset+1)
          pers.age = ages[nset]
       end
    end
 end

"""

"""
function make_hh(
    ;
    adults   :: Int = 1,
    children :: Int = 0,
    earnings :: Real = -1,
    rent     :: Real = -1,
    rooms    :: Int  = 4,
    age      :: Int = -1,
    spouse_age :: Int = -1,
    tenure   :: Tenure_Type = Private_Rented_Furnished ) :: Household
    hh = nothing
    if adults == 2
       if children > 0
          hh = get_example( cpl_w_2_children_hh )
       else
          hh = get_example( childless_couple_hh )
       end
    elseif adults == 1
       if children > 0
          hh = get_example( single_parent_hh )
       else
          hh = get_example( single_hh )
       end
    else
       error("can't do $adults adults yet")
    end
    hh.tenure = tenure
    hh.ct_band = Band_B
    num_kids = num_children( hh )
    if num_kids < children
       for i in (num_kids+1):children
          sex = (i % 2) == 0 ? Male : Female
          add_child!( hh, i, sex ) # use the counter as age
       end
    elseif num_kids > children
       delete_child!( hh )
    end
    nc = num_children( hh )
    na = num_adults( hh )
    @assert nc == children "num_childen=$nc but requested=$children"
    @assert na == adults "num_adults=$na but requested=$adults"
    head = get_head( hh )
    if age != -1
       head.age = age
    end
    if spouse_age != -1
       @assert na == 2 "need 2 adults for spouse age to be meaningful"
       sp = get_spouse( hh )
       sp.age = spouse_age
    end
    if earnings != -1
       head.income[wages] = earnings
    end
    if rent != -1
       hh.gross_rent = rent
    end
    make_eq_scales!( hh )
    return hh
 end

 #
 # quickie for making a default-ish pid
 #
 function makePID( hid::Int, year = 2018, pno=1 )::BigInt
    get_pid( FRS, year, hid, pno )
 end

 """
 Really, really really crude, suitable for interactive use only.

 Retrieve one of the model's example households & overwrite a few fields
 to make things simpler.
 """
 function crude_construct_hh(
    tenure    :: AbstractString, # 'private|council|owner
    bedrooms  :: Integer,
    hcost     :: Real,
    marrstat  :: AbstractString, # 'couple'|'single'
    chu5      :: Integer,
    ch5p      :: Integer ) :: Household
    hh = get_example( single_hh )
    head = get_head(hh)
    head.age = 30
    sp = get_spouse(hh)
    enable!(head) # clear dla stuff from example
    hh.tenure = if tenure == "private"
       Private_Rented_Unfurnished
    elseif tenure == "council"
       Council_Rented
    elseif tenure == "owner"
       Mortgaged_Or_Shared
    else
       @assert false "$tenure not recognised"
    end
    hh.bedrooms = bedrooms
    hh.other_housing_charges = hh.water_and_sewerage = 0
    if hh.tenure == Mortgaged_Or_Shared
       hh.mortgage_payment = hcost
       hh.mortgage_interest = hcost
       hh.gross_rent = 0
    else
       hh.mortgage_payment = 0
       hh.mortgage_interest = 0
       hh.gross_rent = hcost
    end
    if marrstat == "couple"
       sex = head.sex == Male ? Female : Male # hetero ..
       add_spouse!( hh, 30, sex )
       sp = get_spouse(hh)
       enable!(sp)
       set_wage!( sp, 0, 10 )
    end
    age = 0
    for ch in 1:chu5
       sex = ch % 1 == 0 ? Male : Female
       age += 1
       add_child!( hh, age, sex )
    end
    age = 7
    for ch in 1:ch5p
       sex = ch % 1 == 0 ? Male : Female
       age += 1
       add_child!( hh, age, sex )
    end
    set_wage!( head, 0, 10 )
    for (pid,pers) in hh.people
       # println( "age=$(pers.age) empstat=$(pers.employment_status) " )
       empty!( pers.income )
       empty!( pers.assets )
    end
    return hh
 end

end # module


text:
using SimpleWeightedGraphs
include("bijection_map.jl")

function edges_from_rule(rule_string)
    # rules are like this: light red bags contain 1 bright white bag, 2 muted yellow bags.
    parent_bag_string, other_bags_string = split(rule_string, "contain")
    parent_bag = strip(split(parent_bag_string, "bag")[1])
    other_bags_descriptions = split(other_bags_string, ",")

    edges = []
    for children_bag_description in split(other_bags_string, ",")
        child_bag_with_count = strip(split(children_bag_description, "bag")[1])

        # special case: handle no other
        if occursin("no other", child_bag_with_count)
            return [(parent_bag, nothing, 0)]
        end

        child_bag_count = parse(Int32, child_bag_with_count[1])
        child_bag = strip(child_bag_with_count[2:end])

        push!(edges, (parent_bag, child_bag, child_bag_count))
    end
    edges
end

function add_nodes_and_ids!(nodes_to_ids, node)
    if node === nothing
        return
    end

    node = String(node)
    if !haskey(nodes_to_ids, node)
        node_id = length(nodes_to_ids) + 1
        nodes_to_ids[node] = node_id
    end
end

function get_edges_and_nodes(input_file)
    edges, nodes_to_ids = open(input_file) do file
        file_string = read(file, String)
        rules = split(file_string, "\r\n")

        # note - Julia doesn't have bidicts... annoying.
        # also annoying - Julia graphs require you to use integers
        # for nodes.

        edges = []
        nodes_to_ids = BiDict{String,Int64}()
        for rule in rules
            rule_edges = edges_from_rule(rule)
            for edge in rule_edges
                node_1, node_2, edge_weight = edge
                add_nodes_and_ids!(nodes_to_ids, node_1)
                add_nodes_and_ids!(nodes_to_ids, node_2)
            end
            # println(edge_rules)
            append!(edges, rule_edges)
            # println("edges: $edges")
        end
        edges, nodes_to_ids
    end
    edges, nodes_to_ids
end

function build_graph(edges, nodes_to_ids)
    num_nodes = length(nodes_to_ids)
    g = SimpleWeightedDiGraph(num_nodes)
    for (n1, n2, num_bags) in edges
        if !(n2 === nothing)
            id1, id2 = nodes_to_ids[String(n1)], nodes_to_ids[String(n2)]
            # println("edge from: ($n1 $id1) to ($n2 $id2)")
            add_edge!(g, id1, id2, num_bags)
        end
    end
    println("number of vertex: $(nv(g))")
    println("number of edges: $(ne(g))")
    g
end

function find_parent_bags(g, nodes_to_ids, target_node)

    target_node_id = nodes_to_ids[String(target_node)]
    println("target_node: $target_node node_id: $target_node_id")
    all_parent_nodes = []
    for (node_name, node_id) in nodes_to_ids.key_to_value
        if (node_id != target_node_id) && (has_path(g, node_id, target_node_id))
            push!(all_parent_nodes, node_name)
        end
    end
    println("all bags: $all_parent_nodes")
    println("num bags: $(length(all_parent_nodes))")
end

function calculate_costs(g::AbstractGraph{T}, s::Integer, node_cost::Float64) where {T}
    nbs = outneighbors(g, s)
    println("Source: $s nbs: $(collect(nbs))")
    for n in nbs
        node_cost += calculate_costs(g, n, 1.0) * g.weights[n, s]
        println("Source: $s Node: $n edge weight: $(g.weights[n, s]) total cost so far: $node_cost")
    end
    node_cost
end

function part1_sol()
    edges_tuple, nodes_to_ids = get_edges_and_nodes("day7_input.txt")
    g = build_graph(edges_tuple, nodes_to_ids)
    find_parent_bags(g, nodes_to_ids, "shiny gold")
    return g
end

function part2_sol()
    edges_tuple, nodes_to_ids = get_edges_and_nodes("day7_input.txt")
    g = build_graph(edges_tuple, nodes_to_ids)

    start_node_id = nodes_to_ids[String("shiny gold")]
    calculate_costs(g, start_node_id, 0.0)
end

part2_sol()


text:
#-----------------------------------------------------------------------------------
# Dispatch.Structure;
#-----------------------------------------------------------------------------------
import ..Dispatch.Structure: MetaMethod, MetaMethodTable, MetaMethodError

"""
`MetaMethod` associates a pattern tree to a function. They populate
`MetaMethodTable`s.

"""
MetaMethod;

"""
`MetaMethodTable`s are collections of `MetaMethod`s, they associate
each one with both a index and a label.

Relevant functions:
- `getmethod`
- `newmethod!`
- `removemethod!`
- `prefermethod!`

"""
MetaMethodTable;

"""
`MetaMethodError`

Error that is thrown when a method is not found in a `MetaMethodTable`.

"""
MetaMethodError;

#-----------------------------------------------------------------------------------
# Dispatch.TableManipulation;
#-----------------------------------------------------------------------------------
import ..Dispatch.TableManipulation: getmethod, newmethod!, removemethod!, prefermethod!, whichmethod,
                                     methodconflicts, set_conflict_warnings

"""
`getmethod(table, parameters) -> MetaMethod`

Find the method whose pattern matches the given parameters.
Throws a `MetaMethodError` if no method is found.

"""
getmethod;

"""
`newmethod!(table, pattern, body, mod[, label])`

Creates a new method in `table` that matches `pattern` and executes `body`.
Also takes a module that will be used in the evaluation of `pattern` and `body`.
An optionally given `label` will be associated with the new method, so that it
can be accessed with `table.labels[label]`.

"""
newmethod!;

"""
`removemethod!(table, label)`

Removes the method associated with `label` from `table`.

`removemethod!(table, pattern)`

Same as above, but associates the method with a pattern instead.

"""
removemethod!;

"""
`prefermethod!(table, label1, label2)`

Gives priority to the method associated with `label1` over the one associated with `label2`.
Used to resolve ambiguities between conflicting methods. Will print a warning if the
methods passed don't conflict.

`prefermethod!(table, pattern1, pattern2)`

Same as above, but associates the methods with the given patterns instead.

"""
prefermethod!;

"""
`whichmethod(table, parameters)`

Same as `getmethod`, but doesn't throw an error if no method is found.

"""
whichmethod;

"""
`methodconflicts(table)`

Finds and prints any conflict between the methods in `table`.

"""
methodconflicts;

"""
`set_conflict_warnings(Symbol)`

Sets the behaviour of conflict warnings.

| option       | meaning                                                          |
|:-------------|:-----------------------------------------------------------------|
|`:yes`        | Will always print a warning if a new method introduces conflicts.|
|`:interactive`| Only prints warnings in interactive mode.                        |
|`:no`         | Never print conflict warnings.                                   |

The default is `:interactive`.

"""
set_conflict_warnings;

#-----------------------------------------------------------------------------------
# Dispatch.TopMetaTables;
#-----------------------------------------------------------------------------------
import ..Dispatch.TopMetaTables: TopMetaTable,  init_module_table!, init_metatable!, get_metatable, import_metatable!

"""
`TopMetaTable`s keeps track of a collection of `MetaMethodTable`s for each module.
They are used to implement `@macromethod` and `@metafunction`.

"""
TopMetaTable;

"""
`init_module_table!(toptable, mod)`

Initializes the table collection for the module `mod`.

"""
init_module_table!;

"""
`init_metatable!(toptable, mod, key, name) -> MetaMethodTable`

Initializes a metatable, putting it into `toptable[mod][key]`.
Calls `init_module_table!(table, mod)` before doing anything else.

"""
init_metatable!;

"""
`get_metatable(toptable, mod, key) -> MetaMethodTable`

Finds the metatable associated with the symbol `key` and the module `mod`.
If no table is found, throw a `MetaTableNotFoundError`.
"""
get_metatable;

"""
`import_metatable(toptable, key, from[, to=current_module()])`

Associates a metatable to a new module.

"""
import_metatable;

#-----------------------------------------------------------------------------------
# Dispatch.Applications;
#-----------------------------------------------------------------------------------
import ..Dispatch.Applications: @macromethod, @metafunction, @metadestruct, @metadispatch

"""
`@macromethod name(patterns...) body`
`@macromethod name(patterns...) = body`

Creates a extensible macro that matches and destructures the given patterns.

For examples see the [`/examples`](../../examples) directory or the [dispatch tests](../../test/dispatch.jl).
"""
:@macromethod;

"""
`@metafunction name(patterns...) body`
`@metafunction name(patterns...) = body`

Creates a function that dispatches on expression patterns.

For examples see the [`/examples`](../../examples) directory or the [dispatch tests](../../test/dispatch.jl).

"""
:@metafunction;

"""
`@metadestruct let ...;  ... end`
`@metadestruct macro m(...) ... end`
`@metadestruct (...,) -> ...`
`@metadestruct f(...) = ...`
`@metadestruct function f(...) ... end`

Adds expression destructuring to its parameter.

Related:
- `@letds`
- `@macrods`
- `@anonds`
- `@funds`

"""
:@metadestruct;

"""
`@metadispatch macro m(...) ... end`
`@metadispatch function f(...) ... end`
`@metadispatch f(...) = ...`

Adds expression destructuring and dispatch to its parameter.

Related:
- `@macromethod`
- `@metafunction`

"""
:@metadispatch;

#-----------------------------------------------------------------------------------
# Dispatch.MetaModule;
#-----------------------------------------------------------------------------------
import ..Dispatch.MetaModule: @metamodule

"""
`@metamodule import Module.Path.name`

Import the metatable `name` from `Module.Path`. This allows the metatable to
be extended with new metamethods.

example:
```
module A
using ExpressionPatterns.Dispatch
  @macromethod f(x) 1
end

module B
using ExpressionPatterns.Dispatch
  @metamodule import ..A.@f
  @macromethod f(x,y) 2
end

A.@f(x)   == 1
A.@f(x,y) == 2

```

`@metamodule export name`

Exports the metatable `name` from the current module M so that `@metamodule importall M` will import it.

`@metamodule importall Module.Path`

Import all exported metatables from `Module.Path`.

"""
:@metamodule;


text:
using InfiniteArrays, FillArrays, BlockArrays, BlockBandedMatrices

Δ = mortar(Tridiagonal(Vcat([ones(2,1)],Fill([1.0 0; 0.0 1.0],∞)), Vcat([zeros(1,1)],Fill(zeros(2,2),∞)), Vcat([ones(1,2)],Fill([1.0 0; 0.0 1.0],∞))))

Vcat([ones(2,1)],Fill([1.0 0; 0.0 1.0],∞))
Vcat(zeros(1,1),Fill(zeros(2,2),∞))
Vcat(ones(1,2),Fill([1.0 0; 0.0 1.0],∞))[


text:
## Fallback

face(s::T, i) where {T} = error("face not implemented for type $T")

nv(::Type{T}) where {T} = error("nv not implemented for type $T")

## Tuple implementation

# From deleteat method in StaticArrays
@generated function face(vec::NTuple{N, Any}, index) where {N}
    newlen = N - 1
    exprs = [:(ifelse($i < index, vec[$i], vec[$i+1])) for i = 1:newlen]
    return quote
        Base.@_propagate_inbounds_meta
        @boundscheck if (index < 1 || index > $N)
            throw(BoundsError(vec, index))
        end
        @inbounds return tuple($(exprs...))
    end
end

nv(::Type{<:NTuple{N, Any}}) where {N} = N


text:
import Base: det, logdet, LowerTriangular, UpperTriangular
export det, logdet, LowerTriangular, UpperTriangular

for (ctor, ctor_sym, T, T_sym) in zip([:LowerTriangular, :UpperTriangular],
                               [:(:(Base.LowerTriangular)), :(:(Base.UpperTriangular))],
                               [:(LowerTriangular{<:Real}), :(UpperTriangular{<:Real})],
                               [:(:(LowerTriangular{<:Real})), :(:(UpperTriangular{<:Real}))])

    @eval begin

    push!(ops, DiffOp($ctor_sym, :(Tuple{DLA.AM}), [true]))
    ∇(::Type{$ctor}, ::Arg1, p, Y::$T, Ȳ::$T, X::AM) = full(Ȳ)
    ∇(X̄::AM, ::Type{$ctor}, ::Arg1, p, Y::$T, Ȳ::$T, X::AM) = broadcast!(+, X̄, X̄, Ȳ)

    push!(ops, DiffOp(:(Base.det), Expr(:curly, :Tuple, $T_sym), [true]))
    ∇(::typeof(det), ::Arg1, p, y::Real, ȳ::Real, X::$T) =
        Diagonal(ȳ .* y ./ view(X, diagind(X)))

    # Optimisation for in-place updates.
    function ∇(X̄::AM, ::typeof(det), ::Arg1, p, y::Real, ȳ::Real, X::$T)
        X̄_diag = view(X̄, diagind(X̄))
        broadcast!((x̄, x, y, ȳ)->x̄ + ȳ * y / x,
                   X̄_diag, X̄_diag, view(X, diagind(X)), y, ȳ)
        return X̄
    end

    # Optimisation for in-place updates to `Diagonal` sensitivity cache.
    function ∇(X̄::Diagonal, ::typeof(det), ::Arg1, p, y::Real, ȳ::Real, X::$T)
        X̄.diag .+= ȳ .* y ./ view(X, diagind(X))
        return X̄
    end

    push!(ops, DiffOp(:(Base.logdet), Expr(:curly, :Tuple, $T_sym), [true]))
    ∇(::typeof(logdet), ::Arg1, p, y::Real, ȳ::Real, X::$T) =
        Diagonal(ȳ ./ view(X, diagind(X)))

    # Optimisation for in-place updates.
    function ∇(X̄::AM, ::typeof(logdet), ::Arg1, p, y::Real, ȳ::Real, X::$T)
        X̄_diag = view(X̄, diagind(X̄))
        broadcast!((x̄, x, ȳ)->x̄ + ȳ / x, X̄_diag, X̄_diag, view(X, diagind(X)), ȳ)
        return X̄
    end

    # Optimisation for in-place updates to `Diagonal` sensitivity cache.
    function ∇(X̄::Diagonal, ::typeof(logdet), ::Arg1, p, y::Real, ȳ::Real, X::$T)
        X̄.diag .+= ȳ ./ view(X, diagind(X))
        return X̄
    end

    end
end