text:
module Example

using Glimmer, Glimmer.FlexUI
using Colors
using StaticArrays
import Markdown as MD

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

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

expansion_panel_style = "margin:0.2em;"
expansion_panel_style = "margin:0.4em; border: 0.5px solid lightgray!important; border-radius: 10px !important;"
expansion_panel_header_style = "font-weight: bold;" # "border: 1px solid lightgray!important;"
expansion_panel_subtitle_style = "position: absolute; padding-left: 30%;"

# ---------------------------------------------------------------
# prepare some data for the grids
# ---------------------------------------------------------------
mlb_data_json = "[{\"Name\":\"Adam Donachie\",\"Team\":\"ANA\",\"Position\":\"Catcher\",\"Height(inches)\":74,\"Weight(lbs)\":180,\"Age\":22.99},{\"Name\":\"Paul Bako\",\"Team\":\"SEA\",\"Position\":\"Catcher\",\"Height(inches)\":74,\"Weight(lbs)\":215,\"Age\":34.69},{\"Name\":\"Ramon Hernandez\",\"Team\":\"BOS\",\"Position\":\"Catcher\",\"Height(inches)\":72,\"Weight(lbs)\":210,\"Age\":30.78},{\"Name\":\"Kevin Millar\",\"Team\":\"BAL\",\"Position\":\"First Baseman\",\"Height(inches)\":72,\"Weight(lbs)\":210,\"Age\":35.43},{\"Name\":\"Chris Gomez\",\"Team\":\"BAL\",\"Position\":\"First Baseman\",\"Height(inches)\":73,\"Weight(lbs)\":188,\"Age\":35.71},{\"Name\":\"Brian Roberts\",\"Team\":\"BAL\",\"Position\":\"Second Baseman\",\"Height(inches)\":69,\"Weight(lbs)\":176,\"Age\":29.39},{\"Name\":\"Miguel Tejada\",\"Team\":\"BAL\",\"Position\":\"Shortstop\",\"Height(inches)\":69,\"Weight(lbs)\":209,\"Age\":30.77},{\"Name\":\"Melvin Mora\",\"Team\":\"BAL\",\"Position\":\"Third Baseman\",\"Height(inches)\":71,\"Weight(lbs)\":200,\"Age\":35.07},{\"Name\":\"Aubrey Huff\",\"Team\":\"BAL\",\"Position\":\"Third Baseman\",\"Height(inches)\":76,\"Weight(lbs)\":231,\"Age\":30.19},{\"Name\":\"Adam Stern\",\"Team\":\"BAL\",\"Position\":\"Outfielder\",\"Height(inches)\":71,\"Weight(lbs)\":180,\"Age\":27.05},{\"Name\":\"Jeff Fiorentino\",\"Team\":\"BAL\",\"Position\":\"Outfielder\",\"Height(inches)\":73,\"Weight(lbs)\":188,\"Age\":23.88},{\"Name\":\"Freddie Bynum\",\"Team\":\"BAL\",\"Position\":\"Outfielder\",\"Height(inches)\":73,\"Weight(lbs)\":180,\"Age\":26.96},{\"Name\":\"Nick Markakis\",\"Team\":\"BAL\",\"Position\":\"Outfielder\",\"Height(inches)\":74,\"Weight(lbs)\":185,\"Age\":23.29},{\"Name\":\"Brandon Fahey\",\"Team\":\"BAL\",\"Position\":\"Outfielder\",\"Height(inches)\":74,\"Weight(lbs)\":160,\"Age\":26.11},{\"Name\":\"Corey Patterson\",\"Team\":\"BAL\",\"Position\":\"Outfielder\",\"Height(inches)\":69,\"Weight(lbs)\":180,\"Age\":27.55},{\"Name\":\"Jay Payton\",\"Team\":\"BAL\",\"Position\":\"Outfielder\",\"Height(inches)\":70,\"Weight(lbs)\":185,\"Age\":34.27},{\"Name\":\"Jay Gibbons\",\"Team\":\"BAL\",\"Position\":\"Designated Hitter\",\"Height(inches)\":72,\"Weight(lbs)\":197,\"Age\":30.0},{\"Name\":\"Erik Bedard\",\"Team\":\"BAL\",\"Position\":\"Starting Pitcher\",\"Height(inches)\":73,\"Weight(lbs)\":189,\"Age\":27.99},{\"Name\":\"Hayden Penn\",\"Team\":\"BAL\",\"Position\":\"Starting Pitcher\",\"Height(inches)\":75,\"Weight(lbs)\":185,\"Age\":22.38},{\"Name\":\"Adam Loewen\",\"Team\":\"BAL\",\"Position\":\"Starting Pitcher\",\"Height(inches)\":78,\"Weight(lbs)\":219,\"Age\":22.89}]"
mlb_data_table = GridUtils.toJSONTable(mlb_data_json)

countries_data_json = "[{\"Population\":\"30M\",\"ParentID\":-1,\"Type\":\"Country\",\"Name\":\"USA\",\"ID\":1},{\"Population\":\"250K \",\"ParentID\":1,\"Type\":\"City\",\"Name\":\"Seattle\",\"ID\":2},{\"Population\":\"600K \",\"ParentID\":1,\"Type\":\"City\",\"Name\":\"Boston\",\"ID\":3},{\"Population\":\"2M \",\"ParentID\":1,\"Type\":\"City\",\"Name\":\"New-York\",\"ID\":4},{\"Population\":\"250 people \",\"ParentID\":1,\"Type\":\"City\",\"Name\":\"Redmond\",\"ID\":5},{\"Population\":\"3 on week days\",\"ParentID\":5,\"Type\":\"Place\",\"Name\":\"City Center\",\"ID\":6},{\"Population\":\"0.5 during covid\",\"ParentID\":5,\"Type\":\"Place\",\"Name\":\"MS Campus\",\"ID\":7},{\"Population\":\"35M 24/7\",\"ParentID\":5,\"Type\":\"Place\",\"Name\":\"River Trail\",\"ID\":8},{\"Population\":\"20M\",\"ParentID\":-1,\"Type\":\"Country\",\"Name\":\"Canada\",\"ID\":9},{\"Population\":\"1.7M\",\"ParentID\":9,\"Type\":\"City\",\"Name\":\"Montreal\",\"ID\":10},{\"Population\":\"3M\",\"ParentID\":9,\"Type\":\"City\",\"Name\":\"Toronto\",\"ID\":11},{\"Population\":\"630K\",\"ParentID\":9,\"Type\":\"City\",\"Name\":\"Vancouver\",\"ID\":12},{\"Population\":\"25M\",\"ParentID\":-1,\"Type\":\"Country\",\"Name\":\"Mexico\",\"ID\":13},{\"Population\":\"9.2M\",\"ParentID\":13,\"Type\":\"City\",\"Name\":\"Mexico City\",\"ID\":14},{\"Population\":\"1.5M\",\"ParentID\":13,\"Type\":\"City\",\"Name\":\"Guadalajara\",\"ID\":15},{\"Population\":\"890K\",\"ParentID\":13,\"Type\":\"City\",\"Name\":\"Cancún\",\"ID\":16}]"
countries_data_table = GridUtils.toJSONTable(countries_data_json)

loremText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Nec ullamcorper sit amet risus nullam. Sagittis eu volutpat odio facilisis mauris sit amet massa vitae."

# ---------------------------------------------------------------
# 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()
prop!(app, :title, "Glimmer 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"))

# prepare the grid tabel
table_label = addVariable!(app, Variable(name="table_label", type="string", value="press the button to see row details"))
table_var = addVariable!(app, Variable(name="table_var", type="aggrid", value=""))

# setup the grid data and options - will get friendlier in the near future
table_var[] = GridUtils.table2agGrid(mlb_data_table)

# setting some grid options - because of it's complexity, the grid's data and visualization properties
# are all stored in the variable and not the UI control.
gridOption!(table_var, "rowSelection", "single")

# insert a row field
insertGridColumn!(table_var, 1, gridRowIndexCell(
    header="Row",
    width=70,
    cellStyle = Dict(
        "color" => "yellow",
        "background-color" => "pink",
    ),
))

# insert a combobox field in addition to the non-combobox Team field. you can edit either.
replaceGridColumn!(table_var, 3, gridSelectCell(
    header="Teams Combobox",
    field="Team",
    selectOptions=[
        Dict(:key=>"BAL", :value=>"Baltimore Orioles"),
        Dict(:key=>"CWS", :value=>"College World Series"),
        Dict(:key=>"ANA", :value=>"Los Angeles Angels"),
        Dict(:key=>"BOS", :value=>"Boston Red Sox"),
        Dict(:key=>"CLE", :value=>"Cleveland Indians"),
        Dict(:key=>"OAK", :value=>"Oakland Athletics"),
        Dict(:key=>"NYY", :value=>"New York Yankees"),
        Dict(:key=>"DET", :value=>"Detroit Tigers"),
        Dict(:key=>"SEA", :value=>"Seattle Mariners"),
        Dict(:key=>"TB", :value=>"Tampa Bay Rays"),
        Dict(:key=>"KC", :value=>"Kansas City Royals"),
        Dict(:key=>"TEX", :value=>"Texas Rangers"),

    ]
))

# insert a button column and defining the event for it. further down we write a function to handle that event per row.
insertGridColumn!(table_var, 4, gridButtonCell(
    header="Example Button",
    eventName="myButtonClicked",
    buttonText="Show Details",
))

# define the column default values (note the cellStyle to color a line red according to documantation existance)
gridDefaultColDef!(table_var, gridCell(
    editable=true,
    resizable=true,
    # filter = "agTextColumnFilter",
    # floatingFilter = true,
    # cellStyle="__js__ params => params.data.hasDocs==false ? { color: 'red' } : { color: 'green' }",
))

# prepare the countries table grid
table_var2 = addVariable!(app, Variable(name="table_var2", type="aggrid", value=""))

# setup the grid data and options - will get friendlier in the near future
# for tree type tables, we need to supply the name of the "id" firld and the "parent" field.
table_var2[] = GridUtils.table2agGridTree(countries_data_table, "ID", "ParentID")

# setting some grid options - because of it's complexity, the grid's data and visualization properties
# are all stored in the variable and not the UI control.
gridOption!(table_var2, "rowSelection", "single")
gridOption!(table_var2, "showRowIndex", true)
gridOption!(table_var2, "treeViewIndentPixels", 30)
gridOption!(table_var2, "suppressScrollOnNewData", true)
gridOption!(table_var2, "showTreeViewFilter", true)

clearGridColumns!(table_var2)
addGridColumn!(table_var2, gridTreeViewCell(header="Name", field="Name", width=250))
addGridColumn!(table_var2, gridCell(header="Type", field="Type"))
addGridColumn!(table_var2, gridCell(header="Population", field="Population"))

# define the column default values (note the cellStyle to color a line red according to documantation existance)
gridDefaultColDef!(table_var2, gridCell(
    editable=false,
    resizable=true,
    width=150,
    # cellStyle="__js__ params => params.data.hasDocs==false ? { color: 'red' } : { color: 'green' }",
))

# ---------------------------------------------------------------
# Define Events Handlers
# ---------------------------------------------------------------
on(table_var, :myButtonClicked) do val
    # @info """Button Clicked: name=[$(val["data"]["Name"])]"""
    data = val["data"]
    table_label[] = """[$(data["Name"])] is a [$(data["Name"])], [$(data["Age"]) years old)]"""
end

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

ui = VContainer(
    Card(
        # title="Information",
        style=card_style * highlight_color_style,
        content=UIControls.HContainerCenter(
            Label(
                text = "This example shows most of the Glimmer.jl UI controls in an interactive format.",
                style = "font-weight: bold; font-size:24px; align: center;",
            ),
        ),
    ),
    Accordion(
        panels=[

            # Labels
            ExpansionPanel(
                title="Label",
                subtitle="labels are non-interactive elements used to display text",
                style=expansion_panel_style,
                titleStyle=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,
                titleStyle=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 basic 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,
                titleStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Basic 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 [\$()]",
                                    trailingText="[\$()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",
                                    trailingText="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,
                titleStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Basic 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,
                titleStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Basic 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(Glimmer)), "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 and SlideToggle
            ExpansionPanel(
                title="CheckBox and SlideToggle",
                subtitle="togglers",
                style=expansion_panel_style,
                titleStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Basic 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 """),
                            ),
                        ),
                        Card(
                            title="Basic SlideToggle",
                            style=card_style,
                            content=VContainer(
                                syntax("""SlideToggle(
                                    text = "Sample Text Before Toggle",
                                    trailingText = "Sample Text After Toggle",
                                    color = "primary",
                                    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,
                titleStyle=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,
                titleStyle=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,
                titleStyle=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,
                titleStyle=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/Glimmer.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/Glimmer.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)",
                                        )""")...,

                            ),
                        ),

                    ],
                ),
            ),

            # Grid
            ExpansionPanel(
                title="Grid",
                subtitle="editing tabular and hierarchical data",
                style=expansion_panel_style,
                titleStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Basic Grid with a Combobox and Button examples",
                            style=card_style,
                            content=VContainer(
                                AGGrid(
                                    style="width: 600px; height: 500px;",
                                    variable="table_var",
                                ),
                                Label(variable="table_label"),

                                Divider(),

                                Label(text="To see how to define the grid properties please take a look in the example code."),
                            ),
                        ),

                        Card(
                            title="Grid with Tree/hierarchy support",
                            style=card_style,
                            content=VContainer(
                                AGGrid(
                                    style="width: 600px; height: 500px;",
                                    variable="table_var2",
                                ),

                                Divider(),

                                Label(text="To see how to define the grid properties please take a look in the example code."),
                            ),
                        ),

                    ],
                ),
            ),

            # Splitter
            ExpansionPanel(
                title="Splitter",
                subtitle="split views and allow dragging to resize areas",
                style=expansion_panel_style,
                titleStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Basic example of horizontal and vertical splitters",
                            style=card_style,
                            content=VContainer(
                                syntax("""Splitter(
                                    units = "percent",
                                    direction = "horizontal",
                                    style= "width: 100%; height: 500px;",
                                    areas = [
                                        SplitterArea(
                                            size = "30",
                                            minSize=10,
                                            content = VContainer(
                                                Card(
                                                    title="Nested Splitters",
                                                    subtitle="A Card inside a aplitter area containing a vertical splitter",
                                                    style=card_style,
                                                    content=VContainer(
                                                        Splitter(
                                                            units = "pixel",
                                                            direction = "vertical",
                                                            style= "width: 100%; height: 350px;",
                                                            areas = [
                                                                SplitterArea(
                                                                    size = "*",
                                                                    content = VContainer(
                                                                        Label(text=loremText),
                                                                    ),
                                                                ),
                                                                SplitterArea(
                                                                    size = "100",
                                                                    minSize=50,
                                                                    content = VContainer(
                                                                        Label(text=loremText),
                                                                    ),
                                                                ),
                                                                SplitterArea(
                                                                    size = "100",
                                                                    minSize=50,
                                                                    content = VContainer(
                                                                        Label(text=loremText),
                                                                    ),
                                                                ),
                                                            ],
                                                        ),
                                                    ),
                                                ),
                                            ),
                                        ),
                                        SplitterArea(
                                            size = "40",
                                            minSize=10,
                                            content = VContainer(
                                                Label(text="We are inside a splitter area"),
                                                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"),
                                                )
                                            ),
                                        ),
                                        SplitterArea(
                                            size = "30",
                                            minSize=10,
                                            content = VContainer(
                                                Label(text="Another splitter area"),
                                                Slider(
                                                    text="Value ",
                                                    trailingText="[\\\$()cm]",
                                                    min=0, max=100, value=10, variable="range1"
                                                )
                                            ),
                                        )

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

            # RawHTML
            ExpansionPanel(
                title="RawHTML",
                subtitle="allowing hosting of HTML rendered content inside the application",
                style=expansion_panel_style,
                titleStyle=expansion_panel_header_style,
                subtitleStyle=expansion_panel_subtitle_style,
                content=Container(
                    direction="row warp",
                    children=[
                        Card(
                            title="Techinal Details",
                            style=card_style * highlight_color_style,
                            # contentStyle="background-color: pink;",
                            content=VContainer(
                                Label(text="""The Glimmer package UI is an Angular application (a framework for building web applications)
                                              running inside a Blink window.  The UI controls that are supported by Glimmer are mostly Angular
                                              compatible components. However, sometimes you might find the need to host a pure html content
                                              inside the Glimmer UI. An example would be a Julia package that renders HTML, such as WGLMakie.jl
                                              or TableView.jl.""",
                                ),
                                Label(text="""Is such cases, you will need to use the RawHTML control. This control allows you to inject pure
                                              HTML to the angular scope or use an IFRAME html tag to treat it as an isolated island
                                              (useFrame = true or false). """,
                                ),
                            ),
                        ),

                        Card(
                            title="RawHTML inject an iframe tag",
                            style=card_style,
                            content=VContainer(
                                syntax("""RawHTML(
                                    html="

                                        ",
                                    style = "width: 100%; height: 100%;",
                                )""")...,
                            ),
                        ),

                        Card(
                            title="RawHTML inject an iframe tag",
                            style=card_style,
                            content=VContainer(
                                syntax("""RawHTML(
                                    html="",
                                )""")...,
                            ),
                        ),

                        Card(
                            title="RawHTML display an entire html page in a frame",
                            style=card_style,
                            content=VContainer(
                                syntax("""RawHTML(
                                    html="<!DOCTYPE html>

My First Heading

\$(loremText).

                                    ",
                                    style = "width: 100%; height: 300%;",
                                    useFrame = true,
                                )""")...,
                            ),
                        ),

                        Card(
                            title="RawHTML result of rendering a Julia object's HTML",
                            subtitle="Convert a Julia markdown string to it's HTML representation",
                            style=card_style,
                            content=VContainer(
                                syntax("""RawHTML(
                                    html=renderHTML(MD.md\"\"\"# Level One
                                                            ## Level Two
                                                            ### Level Three
                                                            #### Level Four
                                                            ##### Level Five
                                                            ###### Level Six\"\"\" ),
                                    style = "width: 100%; height: 300%;",
                                    useFrame = true,
                                )""")...,

                            ),
                        ),

                    ],
                ),
            ),

        ],
    ),
)
# set the controls for the application
controls!(app, ui)

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

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

end # module


text:
# These notes are partly based on Michael Shashoua's notes on parallelization. Thanks, Michael!
#     https://economics.rice.edu/students/michael-shashoua
# See also https://juliaeconomics.com/2014/06/18/parallel-processing-in-julia-bootstrapping-the-mle/

# ------------------------------------------------
# Starting workers
# ------------------------------------------------

myid()             # Master is always "1"
workers()          # Return vector of worker IDs
addprocs(2)        # Add workers. Good to add as many as CPU CORES
@show Sys.CPU_CORES      # this is the number of hyper-threading cores (NOT PHYSICAL)
rmprocs(workers()) # get rid of all workers

@show addprocs()  # Defaults to number of virtual cores
@show procs()     # Master + workers
@show workers()   # workers only

# doing stuff on the workers
@everywhere println(myid()) # @everywhere macro will have each process return info
@show fetch(@spawn myid())        # @spawn will go through the different workers
@show fetch(@spawnat workers()[2] myid())    # @spawnat will be directed to a specific worker

# ------------------------------------------------
# Getting data on workers
# ------------------------------------------------

data_example = 54 # "data_example" has value of 54 only for the Master
@everywhere try
    println(data_example)
  catch e
    println(e)
end

# to send arrays, data, etc use @eval
@eval @everywhere begin
  data_example1 = 54+3
  data_example2 = $data_example+2
  println((data_example1,data_example2,))
end

# This works the same with packages.
using Distributions  # load pkg on the master, but not workers
@everywhere begin
  try
    println(rand(Normal(0,1)))
  catch e
    println(e)
  end
end

# NOTE: have to load pkg on master first before loading on worker
@everywhere begin
  using Distributions
  println(rand(Normal(0,1)))

  function exmp(n)
    println("worker $myid() will draw $n random values")
    rand(n)
  end
end

val = pmap(exmp,[1,3,4,10])
@show valcat = vcat(val...)
rmprocs(workers())

# ------------------------------------------------
# Doing things in parallel
# ------------------------------------------------

#=
2 main options: pmap and @distributed

- pmap([::AbstractWorkerPool], f, c...)
    + like a parallel map function that returns a Vector{Any}
    + If needing to move data, make sure to use a CachingPool(), not a WorkerPool()
    + Allocates tasks 1 at a time to different workers.
    + Better if tasks take different amounts of time
- @distributed
    + can be put in front of a loop to make it run over all available workers
    + Usually want to prefix w/ @sync if not a reduction... otherwise code won't wait on workers
    + can also be made into a reduction
    + Divides up index into big chunks and gives each worker a section
    + Best when tasks take same amount of time
=#

# Example 1: Simulating Heads or Tails with parallel reduction
tic()
nheads = @sync @distributed (+) for i=1:8
  sleep(1)
  println(i)
  Int(rand(Bool))
end
toc()

addprocs()

tic()
nheads = @sync @distributed (+) for i=1:8
  sleep(1)
  println(i)
  Int(rand(Bool))
end
toc()

# EXAMPLE 2: FINDING Area under a curve
NITER = 2000000000
rmprocs(workers())
f(i::Int) = rand()^2 + rand()^2 <= 1 ? 1 : 0

sleep(1)

tic()
srand(1234)
out = @sync @distributed (+) for i = 1:NITER
  f(i)
end
println(out / NITER)
toc()

addprocs()
@eval @everywhere g(i::Int) = rand()^2 + rand()^2 <= 1 ? 1 : 0

tic()
srand(1234)
inside = @sync @distributed (+) for i = 1:NITER
  g(i)
end
println(inside / NITER)
toc()

# ------------------------------------------------
# Working on big arrays together
# ------------------------------------------------

#=
- SharedArray{T,N}(dims::NTuple; init=false, pids=Int[])
  + each “participating” process has access to the entire array,
  + participating workers specified by the pids named argument
- DistributedArray
  + each worker "owns" a particular subset of array and can't see the rest
=#

# Workers can't see this array on master
rmprocs(workers())
addprocs()
a = zeros(Int, 10)
s = @sync @distributed for i in eachindex(a)
  a[i] = myid()
  println(i)
end
@show a

# SharedArray(T::Type, dims::NTuple; init=false, pids=Int[])=
b = SharedArray(Int, 10)
fill!(b, 0)
s = @sync @distributed for i in eachindex(b)
  b[i] = myid()
  println(i)
end
@show b

rmprocs(workers())

# ------------------------------------------------
# Jedi tricks
# ------------------------------------------------

#=
- Easiest to load things on workers by "using" an entire module
- Can define global variables in a module
  + that can only be seen by that module...
  + and only modified from w/ in module
  + functions in the module can use the globals if "global" keyword given
- Problem: globals are not typed, so compiler can't optimize
- Solution
  + Annotate types of globals when used in function arguments
    * Must be CONCRETE
    * eg, Array{Real} does not help, but Matrix{Int} does.
  + "function-barrier" technique: outer wrapper + inner function
- Set global variables (like data) using module functions

=#

ext: jl


text:
include("../src/Library.jl")
using DataFrames
using CSV

function denoise!(sol)

end

function munge(A::Vector{Vector{Float64}})
    l1 = length(A)
    l2 = length(A[1])
    M = zeros(l2,l1)
    for  i = 1:l1
        M[:,i] = A[i]
    end
    M
end

function pprint(x::Matrix,btype::AbstractBasis)
    if size(x,2) == 3 && typeof(btype) == PolyTrigBasis
        labels = ["1","x","y","z","x²","xy","xz","y²","yz","z²",
                 "x³","x²y","x²z","xy²","y³","y²z","xz²","yz²","z³","sin(x)","sin(y)","sin(z)"
                 ,"cos(x)","cos(y)","cos(z)","tan(x)","tan(y)","tan(z)"]
    elseif size(x,2) == 3 && typeof(btype) == PolynomialBasis
        labels = ["1","x","y","z","x²","xy","xz","y²","yz","z²",
                 "x³","x²y","x²z","xy²","y³","y²z","xz²","yz²","z³"]

    elseif size(x,2) == 2 && typeof(btype) == PolyTrigBasis
        labels = ["1","x","y","x²","xy","y²",
                 "x³","x²y","xy²","y³","sin(x)","sin(y)"
                 ,"cos(x)","cos(y)","tan(x)","tan(y)"]
    elseif size(x,2) == 2 && typeof(btype) == PolynomialBasis
        labels = ["1","x","y","x²","xy","y²",
                 "x³","x²y","xy²","y³"]
    elseif size(x,2) == 2 && typeof(btype) == TrigBasis
        labels = ["sin(x)","sin(y)"
        ,"cos(x)","cos(y)","tan(x)","tan(y)"]
    end
    df = DataFrame(basis=labels)
    df2 = DataFrame(x,:auto)
    display(hcat(df,df2))
end

function _remake(ξ::Matrix{T},type::AbstractBasis) where T
    if size(ξ,2) == 3
        if typeof(type)==PolyTrigBasis
            basis = [(x,y,z)->1,(x,y,z)->x,(x,y,z)->y,(x,y,z)->z,
                    (x,y,z)->x^2,(x,y,z)->x*y,(x,y,z)->x*z,(x,y,z)->y^2,
                    (x,y,z)->y*z,(x,y,z)->z^2,(x,y,z)->x^3,(x,y,z)->x^2*y,
                    (x,y,z)->x^2*z,(x,y,z)->x*y^2,(x,y,z)->y^3,(x,y,z)->y^2*z,
                    (x,y,z)->x*z^2,(x,y,z)->y*z^2,(x,y,z)->z^3,(x,y,z)->sin(x),(x,y,z)->sin(y),
                    (x,y,z)->sin(z),(x,y,z)->cos(x),(x,y,z)->cos(y),(x,y,z)->cos(z),(x,y,z)->tan(x),
                    (x,y,z)->tan(y),(x,y,z)->tan(z)]
        elseif typeof(type) == PolynomialBasis
            basis = [(x,y,z)->1,(x,y,z)->x,(x,y,z)->y,(x,y,z)->z,
                    (x,y,z)->x^2,(x,y,z)->x*y,(x,y,z)->x*z,(x,y,z)->y^2,
                    (x,y,z)->y*z,(x,y,z)->z^2,(x,y,z)->x^3,(x,y,z)->x^2*y,
                    (x,y,z)->x^2*z,(x,y,z)->x*y^2,(x,y,z)->y^3,(x,y,z)->y^2*z,
                    (x,y,z)->x*z^2,(x,y,z)->y*z^2,(x,y,z)->z^3]
        end
        @assert size(ξ,1) == length(basis) "Non Equal basis indices"
        f1 = ξ[1,1]*basis[1]
        f2 = ξ[1,2]*basis[1]
        f3 = ξ[i,3]*basis[1]
        for i = 2:length(basis)
            f1 += basis[i]*ξ[i,1]
            f2 += basis[i]*ξ[i,2]
            f3 += basis[i]*ξ[i,3]
        end
        function f(du,u,p,t)
            du[1] = f1(u[1],u[2],u[3])
            du[2] = f2(u[1],u[2],u[3])
            du[3] = f3(u[1],u[2],u[3])
        end
        return f
    elseif size(ξ,2) == 2
        if typeof(type) == PolyTrigBasis
            basis = [(x,y,z)->1,(x,y,z)->x,(x,y,z)->y,(x,y,z)->x^2,(x,y,z)->x*y,
                    (x,y,z)->y^2,(x,y,z)->x^3,(x,y,z)->x^2*y,(x,y,z)->x*y^2,(x,y,z)->y^3,(x,y,z)->sin(x),
                    (x,y,z)->sin(y),(x,y,z)->cos(x),(x,y,z)->cos(y),(x,y,z)->tan(x),(x,y,z)->tan(y)]
        elseif typeof(type) == PolynomialBasis
            basis = [(x,y,z)->1,(x,y,z)->x,(x,y,z)->y,(x,y,z)->x^2,(x,y,z)->x*y,
                    (x,y,z)->y^2,(x,y,z)->x^3,(x,y,z)->x^2*y,(x,y,z)->x*y^2,(x,y,z)->y^3]
        end
        x_basis(x,y,z) = basis(ξ[:,1],x,y,z)
        y_basis(x,y,z) = basis(ξ[:,2],x,y,z)
        function f(du,u,p,t)
            du[1] = f1(u[1],u[2],u[3])
            du[2] = f2(u[1],u[2],u[3])
        end
        return f
    end
end


text:
using PackedReadWrite
using BenchmarkTools

struct Simple
    int32::Int32
    float64::Float64
    byte1::UInt8
    byte2::UInt8
    single::Float32
end

function packed_size(::Type{T}) where T
    sum(sizeof.(fieldtypes(T)))
end

function handcrafted(io::IO, ::Type{T}) where T <: Simple
    Simple(read(io, Int32),
            read(io, Float64),
            read(io, UInt8),
            read(io, UInt8),
            read(io, Float32))
end

function test_base_read(io::T) where T
    seekstart(io)
    while !eof(io)
        read(io, Simple)
    end
end

function test_handcrafted(io::T) where T
    seekstart(io)
    while !eof(io)
        handcrafted(io, Simple)
    end
end

function test_generic_read(io::T) where T
    seekstart(io)
    while !eof(io)
        PackedReadWrite.read_struct(io, Simple)
    end
end

n = 1000
data = IOBuffer(rand(UInt8, n * packed_size(Simple)))

@info "Handcrafted, hard-coded specialized method:"
@btime test_handcrafted(data)
#   6.300 μs (0 allocations: 0 bytes)

@info "Generic read, before caching reflection:"
@btime test_generic_read(data)
#   88.000 μs (0 allocations: 0 bytes)

@reflect Simple

@info "Generic read, after caching reflection:"
@btime test_generic_read(data)
#   6.280 μs (0 allocations: 0 bytes)

Base.read(io::IO, ::Type{Simple}) = read_struct(io, Simple)

@info "Using new Base.read method:"
@btime test_base_read(data)
#   6.280 μs (0 allocations: 0 bytes)


text:
function sparse_ao_2e4c(BS::BasisSet, T::DataType = Float64)

    cutoff = Options.get("eri_cutoff")

    # Number of unique integral elements
    N = Int((BS.nbas^2 - BS.nbas)/2) + BS.nbas
    N = Int((N^2 - N)/2) + N

    # Pre allocate output
    out = zeros(T, N)
    indexes = Array{NTuple{4,Int16}}(undef, N)

    # Pre compute a list of angular momentum numbers (l) for each shell
    lvals = [Libcint.CINTcgtos_spheric(i-1, BS.lc_bas) for i = 1:BS.nshells]
    Lmax = maximum(lvals)

    # Offset list for each shell, used to map shell index to AO index
    ao_offset = [sum(lvals[1:(i-1)]) - 1 for i = 1:BS.nshells]

    # Unique shell pairs with i < j
    num_ij = Int((BS.nshells^2 - BS.nshells)/2) + BS.nshells

    # Pre allocate array to save ij pairs
    ij_vals = Array{NTuple{2,Int32}}(undef, num_ij)

    # Pre allocate array to save σij, that is the screening parameter for Schwarz
    σvals = zeros(Float64, num_ij)

    ### Loop thorugh i and j such that i ≤ j. Save each pair into ij_vals and compute √σij for integral screening
    lim = Int32(BS.nshells - 1)
    for i = UnitRange{Int32}(zero(Int32),lim)
        @inbounds begin
        Li2 = lvals[i+1]^2
            for j = UnitRange{Int32}(i, lim)
                Lj2 = lvals[j+1]^2
                buf = zeros(Cdouble, Li2*Lj2)
                idx = index2(i,j) + 1
                ij_vals[idx] = (i,j)
                cint2e_sph!(buf, [i,i,j,j], BS.lc_atoms, BS.natoms, BS.lc_bas, BS.nbas, BS.lc_env)
                σvals[idx] = √maximum(buf)
            end
        end
    end

    buf_arrays = [zeros(Cdouble, Lmax^4) for _ = 1:Threads.nthreads()]

    # i,j,k,l => Shell indexes starting at zero
    # I, J, K, L => AO indexes starting at one
    @sync for ij in eachindex(ij_vals)
        Threads.@spawn begin
        @inbounds begin
            buf = buf_arrays[Threads.threadid()]
            i,j = ij_vals[ij]
            Li, Lj = lvals[i+1], lvals[j+1]
            Lij = Li*Lj
            ioff = ao_offset[i+1]
            joff = ao_offset[j+1]
            for kl in ij:num_ij
                σ = σvals[ij]*σvals[kl]
                if σ < cutoff
                    continue
                end
                k,l = ij_vals[kl]
                Lk, Ll = lvals[k+1], lvals[l+1]
                Lijk = Lij*Lk
                koff = ao_offset[k+1]
                loff = ao_offset[l+1]

                # Compute ERI
                cint2e_sph!(buf, [i,j,k,l], BS.lc_atoms, BS.natoms, BS.lc_bas, BS.nbas, BS.lc_env)

                ### This block aims to retrieve unique elements within buf and map them to AO indexes
                # is, js, ks, ls are indexes within the shell e.g. for a p shell is = (1, 2, 3)
                # bl, bkl, bjkl are used to map the (i,j,k,l) index into a one-dimensional index for buf
                # That is, get the correct integrals for the AO quartet.
                for ls = 1:Ll
                    L = loff + ls
                    bl = Lijk*(ls-1)
                    for ks = 1:Lk
                        K = koff + ks
                        L < K ? break : nothing

                        # L ≥ K
                        KL = (L * (L + 1)) >> 1 + K
                        bkl = Lij*(ks-1) + bl
                        for js = 1:Lj
                            J = joff + js
                            bjkl = Li*(js-1) + bkl
                            for is = 1:Li
                                I = ioff + is
                                J < I ? break : nothing

                                IJ = (J * (J + 1)) >> 1 + I

                                #KL < IJ ? continue : nothing # This restriction does not work... idk why

                                idx = index2(IJ,KL) + 1
                                out[idx] = buf[is + bjkl]
                                indexes[idx] = (I, J, K, L)
                            end
                        end
                    end
                end
            end
        end #inbounds
        end #spawn
    end #sync
    mask = abs.(out) .> cutoff
    return indexes[mask], out[mask]
end

# This function is expensive and not optimized. Prefer using the sparse version
function ao_2e4c(BS::BasisSet, T::DataType = Float64)

    # Save a list containing the number of primitives for each shell
    num_prim = [Libcint.CINTcgtos_spheric(i-1, BS.lc_bas) for i = 1:BS.nshells]

    # Get slice corresponding to the address in S where the compute chunk goes
    ranges = UnitRange{Int64}[]
    iaccum = 1
    for i = 1:BS.nshells
        push!(ranges, iaccum:(iaccum+ num_prim[i] -1))
        iaccum += num_prim[i]
    end

    # Allocate output array
    out = zeros(T, BS.nbas, BS.nbas, BS.nbas, BS.nbas)
    unique_idx = find_indices(BS.nshells)

    @sync for (i,j,k,l) in unique_idx
        Threads.@spawn begin
            @inbounds begin
                # Shift indexes (C starts with 0, Julia 1)
                id, jd, kd, ld = i+1, j+1, k+1, l+1

                # Initialize array for results
                buf = ones(Cdouble, num_prim[id]*num_prim[jd]*num_prim[kd]*num_prim[ld])

                # Compute ERI
                cint2e_sph!(buf, Cint.([i,j,k,l]), BS.lc_atoms, BS.natoms, BS.lc_bas, BS.nbas, BS.lc_env)

                # Move results to output array
                ri, rj, rk, rl = ranges[id], ranges[jd], ranges[kd], ranges[ld]
                out[ri, rj, rk, rl] .= reshape(buf, (num_prim[id], num_prim[jd], num_prim[kd], num_prim[ld]))

                if i != j && k != l && index2(i,j) != index2(k,l)
                    # i,j permutation
                    out[rj, ri, rk, rl] .= permutedims(out[ri, rj, rk, rl], (2,1,3,4))
                    # k,l permutation
                    out[ri, rj, rl, rk] .= permutedims(out[ri, rj, rk, rl], (1,2,4,3))

                    # i,j + k,l permutatiom
                    out[rj, ri, rl, rk] .= permutedims(out[ri, rj, rk, rl], (2,1,4,3))

                    # ij, kl permutation
                    out[rk, rl, ri, rj] .= permutedims(out[ri, rj, rk, rl], (3,4,1,2))
                    # ij, kl + k,l permutation
                    out[rl, rk, ri, rj] .= permutedims(out[ri, rj, rk, rl], (4,3,1,2))
                    # ij, kl + i,j permutation
                    out[rk, rl, rj, ri] .= permutedims(out[ri, rj, rk, rl], (3,4,2,1))
                    # ij, kl + i,j + k,l permutation
                    out[rl, rk, rj, ri] .= permutedims(out[ri, rj, rk, rl], (4,3,2,1))

                elseif k != l && index2(i,j) != index2(k,l)
                    # k,l permutation
                    out[ri, rj, rl, rk] .= permutedims(out[ri, rj, rk, rl], (1,2,4,3))
                    # ij, kl permutation
                    out[rk, rl, ri, rj] .= permutedims(out[ri, rj, rk, rl], (3,4,1,2))
                    # ij, kl + k,l permutation
                    out[rl, rk, ri, rj] .= permutedims(out[ri, rj, rk, rl], (4,3,1,2))

                elseif i != j && index2(i,j) != index2(k,l)
                    # i,j permutation
                    out[rj, ri, rk, rl] .= permutedims(out[ri, rj, rk, rl], (2,1,3,4))

                    # ij, kl permutation
                    out[rk, rl, ri, rj] .= permutedims(out[ri, rj, rk, rl], (3,4,1,2))
                    # ij, kl + i,j permutation
                    out[rk, rl, rj, ri] .= permutedims(out[ri, rj, rk, rl], (3,4,2,1))

                elseif i != j && k != l
                    # i,j permutation
                    out[rj, ri, rk, rl] .= permutedims(out[ri, rj, rk, rl], (2,1,3,4))
                    # k,l permutation
                    out[ri, rj, rl, rk] .= permutedims(out[ri, rj, rk, rl], (1,2,4,3))

                    # i,j + k,l permutatiom
                    out[rj, ri, rl, rk] .= permutedims(out[ri, rj, rk, rl], (2,1,4,3))
                elseif index2(i,j) != index2(k,l)
                    # ij, kl permutation
                    out[rk, rl, ri, rj] .= permutedims(out[ri, rj, rk, rl], (3,4,1,2))
                end
            end #inbounds
        end #spawn
    end #sync

    return out
end


text:
@testset "solve_btpde_midpoint.jl" begin

end


text:
@testset "varstruct_call_parse" begin
    expr, args_field, args_defaultvalue, args_type, args_param, T = VarStructs.varstruct_call_parse(
        Main,
        quote
            Person(
                name::String = "Amin",
                number::Float64 = 20.0,
            )
        end
    )

    @test args_field == [:name, :number]
    @test args_defaultvalue == ["Amin", 20.0]
    @test args_type == [:String, :Float64]
    @test args_param == [Expr(:kw, :name, "Amin"), Expr(:kw, :number, 20.0)]
    @test T == :Person
end

@testset "varstruct_struct_parse" begin
    argsexpr, args_field, args_defaultvalue, args_type, args_param, args_check, is_struct_mutable, T = VarStructs.varstruct_struct_parse(
        Main,
        quote
            struct Person
                name::String
                number::Float64 = 20.0
            end
        end
    )

    @test args_field == [:name, :number]
    @test any(args_defaultvalue .== [Unset(), 20.0])
    @test args_type == [:String, :Float64]
    @test args_param == [:name, Expr(:kw, :number, 20.0)]
    @test T == :Person
end


text:
# soundsc.jl

using PortAudio: PortAudioStream, PortAudioDevice, write, devices
import PortAudio as PA # terminate, initialize, get_default_output_index
using Requires: @require
import SignalBase: framerate

export sound, soundsc

# fallback
framerate(x::Any) = error("The signal you are trying to play as a sound ",
 "does not have a known sampling rate. ",
 "Consider wrapping in a `SampleBuf` or defining `framerate(x::MyType)`.")

"""
    pick_output( ; io_in::IO = stdin, io_out::IO = stdout)
Show available audio devices and
prompt user to select output device.
"""
function pick_output( ; io_in::IO = stdin, io_out::IO = stdout)
    devs = devices()
    outable = map(x -> x.output_bounds.max_channels > 0, devs)
    any(outable) || throw("no output devices?")
    devnum = findfirst(outable)
    for (i,dev) in enumerate(devs)
       println(io_out, outable[i] ? i : "?", " ", dev)
    end
    print(io_out, "pick output device [$devnum]: ")
    char = read(io_in, Char)
    if char == '\n'
        return devs[devnum]
    end
    index = char - '0'
    (1 ≤ index ≤ length(devs) && outable[index]) || throw("bad index $index")
    return devs[index]
end

"""
    sound(x::AbstractVector, S::Real = framerate(x), args...; kwargs...)
Play monophonic audio signal `x` at sampling rate `S` samples per second
through default audio output device using the `PortAudio` package.
Caller must specify `S` unless a `framerate` method is defined for `x`.
"""
sound(x::AbstractVector, S::Real = framerate(x), args...; kwargs...) =
    sound(reshape(x, :, 1), S, args...; kwargs...)

"""
    sound(:pick, x, S::Real = framerate(x); kwargs...)
Prompt user to pick output device, then play sound in `x`.
"""
sound(::Symbol,
    x::AbstractArray,
    S::Real = framerate(x) ;
    io_in::IO = stdin,
    io_out::IO = stdout,
    kwargs...
) = sound(x, S, pick_output( ; io_in, io_out); kwargs...)

"""
    get_default_output_device()
Determine current system-wide default output audio device.
"""
function get_default_output_device()
    PA.terminate()
    PA.initialize()
    isempty(devices()) && throw("No audio devices.")
    return devices()[1 + PA.get_default_output_index()]
end

"""
    sound(output_device_index::Int, x, S::Real = framerate(x); kwargs...)
Play sound in `x` using `devices()[output_device_index]`.
"""
function sound(
    index::Int,
    x::AbstractArray,
    S::Real = framerate(x) ;
    kwargs...
)
    devs = devices()
    (1 ≤ index ≤ length(devs)) || throw("bad index $index")
    dev = devs[index]
    dev.output_bounds.max_channels > 0 || throw("no output channels")
    sound(x, S, dev; kwargs...)
end

"""
    sound(x::AbstractMatrix, S::Real = framerate(x) [, output_device])
Play stereo audio signal `x` at sampling rate `S` samples per second
through default audio output device using the `PortAudio` package.
Caller must specify `S` unless a `framerate` method is defined for `x`.
"""
function sound(
    x::AbstractMatrix,
    S::Real = framerate(x),
    output_device::PortAudioDevice = get_default_output_device(),
)
    if size(x,1) == 1 # row "vector"
        x = vec(x) # convenience
    end
    size(x,2) ≤ 2 || throw("size(x,2) = $(size(x,2)) is too many channels")

    output_device.output_bounds.max_channels > 0 ||
        throw("no output channels for $output_device")

    PortAudioStream(output_device, 0, 2; samplerate=Float64(S)) do stream
        write(stream, x)
    end
end

"""
    soundsc(x, S::Real = framerate(x), args...; kwargs...)
Call `sound` after scaling `x` to have values in `(-1,1)`.
"""
soundsc(x::AbstractArray, S::Real = framerate(x), args...; kwargs...) =
    sound(x * prevfloat(1.0) / maximum(abs, x), S, args...; kwargs...)


text:
# Create an admittance matrix. The implementation is a modification of
# MATPOWER's makeYbus. We attach the original MATPOWER's license in makeYbus.m:
#
# MATPOWER
# Copyright (c) 1996-2016, Power Systems Engineering Research Center (PSERC)
# by Ray Zimmerman, PSERC Cornell
#
# Covered by the 3-clause BSD License.
#
# This function returns the following:
#
#  Ybus : nb  x nb admittance
#  Yf_br: nbr x nb from-bus admittance of non-transformer branches
#  Yt_br: nbr x nb to-bus admittance of non-transformer branches
#  Yf_tr: ntr x nb from-bus admittance of transformer branches
#  Yt_tr: ntr x nb to-bus admittance of transformer branches
#
# where nb is the number of buses, nbr is the number of non-transformer
# branches, and ntr is the number of transformer branches.
function makeYbus(data, bus_to_indexes)
    baseMVA = data["baseMVA"]
    bus     = data["bus"]
    branch  = data["branch"]
    F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, TAP, SHIFT, BR_STATUS,
    ANGMIN, ANGMAX, PF, QF, PT, QT, MU_SF, MU_ST, MU_ANGMIN, MU_ANGMAX = IndexSet.idx_branch()
    BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, VA, BASE_KV, ZONE, VMAX, VMIN,
    LAM_P, LAM_Q, MU_VMAX, MU_VMIN = IndexSet.idx_bus()

    # constants
    nb = size(bus, 1)          # number of buses
    nl = size(branch, 1)       # number of lines

    # define named indices into bus, branch matrices

    # for each branch, compute the elements of the branch admittance matrix where
    #
    #      | If |   | Yff  Yft |   | Vf |
    #      |    | = |          | * |    |
    #      | It |   | Ytf  Ytt |   | Vt |
    #
    stat = branch[:, BR_STATUS]                     # ones at in-service branches
    Ys = stat ./ (branch[:, BR_R] + 1im * branch[:, BR_X])  # series admittance
    Bc = stat .* branch[:, BR_B]                           # line charging susceptance
    tap = ones(nl)                               # default tap ratio = 1
    i = findall(branch[:, TAP] .!= 0)              # indices of non-zero tap ratios
    tap[i] = branch[i, TAP]                         # assign non-zero tap ratios
    tap = tap .* exp.(1im*pi/180 * branch[:, SHIFT]) # add phase shifters
    Ytt = Ys + 1im*Bc/2
    Yff = Ytt ./ (tap .* conj(tap))
    Yft = - Ys ./ conj(tap)
    Ytf = - Ys ./ tap

    # compute shunt admittance
    # if Psh is the real power consumed by the shunt at V = 1.0 p.u.
    # and Qsh is the reactive power injected by the shunt at V = 1.0 p.u.
    # then Psh - j Qsh = V * conj(Ysh * V) = conj(Ysh) = Gs - j Bs,
    # i.e. Ysh = Psh + j Qsh, so ...
    Ysh = (bus[:, GS] + 1im * bus[:, BS]) / baseMVA[1] # vector of shunt admittances

    # build connection matrices
    f = [bus_to_indexes[e] for e in branch[:, F_BUS]] # list of "from" buses
    t = [bus_to_indexes[e] for e in branch[:, T_BUS]] # list of "to" buses

    Cf = sparse(1:nl, f, ones(nl), nl, nb)       # connection matrix for line & from buses
    Ct = sparse(1:nl, t, ones(nl), nl, nb)       # connection matrix for line & to buses

    # build Yf and Yt such that Yf * V is the vector of complex branch currents injected
    # at each branch's "from" bus, and Yt is the same for the "to" bus end
    i = [1:nl; 1:nl]
    Yf = sparse(i, [f; t], [Yff; Yft], nl, nb)
    Yt = sparse(i, [f; t], [Ytf; Ytt], nl, nb)

    # build Ybus
    Ybus = Cf' * Yf + Ct' * Yt + sparse(1:nb, 1:nb, Ysh, nb, nb)

    return Ybus

end

"""
    bustypeindex(bus, gen)

Returns vectors indexing buses by type: ref, pv, pq.

"""
function bustypeindex(bus, gen, bus_to_indexes)
    # retrieve indeces
    BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, VA, BASE_KV, ZONE, VMAX, VMIN,
    LAM_P, LAM_Q, MU_VMAX, MU_VMIN = IndexSet.idx_bus()

    GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, PC1, PC2, QC1MIN,
    QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF, MU_PMAX, MU_PMIN, MU_QMAX,
    MU_QMIN = IndexSet.idx_gen()

    # form vector that lists the number of generators per bus.
    # If a PV bus has 0 generators (e.g. due to contingency)
    # then that bus turns to a PQ bus.

    # Design note: this might be computed once and then modified for each contingency.
    gencon = zeros(Int8, size(bus, 1))

    for i in 1:size(gen, 1)
        if gen[i, GEN_STATUS] == 1
            id_bus = bus_to_indexes[gen[i, GEN_BUS]]
            gencon[id_bus] += 1
        end
    end

    bustype = copy(bus[:, BUS_TYPE])

    for i in 1:size(bus, 1)
        if (bustype[i] == PV_BUS_TYPE) && (gencon[i] == 0)
            bustype[i] = PQ_BUS_TYPE
        elseif (bustype[i] == PQ_BUS_TYPE) && (gencon[i] > 0)
            bustype[i] = PV_BUS_TYPE
        end
    end

    # form vectors
    ref = findall(x -> x==REF_BUS_TYPE, bustype)
    pv = findall(x -> x==PV_BUS_TYPE, bustype)
    pq = findall(x -> x==PQ_BUS_TYPE, bustype)

    return ref, pv, pq, bustype
end

"""
    assembleSbus(gen, load, SBASE, nbus)

Assembles vector of constant power injections (generator - load). Since
we do not have voltage-dependent loads, this vector only needs to be
assembled once at the beginning of the power flow routine.

"""
function assembleSbus(gen, bus, baseMVA, bus_to_indexes)

    ngen = size(gen, 1)
    nbus = size(bus, 1)
    sbus = zeros(Complex{Float64}, nbus)
    sload = zeros(Complex{Float64}, nbus)

    # retrieve indeces
    BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, VA, BASE_KV, ZONE, VMAX, VMIN,
    LAM_P, LAM_Q, MU_VMAX, MU_VMIN = IndexSet.idx_bus()

    GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, PC1, PC2, QC1MIN,
    QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF, MU_PMAX, MU_PMIN, MU_QMAX,
    MU_QMIN = IndexSet.idx_gen()

    for i in 1:ngen
        if gen[i, GEN_STATUS] == 1
            id_bus = bus_to_indexes[gen[i, GEN_BUS]]
            sbus[id_bus] += (gen[i, PG] + 1im*gen[i, QG])/baseMVA
        end
    end

    for i in 1:nbus
        id_bus = bus_to_indexes[bus[i, BUS_I]]
        load = (bus[i, PD] + 1im*bus[i, QD])/baseMVA
        sbus[id_bus] -= load
        sload[id_bus] = load
    end

    return sbus, sload
end


text:
using FractionalGaussianFields, AsyPlots
using Test

# write your own tests here

zeroboundary(torus_gff(100))

P = [(1+cos(8θ)/8)*cis(θ) for θ=range(0,2π,length=500)]
loop = Path(P).points
n = 40

G = domainapprox(loop,n)