text:
using Test

using JSON, Unitful, AxisArrays
using ImagineInterface
import ImagineInterface.METADATA_KEY

#test reading

example_dir = joinpath(dirname(@__DIR__), "examples")
fname = joinpath(example_dir, "t.json")

#analog
d = JSON.parsefile(fname)
pos = parse_command(d, "axial piezo")
pos0 = parse_command(fname, "axial piezo")
nsamps = d[METADATA_KEY]["sample num"]
@test length(pos) == length(pos0) == nsamps
@test name(pos) == name(pos0) == "axial piezo"
@test isdigital(pos) == false

sample_rate = d[METADATA_KEY]["samples per second"]
@test sample_rate*Unitful.s^-1 == samprate(pos)

rig = d[METADATA_KEY]["rig"]
@test rig_name(pos) == rig

#show
show(IOBuffer(), pos)

allcoms = parse_commands(fname)
cam = getcameras(allcoms)[1]
camid = name(cam)
@test in(camid, keys(d[METADATA_KEY]))

nframes = d[METADATA_KEY][camid]["frames per stack"]
nstacks = d[METADATA_KEY][camid]["stacks"]
@test nframes*nstacks == count_pulses(cam)

#digital
nm = "488nm laser shutter"
las1 = getname(allcoms, nm)
@test isdigital(las1) == true
@test name(las1) == nm
@test length(las1) == nsamps
@test_throws ErrorException getname(allcoms, "nonexistent name")

#show
show(IOBuffer(), las1)

#decompression
#world-mapped, analog
sampsa0 = get_samples(pos, 1, nsamps; sampmap=:world)
sampsa = get_samples(getname(allcoms, "axial piezo") , 1, nsamps; sampmap=:world)
@test length(sampsa) == nsamps
@test all(sampsa0.==sampsa)

@test unit(sampsa[1]) == Unitful.μm
axs = AxisArrays.axes(sampsa)
@test length(axs) == 1
axsv = axisvalues(axs[1])
@test length(axsv) == 1
@test axsv[1] == range(0.0*Unitful.s, stop=4.74238*Unitful.s, length=nsamps)

#voltage-mapped, analog
sampsa = get_samples(pos, 1, nsamps; sampmap=:volts)
@test unit(sampsa[1]) == Unitful.V

#raw, analog
sampsa = get_samples(pos, 1, nsamps; sampmap=:raw)
@test eltype(sampsa) == rawtype(pos) #Int16 by default

#world-mapped, digital
sampsd = get_samples(las1, 1, nsamps; sampmap=:world)
@test length(sampsd) == nsamps

sampsdsub = get_samples(las1, 50000, 100000; sampmap=:world)
@test all(sampsdsub.==sampsd[50000:100000])

sampsd = get_samples(las1, 1, nsamps; sampmap=:volts)
@test unit(sampsd[1]) == Unitful.V

sampsd = get_samples(las1, 1, nsamps; sampmap=:raw)
@test eltype(sampsd) == rawtype(las1) #UInt8 by default

#time-based indexing
sampsd = get_samples(las1, 1, nsamps; sampmap=:world)
subsamps = get_samples(las1, 0.0*Unitful.s, 0.0*Unitful.s)
@test length(subsamps) == 1
@test subsamps[1] == sampsd[1]
subsamps = get_samples(las1, 0.0*Unitful.s, 0.1*Unitful.s)
@test all(sampsd[1:500].==subsamps[1:500])
@test get_samples(las1, 0.0049*Unitful.s, 0.0050*Unitful.s) == [false, false, false, false, false, true]

#allow 0-count RepeatedValues
stim_com = getstimuli(rigtemplate("ocpi-2"; sample_rate = 5*Unitful.s^-1))[1]
nsamps_on = nsamps_off = 2
stim_on = RepeatedValue(nsamps_on, true)
stim_off = RepeatedValue(nsamps_off, false)
stim_0=RepeatedValue(0, false)

#0-count first
stim_vec = RepeatedValue{UInt8}[]
push!(stim_vec,stim_0)
push!(stim_vec, stim_on)
push!(stim_vec, stim_off)
v = convert(Vector{UInt8}, stim_vec)
append!(stim_com, "on_off", stim_vec)
@test ImagineInterface.get_samples_raw(stim_com, 1, length(stim_com)) == convert(Vector{UInt8}, stim_vec)

#0-count middle
empty!(stim_com; clear_library=true)
stim_vec = RepeatedValue{UInt8}[]
push!(stim_vec, stim_on)
push!(stim_vec,stim_0)
push!(stim_vec, stim_off)
v = convert(Vector{UInt8}, stim_vec)
append!(stim_com, "on_off", stim_vec)
@test ImagineInterface.get_samples_raw(stim_com, 1, length(stim_com)) == convert(Vector{UInt8}, stim_vec)

#0-count last
empty!(stim_com; clear_library=true)
stim_vec = RepeatedValue{UInt8}[]
push!(stim_vec, stim_on)
push!(stim_vec, stim_off)
push!(stim_vec,stim_0)
v = convert(Vector{UInt8}, stim_vec)
append!(stim_com, "on_off", stim_vec)
@test ImagineInterface.get_samples_raw(stim_com, 1, length(stim_com)) == convert(Vector{UInt8}, stim_vec)

#this caught an off-by-one error
oc2 = rigtemplate("ocpi-2"; sample_rate = 1000 * inv(Unitful.s))
_cam = getcameras(oc2)[1]
c = fill(UInt8(1), 10)
c[1] = 0
c[end] = 0
append!(_cam, "c", c)
@test ImagineInterface.get_samples_raw(_cam, 10, 10)[1] == false
galvos = getgalvos(oc2)
@test hasmonitor(galvos[1]) && hasmonitor(galvos[2])
galvo_mons = getgalvomonitors(oc2)
@test hasactuator(galvo_mons[1]) && hasactuator(galvo_mons[2])

#convenience
digs = getdigital(allcoms)
for di in digs
    if isoutput(di)
        @test in(daq_channel(di), ImagineInterface.DO_CHANS[rig])
    else
        @test in(daq_channel(di), ImagineInterface.DI_CHANS[rig])
    end
end

angs = getanalog(allcoms)
for an in angs
    if isoutput(an)
        @test in(daq_channel(an), ImagineInterface.AO_CHANS[rig])
    else
        @test in(daq_channel(an), ImagineInterface.AI_CHANS[rig])
    end
end

#write
outname = splitext(tempname())[1] *".json"
exp_time = d[METADATA_KEY]["camera1"]["exposure time in seconds"] * Unitful.s
write_commands(outname, allcoms, nstacks, nframes, exp_time; exp_trig_mode = "External Start", isbidi = false)
allcoms2 = parse_commands(outname)
d2 = JSON.parsefile(outname)
@test d2["version"] == "v1.1"
@test d2[METADATA_KEY]["camera1"]["exposure trigger mode"] == "External Start"
@test d2[METADATA_KEY]["camera1"]["bidirectional"] == false

sp = sortperm(map(name,allcoms)) #sort alphabetically to compare
sp2 = sortperm(map(name,allcoms2))
@test length(allcoms2) == length(allcoms)
@assert length(findinputs(allcoms2)) == 4
@test allcoms[sp] == allcoms2[sp2]
rm(outname)

#build commands from template
ocpi1 = rigtemplate("ocpi-1"; sample_rate = 20000*Unitful.s^-1)
@test length(getcameras(ocpi1)) == 1
@test length(getlasers(ocpi1)) == 1
@test length(getpositioners(ocpi1)) == 1
@test length(getstimuli(ocpi1)) == 5

ocpi2 = rigtemplate("ocpi-2"; sample_rate = 20000*Unitful.s^-1)
@test length(getcameras(ocpi2)) == 2
@test length(getlasers(ocpi2)) == 6
@test length(getpositioners(ocpi2)) == 2
@test length(getstimuli(ocpi2)) == 15

realm = rigtemplate("realm"; sample_rate = 20000*Unitful.s^-1)
@test length(getcameras(realm)) == 1
@test length(getlasers(realm)) == 1
@test length(getpositioners(realm)) == 1
@test length(getstimuli(realm)) == 5

@test samprate(ocpi2[1]) == 20000*Unitful.s^-1
@test all(x->x==0, map(length, ocpi2))

#append!
pos = getpositioners(ocpi2)[1]
rawdat = Int16[0:typemax(Int16)...]
append!(pos, "ramp_up", rawdat)
dat = get_samples(pos, "ramp_up")
@test dat[1] == mapper(pos).worldmin
@test dat[end] == mapper(pos).worldmax
append!(pos, "ramp_up") #append existing
@test_throws Exception append!(pos, "alajvekaj") #does not exist
@test_throws Exception add_sequence!(pos, "ramp_up", rawdat) #cannot add because exists
lpos = length(pos)
@test lpos == 2*typemax(Int16)+2

#append! already compressed
stim1 = getstimuli(ocpi2)[1]
stim2 = getstimuli(ocpi2)[2]
append!(stim1, "on_100", trues(100))
rlev = RepeatedValue{rawtype(stim2)}[]
push!(rlev, RepeatedValue(100, true))
append!(stim2, "on_100_2", rlev)
@test length(stim1) == length(stim2)
@test all(get_samples(stim1) .== get_samples(stim2))

#test invalid sample types
rawdat = Int32[1:5...]
@test_throws(Exception, append!(pos, "bad", rawdat))
rawdat = Float64[1:5...] * Unitful.A
@test_throws(Exception, append!(pos, "bad", rawdat))

#test bounds checking
rawdat = Int16[-5:1:5...] #negative samples for the positioner should be invalid
@test_throws(Exception, append!(pos, "bad", rawdat))
rawdat = Int16[-5:1:5...] * Unitful.V
@test_throws(Exception, append!(pos, "bad", rawdat))
rawdat = Int16[-5:1:5...] * Unitful.μm
@test_throws(Exception, append!(pos, "bad", rawdat))

#rename!
@test !isfree(pos)
@test_throws(Exception, rename!(pos, "mypiezo"))
c = ocpi1[findfirst(x->isfree(x), ocpi1)]
nm = name(c)
rename!(c, "new name")
@test name(c) == "new name"
rename!(c, nm)

#replace!
rawdat2 = Int16[typemax(Int16):-1:0...]
replace!(pos, "ramp_up", rawdat2)
@test_throws Exception replace!(pos, "alkjbroaj", rawdat2) #error because sequence does not exist
dat = get_samples(pos, "ramp_up")
@test dat[end] == mapper(pos).worldmin
@test dat[1] == mapper(pos).worldmax
rawdat3 = Int16[0;0;typemax(Int16)] #change length
replace!(pos, "ramp_up", rawdat3)
dat = get_samples(pos, "ramp_up")
@test dat[1] == mapper(pos).worldmin
@test dat[3] == mapper(pos).worldmax
@test length(pos) == 6

#pop!
pop!(pos)
dat = get_samples(pos, "ramp_up")
@test dat[1] == mapper(pos).worldmin
@test dat[3] == mapper(pos).worldmax
@test length(pos) == 3

#empty!
empty!(pos)
@test length(pos) == 0
@test length(sequence_lookup(pos)) != 0
append!(pos, "ramp_up")
empty!(pos; clear_library=true)
@test !haskey(sequence_lookup(pos), "ramp_up")

#append! volts and world units
newdat = Unitful.V * [0.0:0.1:10.0...]
append!(pos, "ramp_up", newdat)
dat = get_samples(pos, "ramp_up")
@test dat[1] == mapper(pos).worldmin
@test dat[end] == mapper(pos).worldmax

newdat = Unitful.μm * [0.0:0.8:800.0...]
replace!(pos, "ramp_up", newdat)
dat = get_samples(pos, "ramp_up")
@test dat[1] == mapper(pos).worldmin
@test dat[end] == mapper(pos).worldmax

lpos = length(pos)
append!(pos, "ramp_up2", newdat[1:5])
append!(pos, "ramp_up2") #append existing, not the first sequence
@test length(pos) == lpos + 10
@test all(get_samples(pos, "ramp_up2") .== get_samples(pos)[lpos+6:end])

#Test metadata retrieval functions
cs2 = chip_size("ocpi-2")
cs1 = chip_size("ocpi-1")
@test max_framerate("ocpi-2", cs2...) == 100.0*Unitful.s^-1
@test max_framerate("ocpi-2", cs2[1], div(cs2[2],2)) == 200.0*Unitful.s^-1
@test max_framerate("ocpi-1", cs1...) == 100.0*Unitful.s^-1
@test max_framerate("ocpi-1", cs1[1], div(cs1[2],2)) == 200.0*Unitful.s^-1

@test max_roi("ocpi-2", 100*Unitful.s^-1) == cs2
@test max_roi("ocpi-2", 200*Unitful.s^-1) == (cs2[1], floor(Int, cs2[2]/2))
@test max_roi("ocpi-1", 100*Unitful.s^-1) == cs1
@test max_roi("ocpi-1", 200*Unitful.s^-1) == (cs1[1], floor(Int, cs1[2]/2))

max_forks_repo_name: HolyLab/ImagineInterface


text:
# # Mesh of a lug plate

# The goal is to generate the mesh of the lug plate under plane-stress conditions, using four-node quadrilateral elements.
# The image below shows the resulting mesh, with the dimensions displayed in meters.

# ![Alt Mesh of the lug plate](http://hogwarts.ucsd.edu/~pkrysl/site.images/lug-mesh.png)

# The mesh will be generated by constructing simple pieces, merging the simple pieces into bigger meshes, and finally using mirroring to obtain the final mesh. The three simple pieces are shown in the image below: first we generate the red piece, which is a template of 1/4 of a plate with an elliptical hole. Then we generate the green piece as a 90-degree segment of an annulus. Finally we generate the blue piece as a simple block. These three pieces will be then merged into a single mesh.
# This is the mesh of half of the plate. The entire plate can be produced by mirroring this half.

# ![Alt Color-coded mesh of the lug plate](http://hogwarts.ucsd.edu/~pkrysl/site.images/lug-color-coded-50.png)

# First we bring in the packages that we will use. The finite element toolkit by itself has all we need for the mesh generation tasks.
using FinEtools

# The width of the plate is twice the radius of the half-circle with which the plate is rounded off.
R =  30.0*phun("mm");
# The hole for the clevis is of radius:
r =  10.0*phun("mm");
# The length of the blue piece of the mesh is:
H =  30.0*phun("mm");
# The numbers of the element edges: The number of edges radially
n1 = 7;
# and the number of edges across the half-width.
n4 = 6;
# Finally, this is the number of edges along the length within the blue piece of the mesh.
n5 = 5;

# The meshes for the three pieces will be stored in an array of tuples, one for each mesh.
meshes = Array{Tuple{FENodeSet, AbstractFESet},1}()

# First we use the function `Q4elliphole` to generate the red piece of the mesh.
xradius = r; yradius = r; L = R; H = R; nL = n4; nH = n4; nW = n1
fens,fes = Q4elliphole(xradius::FFlt, yradius::FFlt, L::FFlt, H::FFlt,
      nL::FInt, nH::FInt, nW::FInt)

# We can verify graphically that we obtained what we intended to get:
File =  "mesh1.vtk"
vtkexportmesh(File, fens, fes)
# If you have `paraview`, use the code fragment `@async run(`"paraview.exe" $File`);` to review the generated mesh.

# The generated mesh is pushed into the array of meshes.
push!(meshes, (fens, fes))

# Next we generate the second piece (the green one). It is also produced in the first quadrant of the Cartesian coordinate system.
rin = r; rex = R; nr = n1; nc = 2*n1; Angl = pi / 2
fens, fes = Q4annulus(rin::FFlt, rex::FFlt, nr::FInt, nc::FInt, Angl::FFlt)

# The mesh is rotated by 90° counterclockwise.
Q = [vec([0.0, 1.0]) vec([-1.0, 0.0])]
for i in 1:count(fens)
    fens.xyz[i, :] .=  Q * fens.xyz[i, :]
end

# The second mesh is also exported for viewing.
File =  "mesh2.vtk"
vtkexportmesh(File, fens, fes)

# The generated mesh is pushed into the array of meshes.
push!(meshes, (fens, fes))

# The third piece is a simple rectangular block.
Length = H; Width = R; nL = n5; nW = n4
fens, fes = Q4block(Length::FFlt, Width::FFlt, nL::FInt, nW::FInt)

# The block is translated to the right by `R`.
for i in 1:count(fens)
    fens.xyz[i, 1] += R
end

File =  "mesh3.vtk"
vtkexportmesh(File, fens, fes)

# The generated mesh is pushed into the array of meshes.
push!(meshes, (fens, fes))

# Now we merge together the three meshes stored in the array `meshes`.
# The nodes will be merged together if they are within the distance `tolerance`:
tolerance = r / n1 / 100

# This function merges together any number of meshes, and returns the merged nodes and an array of renumbered meshes.
fens, fesa = mergenmeshes(meshes, tolerance::FFlt)

# The finite element sets in the array `fesa` are concatenated into a single finite element set.
fes = cat(cat(fesa[1], fesa[2]), fesa[3])

# Again, we can review their current result of the meshing procedure. At this point we have one half of the plate meshed.
File =  "lug-half-mesh.vtk"
vtkexportmesh(File, fens, fes)

# In the final stages, we mirror the current mesh to get another finite element node set and set of finite elements. The renumbering function needs to be supplied so that the area of the mirrored quadrilaterals is positive.
fens1, fes1 = mirrormesh(fens, fes, vec([0.0, 1.0]), vec([0.0, 0.0]); renumb = (c) -> c[[1, 4, 3, 2]])

# Now the original finite element nodes and elements and the mirrored nodes and elements need to be merged into a single mesh.
fens, fes1, fes2  =  mergemeshes(fens1, fes1, fens, fes, tolerance);

# Again, we get renumbered finite element sets, and we can concatenate them into a single finite elements set.
fes = cat(fes1,fes2);

# This is the final mesh.
File =  "lug-mesh.vtk"
vtkexportmesh(File, fens, fes)

# We can verify that the merging did not result in any gaps or cracks by extracting the boundary of the final finite element set. It should consist of two pieces: the external curve consisting of three straight line segments and one semi-circle, and the internal curve in the form of a full circle.
bfes = meshboundary(fes)

File =  "lug-mesh-boundary.vtk"
vtkexportmesh(File, fens, bfes)

# Now view the resulting mesh and verify that it looks as the first image at the top. There should be 481 nodes and 424 quadrilateral finite elements.
@show count(fens), count(fes)
@show typeof(fes)

ext: jl


text:
#JOB FILEPATHS
#sample record and hmm serialisation output path
sample_output = "/bench/PhD/NGS_binaries/BBM/survey_samples"
hmm_output = "/bench/PhD/NGS_binaries/BBM/survey_chains"

#GENERAL SETUP
@info "Loading libraries..."
using BioBackgroundModels, DataFrames, Distributed, Serialization
include("/srv/git/rys_nucleosomes/aws/aws_wrangler.jl")

#JOB CONSTANTS
const replicates = 3 #repeat optimisation from this many seperately initialised samples from the prior
const Ks = [1,2,4,6] #mosaic class #s to test
const order_nos = [0,1,2] #DNA kmer order #s to test
const delta_thresh=1e-3 #stopping/convergence criterion (log probability difference btw subsequent EM iterates)
const max_iterates=15000

#LOAD SAMPLES
@info "Loading samples from $sample_output..."
sample_dfs = deserialize(sample_output)

#BUILD TRAINING AND TEST SETS FROM SAMPLES
training_sets, test_sets = split_obs_sets(sample_dfs)

#PROGRAMATICALLY GENERATE Chain_ID Vector
job_ids=Vector{Chain_ID}()
for (obs_id, obs) in training_sets, K in Ks, order in order_nos, rep in 1:replicates
    push!(job_ids, Chain_ID(obs_id, K, order, rep))
end

#DISTRIBUTED CLUSTER CONSTANTS
load_dict=Dict{Int64,LoadConfig}()
local_config=LoadConfig(1:6,2:2)
remote_config=LoadConfig(1:6,0:1)
aws_instance_config=LoadConfig(1:6,0:2)
remote_machine = "10.0.0.3"
no_local_processes = 1
no_remote_processes = 1
#SETUP DISTRIBUTED BAUM WELCH LEARNERS
@info "Spawning local cluster workers..."
worker_pool=addprocs(no_local_processes, topology=:master_worker)
for worker in worker_pool
    load_dict[worker]=local_config
end

remote_pool=addprocs([(remote_machine,no_remote_processes)], tunnel=true, topology=:master_worker)

for worker in remote_pool
    load_dict[worker]=remote_config
end

worker_pool=vcat(worker_pool, remote_pool)

# #AWS PARAMS
# @info "Setting up AWS wrangling..."

# security_group_name="calc1"
# security_group_desc="calculation group"
# ami="ami-02df7e1881a08f163"
# skeys="AWS"
# instance_type="c5.4xlarge"
# zone,spot_price=get_cheapest_zone(instance_type)
# no_instances=1
# instance_workers=8
# bid=spot_price+.01

# @assert bid >= spot_price

# @info "Wrangling AWS instances..."
# aws_ips = spot_wrangle(no_instances, bid, security_group_name, security_group_desc, skeys, zone, ami, instance_type)
# @info "Giving instances 90s to boot..."
# sleep(90)

# aws_ips = ["18.223.122.201"]

# @info "Spawning AWS cluster workers..."
# for ip in aws_ips
#     instance_pool=addprocs([(ip, instance_workers)], tunnel=true, topology=:master_worker, sshflags="-o StrictHostKeyChecking=no")
#     for worker in instance_pool
#         load_dict[worker]=aws_instance_config
#     end
#     global worker_pool=vcat(worker_pool, instance_pool)
# end

@info "Loading worker libraries everywhere..."
@everywhere using BioBackgroundModels
#INTIIALIZE HMMS
@info "Setting up HMMs..."
if isfile(hmm_output) #if some results have already been collected, load them
    @info "Loading incomplete results..."
    hmm_results_dict = deserialize(hmm_output)
else #otherwise, pass a new results dict
    @info "Initialising new HMM results file at $hmm_output"
    hmm_results_dict = Dict{Chain_ID,Vector{EM_step}}()
end

em_jobset = setup_EM_jobs!(job_ids, training_sets; chains=hmm_results_dict)
execute_EM_jobs!(worker_pool, em_jobset..., hmm_output; load_dict=load_dict, delta_thresh=delta_thresh, max_iterates=max_iterates)


text:
lines = readlines(ARGS[1])

function solution1(lines)
    total = 0
    for line in lines
        output = split(split(line, "|")[2])
        total += length([x for x in output if length(x) in [2, 3, 4, 7]])
    end
    return total
end

# T = Top
# UR = Upper Right
# LR = Lower Right
# M = Middle
# B = Bottom
# UL = Upper left
# LL = Lower Left

# 0 - T, UL, UR, LL, LR, B - count=6
# 1 - UR, LR - count=2
# 2 - T, M, B, UR, LL - count=5
# 3 - T, M, B, UR, LR - count=5
# 4 - M, UR, UL, LR - count=4
# 5 - T, M, B, UL, LR - count=5
# 6 - T, M, B, UL, LL, LR - count=6
# 7 - T, UR, LR - count=3
# 8 - T, M, B, UR, LR, UL, LL - count=7
# 9 - T, M, B, UR, LR, UL  - count=6
render_dict = Dict()
render_dict[Set(["T", "UL", "UR", "LL", "LR", "B"])] = 0
render_dict[Set(["UR", "LR"])] = 1
render_dict[Set(["T", "M", "B", "UR", "LL"])] = 2
render_dict[Set(["T", "M", "B", "UR", "LR"])] = 3
render_dict[Set(["M", "UR", "UL", "LR"])] = 4
render_dict[Set(["T", "M", "B", "UL", "LR"])] = 5
render_dict[Set(["T", "M", "B", "UL", "LL", "LR"])] = 6
render_dict[Set(["T", "UR", "LR"])] = 7
render_dict[Set(["T", "M", "B", "UR", "LR", "UL", "LL"])] = 8
render_dict[Set(["T", "M", "B", "UR", "LR", "UL"])] = 9

# T = set(size=3) - set(size=2)
# UR = count(8) from set(size=2)
# LR = count(9) from set(size=2)
# M = count(7) from set(size=4) - UR,LR
# UL = remaining from set(size=4) - UR,LR,M
# B = remaining from set(size=5) that contains T,M,UL,LR
# LL = remaining

function get_top(groups)
    group_size_3 = [g for g in groups if length(g) == 3][1]
    group_size_2 = [g for g in groups if length(g) == 2][1]
    return [char for char in setdiff(group_size_3, group_size_2)][1]
end

function get_upper_right(groups)
    group_size_2 = [g for g in groups if length(g) == 2][1]
    counts = Dict()
    for char in group_size_2
        count = 0
        for group in groups
            if in(char, group)
                count += 1
            end
        end
        counts[count] = char
    end
    return counts[8], counts[9]
end

function get_middle(groups)
    group_size_4 = [g for g in groups if length(g) == 4][1]
    group_size_2 = [g for g in groups if length(g) == 2][1]
    diff_group = setdiff(group_size_4, group_size_2)
    counts = Dict()
    for char in diff_group
        count = 0
        for group in groups
            if in(char, group)
                count += 1
            end
        end
        counts[count] = char
    end
    return counts[7]

end

function get_upper_left(groups, loc_map)
    group_size_4 = [g for g in groups if length(g) == 4][1]
    return [x for x in setdiff(group_size_4, Set([loc_map["UR"], loc_map["LR"], loc_map["M"]]))][1]
end

function get_bottom(groups, loc_map)
    # B = remaining from set(size=5) that contains T,M,UL,LR
    size_5_groups = [g for g in groups if length(g) == 5]

    for s5group in size_5_groups
        diff = setdiff(s5group, Set([loc_map["T"], loc_map["M"], loc_map["UL"], loc_map["LR"]]))
        if length(diff) == 1
            if in(loc_map["T"], s5group) && in(loc_map["M"], s5group) && in(loc_map["UL"], s5group) && in(loc_map["LR"], s5group)
                return [d for d in diff][1]
            end

        end
    end
end

function get_lower_left(groups, loc_map)
    group_size_7 = [g for g in groups if length(g) == 7][1]
    return [x for x in setdiff(group_size_7, Set([
        loc_map["T"], loc_map["M"], loc_map["UL"], loc_map["LR"], loc_map["UR"], loc_map["B"]
    ]))][1]
end

function decode_input(input)
    loc_map = Dict()
    groups = [Set(x) for x in input]
    loc_map["T"] = get_top(groups)
    (loc_map["UR"], loc_map["LR"]) = get_upper_right(groups)
    loc_map["M"] = get_middle(groups)
    loc_map["UL"] = get_upper_left(groups, loc_map)
    loc_map["B"] = get_bottom(groups, loc_map)
    loc_map["LL"] = get_lower_left(groups, loc_map)
    reverse_map = Dict()
    for key in keys(loc_map)
        reverse_map[loc_map[key]] = key
    end
    return reverse_map
end

function render_output(output, decode_map)
    groups = [Set(x) for x in output]
    total = 0
    for (i, group) in enumerate(groups)
        decoded_set = Set([decode_map[x] for x in group])
        total += render_dict[decoded_set] * 10^(4 - i)
    end
    return total
end

function solution2(lines)
    total = 0
    for line in lines
        input = split(split(line, "|")[1])
        output = split(split(line, "|")[2])
        decoded = decode_input(input)
        total += render_output(output, decoded)
        # break
    end
    return total
end

println(solution1(lines))

println(solution2(lines))


text:
using Test
using PrettyNumbers

@testset "General test" verbose = true begin
    include("./general.jl")
end

@testset "Text backend" verbose = true begin
    include("./text_backend.jl")
end


text:
module Fastfood

using Hadamard
using Distributions
using Random
using LinearAlgebra

export FastfoodParam, FastfoodKernel

struct FastfoodParam
    B::AbstractArray  # Binary scaling matrix
    G::AbstractArray  # Gaussian scaling matrix
    PI::AbstractArray # Permutation matrix
    S::AbstractArray  # Scaling matrix
    function FastfoodParam(n::Integer, d::Integer;
                           rng::AbstractRNG=MersenneTwister())

        d = 2^ceil(Integer, log2(d))
        k = ceil(Integer, n/d)
        n = d*k

        B = rand(rng, [-1, 1], d, k)
        G = randn(rng, d, k);
        PI = zeros(Integer, d, k)
        for i in 1:k
            PI[:,i] = randperm(d)
        end
        S = rand(Chi(1), d * k)*norm(G)^(1/2)

        return new(B, G, PI, S)
    end
end

function FastfoodKernel(X::Matrix, param::FastfoodParam;
                        sgm::Float64=1.0)
    d0, m = size(X)
    d = 2^ceil(Integer, log2(d0))

    if d == d0
        XX = X
    else
        # expand the data dimension to a power of 2.
        XX = zeros(d, m)
        XX[1:d0, :] = X
    end

    k = size(param.B, 2)
    n = d * k
    THT = zeros(n, m)

    for i = 1:k
        B = param.B[:, i]
        G = param.G[:, i]
        PI = param.PI[:, i]
        XX = broadcast(*, XX, B)
        T = fwht(XX, 1)
        T = T[PI, :]
        T = broadcast(*, T, G*d)
        THT[((i-1)*d+1):(i*d), :] = fwht(T, 1)
    end

    THT = broadcast(*, THT, param.S*d^(1/2))
    T = THT/sgm
    PHI = [cos.(T); sin.(T)]*n^(-1/2)

    return PHI
end

end # module


text:
struct FashionMNIST <: Name end

# download options
task(::Type{FashionMNIST}) = MultiClass
format(::Type{FashionMNIST}) = GrayImages
source(::Type{FashionMNIST}) = "https://github.com/zalandoresearch/fashion-FashionMNIST"
make_datadep(::Type{FashionMNIST}) = nothing
loadraw(::Type{FashionMNIST}, type) = loadraw_mldatasets(MLDatasets.FashionMNIST, type)

nclasses(::Type{FashionMNIST}) = 10
classes(::Type{FashionMNIST}) = collect(0:9)
classes_orig(::Type{FashionMNIST}) = [ "T-Shirt", "Trouser", "Pullover", "Dress", "Coat", "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]
nattributes(::Type{FashionMNIST}) = (28, 28)
ninstances(::Type{FashionMNIST}) = (60000, 0, 10000)

# dataset description
name(::Type{FashionMNIST}) = "Fashion-MNIST"
author(::Type{FashionMNIST}) = ["Han Xiao", "Kashif Rasul", "Roland Vollgraf"]
licence(::Type{FashionMNIST}) = "MIT"

function citation(::Type{FashionMNIST})
    return """
    @article{xiao2017fashion,
        title = {Fashion-mnist: a novel image dataset for benchmarking machine learning algorithms},
        author = {Xiao, Han and Rasul, Kashif and Vollgraf, Roland},
        journal = {arXiv preprint arXiv:1708.07747},
        year = {2017}
    }
    """
end

max_stars_repo_name: VaclavMacha/DatasetProvider

max_issues_repo_name: VaclavMacha/DatasetProvider

max_forks_repo_name: VaclavMacha/DatasetProvider


text:
using DataFrames
using MLJ
using CSV
using Logging

function make_artifacts(data_path, target, target_type, export_location, estimator)
    @info "loading $data_path"
    df = DataFrame(CSV.File(data_path))
    y, X = unpack(df, ==(Symbol(target)), colname -> true);
    @info "dropping id columns if present"
    try
        X = select!(X, Not(Symbol("objid")))
    catch
    end
    try
        X = select!(X, Not(Symbol("Id")))
    catch
    end
    X = coalesce.(X,-99999)
    tree = estimator()
    if target_type == "regression"
        @info "training regression estimator"
        ml = machine(tree, X, float(y))
    else
        @info "training classification estimator"
        ml = machine(tree, X, categorical(y))
    end
    train, test = partition(eachindex(y), 0.7, shuffle=true); # 70:30 split
    fit!(ml, rows=train, verbosity=0)
    @info "writing model to disk at $export_location"
    MLJ.save(export_location, ml)
end

## regression model details
regression_data = "tests/testdata/juniors_3_year_stats_regression.csv"
regression_target = "Grade 2014"
regression_output = "tests/fixtures/drop_in_model_artifacts/grade_regression.jlso"

binary_data = "tests/testdata/iris_binary_training.csv"
binary_target = "Species"
binary_output = "tests/fixtures/drop_in_model_artifacts/iris_binary.jlso"

multiclass_data = "tests/testdata/skyserver_sql2_27_2018_6_51_39_pm.csv"
multiclass_target = "class"
multiclass_output = "tests/fixtures/drop_in_model_artifacts/galaxy.jlso"

RandomForestRegressor = @load RandomForestRegressor pkg="ScikitLearn"
RandomForestClassifier = @load RandomForestClassifier pkg="ScikitLearn"

make_artifacts(regression_data, regression_target, "regression", regression_output, RandomForestRegressor)
make_artifacts(binary_data, binary_target, "classification", binary_output, RandomForestClassifier)
make_artifacts(multiclass_data, multiclass_target, "classification", multiclass_output, RandomForestClassifier)

max_stars_repo_name: andreakropp/datarobot-user-models

max_issues_repo_name: andreakropp/datarobot-user-models

max_forks_repo_name: andreakropp/datarobot-user-models


text:
using TerminalUserInterfaces
const TUI = TerminalUserInterfaces
using Random

function main()
    TUI.initialize()
    y, x = 1, 1

    count = 1
    t = TUI.Terminal()

    # TUI.enableRawMode()
    TUI.clear_screen()
    TUI.hide_cursor()

    words = repeat("The Quick Brown Fox Jumps Over The Lazy Dog. ", 60)

    rng = MersenneTwister()
    styles = [
        TUI.Crayon(bold = true)
        TUI.Crayon(italics = true)
        TUI.Crayon(foreground = :red)
        TUI.Crayon(foreground = :blue)
        TUI.Crayon(foreground = :green)
        TUI.Crayon(bold = true, foreground = :red)
        TUI.Crayon(bold = true, foreground = :blue)
        TUI.Crayon(bold = true, foreground = :green)
        TUI.Crayon(italics = true, foreground = :red)
        TUI.Crayon(italics = true, foreground = :blue)
        TUI.Crayon(italics = true, foreground = :green)
        TUI.Crayon()
    ]

    words = [TUI.Word(word, styles[rand(rng, 1:length(styles))]) for word in split(words)]

    scroll = 1

    while true

        w, h = TUI.terminal_size()

        r = TUI.Rect(x, y, w, 35)

        b = TUI.Block(title = "Paragraph example")
        p = TUI.Paragraph(
            b,
            words,
            scroll,
        )

        TUI.draw(t, p, r)

        TUI.flush(t, false)

        count += 1

        c = TUI.get_event(t)

        if c == 'j'
            scroll += 1
        elseif c == 'k'
            scroll -= 1
        elseif c == 'q'
            break
        elseif c == '\x03'
            # keyboard interrupt
            break
        end
        if scroll < 1
            scroll = 1
        end
        if scroll > p.number_of_lines[]
            scroll = p.number_of_lines[]
        end

    end

    TUI.cleanup()

end

main()


text:
using RunTests
using Base.Test
import MetaTools.@commutative

@testmodule ParsedFunctionTests begin

using MetaTools

type AnyLineNumber end

const ANY_LINE_NUMBER = AnyLineNumber()

Base.isequal(x::AnyLineNumber, y::AnyLineNumber) = error("Can not compare ANY_LINE_NUMBER with itself")
@commutative Base.isequal(x::AnyLineNumber, y::WeakRef) = false
@commutative Base.isequal(x::AnyLineNumber, y::LineNumberNode) = true
@commutative Base.isequal(x::AnyLineNumber, y::Expr) = (y.head == :line)
@commutative Base.isequal(x::AnyLineNumber, y::Any) = false

module MetaTestModule1
  module MetaTestModule2
    module MetaTestModule3
      function hello()
      end
    end
    function hello()
    end
  end
  function hello()
  end
end

test_functions = [(ParsedFunction,), (x->ParsedFunction(emit(ParsedFunction(x))),) ]

@parameterize test_functions function test_empty_method_with_no_args(test_function)
  func = test_function(:(function hello() end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_method_with_no_args_and_bracketed_name(test_function)
  func = test_function(:(function (hello)() end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_method_with_one_untyped_arg(test_function)
  func = test_function(:(function hello(x) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_method_with_two_untyped_args(test_function)
  func = test_function(:(function hello(x,y) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :Any
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
end

@parameterize test_functions function test_empty_method_with_one_typed_arg(test_function)
  func = test_function(:(function hello(x::Integer) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_method_with_two_typed_args(test_function)
  func = test_function(:(function hello(x::Integer, y::FloatingPoint) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :FloatingPoint
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
end

@parameterize test_functions function test_empty_method_with_one_union_typed_arg(test_function)
  func = test_function(:(function hello(x::Union(Integer,FloatingPoint)) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :(Union(Integer, FloatingPoint))
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_method_with_one_untyped_default_arg(test_function)
  func = test_function(:(function hello(x=100) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test func.args[1].default == 100
end

@parameterize test_functions function test_empty_method_with_two_untyped_default_args(test_function)
  func = test_function(:(function hello(x=100,y=200) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test func.args[1].default == 100
  @test func.args[2].name == :y
  @test func.args[2].typ == :Any
  @test func.args[2].varargs == false
  @test func.args[2].default == 200
end

@parameterize test_functions function test_empty_method_with_one_typed_default_arg(test_function)
  func = test_function(:(function hello(x::Integer=100) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test func.args[1].default == 100
end

@parameterize test_functions function test_empty_method_with_two_typed_default_args(test_function)
  func = test_function(:(function hello(x::Integer=100, y::FloatingPoint=200.0) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test func.args[1].default == 100
  @test func.args[2].name == :y
  @test func.args[2].typ == :FloatingPoint
  @test func.args[2].varargs == false
  @test func.args[2].default == 200.0
end

@parameterize test_functions function test_empty_method_with_one_untyped_vararg(test_function)
  func = test_function(:(function hello(x...) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == true
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_method_with_one_typed_vararg(test_function)
  func = test_function(:(function hello(x::Integer...) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == true
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_method_with_one_untyped_default_vararg(test_function)
  func = test_function(:(function hello(x...=100) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == true
  @test func.args[1].default == 100
end

@parameterize test_functions function test_empty_method_with_one_typed_default_vararg(test_function)
  func = test_function(:(function hello(x::Integer...=100) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == true
  @test func.args[1].default == 100
end

@parameterize test_functions function test_empty_method_with_one_untyped_kwarg(test_function)
  func = test_function(:(function hello(;x=100) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 1
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Any
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
end

@parameterize test_functions function test_empty_method_with_two_untyped_kwargs(test_function)
  func = test_function(:(function hello(;x=100,y=200) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 2
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Any
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
  @test func.kwargs[2].name == :y
  @test func.kwargs[2].typ == :Any
  @test func.kwargs[2].varargs == false
  @test func.kwargs[2].default == 200
end

@parameterize test_functions function test_empty_method_with_one_typed_kwarg(test_function)
  func = test_function(:(function hello(;x::Integer=100) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 1
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Integer
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
end

@parameterize test_functions function test_empty_method_with_two_typed_kwargs(test_function)
  func = test_function(:(function hello(;x::Integer=100, y::FloatingPoint=200.0) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 2
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Integer
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
  @test func.kwargs[2].name == :y
  @test func.kwargs[2].typ == :FloatingPoint
  @test func.kwargs[2].varargs == false
  @test func.kwargs[2].default == 200.0
end

@parameterize test_functions function test_empty_method_with_one_union_typed_kwarg(test_function)
  func = test_function(:(function hello(;x::Union(Integer, FloatingPoint)=100) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 1
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :(Union(Integer, FloatingPoint))
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
end

@parameterize test_functions function test_empty_method_with_one_untyped_varkwarg(test_function)
  func = test_function(:(function hello(;x...) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 1
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Any
  @test func.kwargs[1].varargs == true
  @test isdefined(func.kwargs[1], :default) == false
end

@parameterize test_functions function test_empty_method_with_one_typed_varkwarg(test_function)
  func = test_function(:(function hello(;x::Array...) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 1
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Array
  @test func.kwargs[1].varargs == true
  @test isdefined(func.kwargs[1], :default) == false
end

@parameterize test_functions function test_empty_method_with_a_mix_of_args_and_kwargs(test_function)
  func = test_function(:(function hello(x,y::Integer,z=99,rest...;a::Integer=100,b=200,c...) end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.body == quote end

  @test length(func.args) == 4
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :Integer
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
  @test func.args[3].name == :z
  @test func.args[3].typ == :Any
  @test func.args[3].varargs == false
  @test func.args[3].default == 99
  @test func.args[4].name == :rest
  @test func.args[4].typ == :Any
  @test func.args[4].varargs == true
  @test isdefined(func.args[4], :default) == false

  @test length(func.kwargs) == 3
  @test func.kwargs[1].name == :a
  @test func.kwargs[1].typ == :Integer
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
  @test func.kwargs[2].name == :b
  @test func.kwargs[2].typ == :Any
  @test func.kwargs[2].varargs == false
  @test func.kwargs[2].default == 200
  @test func.kwargs[3].name == :c
  @test func.kwargs[3].typ == :Any
  @test func.kwargs[3].varargs == true
  @test isdefined(func.kwargs[3], :default) == false
end

@parameterize test_functions function test_empty_method_with_namespace_1_deep(test_function)
  func = test_function(:(function MetaTestModule1.hello() end))
  @test func.name == :hello
  @test func.namespace == [:MetaTestModule1]
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_method_with_namespace_2_deep(test_function)
  func = test_function(:(function MetaTestModule1.MetaTestModule2.hello() end))
  @test func.name == :hello
  @test func.namespace == [:MetaTestModule1, :MetaTestModule2]
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_method_with_namespace_3_deep(test_function)
  func = test_function(:(function MetaTestModule1.MetaTestModule2.MetaTestModule3.hello() end))
  @test func.name == :hello
  @test func.namespace == [:MetaTestModule1, :MetaTestModule2, :MetaTestModule3]
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_method_with_no_type_parameter(test_function)
  func = test_function(:(function hello() end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_method_with_one_type_parameter(test_function)
  func = test_function(:(function hello{T}() end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test func.types == [:T]
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_method_with_two_type_parameters(test_function)
  func = test_function(:(function hello{T1, T2}() end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test func.types == [:T1, :T2]
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_method_with_namespace_3_deep_and_a_type_parameter(test_function)
  func = test_function(:(function MetaTestModule1.MetaTestModule2.MetaTestModule3.hello{T}() end))
  @test func.name == :hello
  @test func.namespace == [:MetaTestModule1, :MetaTestModule2, :MetaTestModule3]
  @test func.types == [:T]
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

#############################################################################

@parameterize test_functions function test_empty_shorthand_method_with_no_args(test_function)
  func = test_function(:(hello() = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_shorthand_method_with_no_args_and_bracketed_name(test_function)
  func = test_function(:((hello)() = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_shorthand_method_with_one_untyped_arg(test_function)
  func = test_function(:(hello(x) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_shorthand_method_with_two_untyped_args(test_function)
  func = test_function(:(hello(x,y) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :Any
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
end

@parameterize test_functions function test_empty_shorthand_method_with_one_typed_arg(test_function)
  func = test_function(:(hello(x::Integer) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_shorthand_method_with_two_typed_args(test_function)
  func = test_function(:(hello(x::Integer, y::FloatingPoint) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :FloatingPoint
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
end

@parameterize test_functions function test_empty_shorthand_method_with_one_union_typed_arg(test_function)
  func = test_function(:(hello(x::Union(Integer,FloatingPoint)) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :(Union(Integer, FloatingPoint))
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_shorthand_method_with_one_untyped_default_arg(test_function)
  func = test_function(:(hello(x=100) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test func.args[1].default == 100
end

@parameterize test_functions function test_empty_shorthand_method_with_two_untyped_default_args(test_function)
  func = test_function(:(hello(x=100,y=200) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test func.args[1].default == 100
  @test func.args[2].name == :y
  @test func.args[2].typ == :Any
  @test func.args[2].varargs == false
  @test func.args[2].default == 200
end

@parameterize test_functions function test_empty_shorthand_method_with_one_typed_default_arg(test_function)
  func = test_function(:(hello(x::Integer=100) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test func.args[1].default == 100
end

@parameterize test_functions function test_empty_shorthand_method_with_two_typed_default_args(test_function)
  func = test_function(:(hello(x::Integer=100, y::FloatingPoint=200.0) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test func.args[1].default == 100
  @test func.args[2].name == :y
  @test func.args[2].typ == :FloatingPoint
  @test func.args[2].varargs == false
  @test func.args[2].default == 200.0
end

@parameterize test_functions function test_empty_shorthand_method_with_one_untyped_vararg(test_function)
  func = test_function(:(hello(x...) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == true
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_shorthand_method_with_one_typed_vararg(test_function)
  func = test_function(:(hello(x::Integer...) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == true
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_shorthand_method_with_one_untyped_default_vararg(test_function)
  func = test_function(:(hello(x...=100) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == true
  @test func.args[1].default == 100
end

@parameterize test_functions function test_empty_shorthand_method_with_one_typed_default_vararg(test_function)
  func = test_function(:(hello(x::Integer...=100) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == true
  @test func.args[1].default == 100
end

@parameterize test_functions function test_empty_shorthand_method_with_one_untyped_kwarg(test_function)
  func = test_function(:(hello(;x=100) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 1
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Any
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
end

@parameterize test_functions function test_empty_shorthand_method_with_two_untyped_kwargs(test_function)
  func = test_function(:(hello(;x=100,y=200) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 2
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Any
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
  @test func.kwargs[2].name == :y
  @test func.kwargs[2].typ == :Any
  @test func.kwargs[2].varargs == false
  @test func.kwargs[2].default == 200
end

@parameterize test_functions function test_empty_shorthand_method_with_one_typed_kwarg(test_function)
  func = test_function(:(hello(;x::Integer=100) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 1
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Integer
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
end

@parameterize test_functions function test_empty_shorthand_method_with_two_typed_kwargs(test_function)
  func = test_function(:(hello(;x::Integer=100, y::FloatingPoint=200.0) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 2
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Integer
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
  @test func.kwargs[2].name == :y
  @test func.kwargs[2].typ == :FloatingPoint
  @test func.kwargs[2].varargs == false
  @test func.kwargs[2].default == 200.0
end

@parameterize test_functions function test_empty_shorthand_method_with_one_union_typed_kwarg(test_function)
  func = test_function(:(hello(;x::Union(Integer, FloatingPoint)=100) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 1
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :(Union(Integer, FloatingPoint))
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
end

@parameterize test_functions function test_empty_shorthand_method_with_one_untyped_varkwarg(test_function)
  func = test_function(:(hello(;x...) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 1
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Any
  @test func.kwargs[1].varargs == true
  @test isdefined(func.kwargs[1], :default) == false
end

@parameterize test_functions function test_empty_shorthand_method_with_one_typed_varkwarg(test_function)
  func = test_function(:(hello(;x::Integer...) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.args == []
  @test func.body == quote end

  @test length(func.kwargs) == 1
  @test func.kwargs[1].name == :x
  @test func.kwargs[1].typ == :Integer
  @test func.kwargs[1].varargs == true
  @test isdefined(func.kwargs[1], :default) == false
end

@parameterize test_functions function test_empty_shorthand_method_with_a_mix_of_args_and_kwargs(test_function)
  func = test_function(:(hello(x,y::Integer,z=99,rest...;a::Integer=100,b=200,c...) = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test func.body == quote end

  @test length(func.args) == 4
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :Integer
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
  @test func.args[3].name == :z
  @test func.args[3].typ == :Any
  @test func.args[3].varargs == false
  @test func.args[3].default == 99
  @test func.args[4].name == :rest
  @test func.args[4].typ == :Any
  @test func.args[4].varargs == true
  @test isdefined(func.args[4], :default) == false

  @test length(func.kwargs) == 3
  @test func.kwargs[1].name == :a
  @test func.kwargs[1].typ == :Integer
  @test func.kwargs[1].varargs == false
  @test func.kwargs[1].default == 100
  @test func.kwargs[2].name == :b
  @test func.kwargs[2].typ == :Any
  @test func.kwargs[2].varargs == false
  @test func.kwargs[2].default == 200
  @test func.kwargs[3].name == :c
  @test func.kwargs[3].typ == :Any
  @test func.kwargs[3].varargs == true
  @test isdefined(func.kwargs[3], :default) == false
end

@parameterize test_functions function test_empty_shorthand_method_with_namespace_1_deep(test_function)
  func = test_function(:(MetaTestModule1.hello() = begin end))
  @test func.name == :hello
  @test func.namespace == [:MetaTestModule1]
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_shorthand_method_with_namespace_2_deep(test_function)
  func = test_function(:(MetaTestModule1.MetaTestModule2.hello() = begin end))
  @test func.name == :hello
  @test func.namespace == [:MetaTestModule1, :MetaTestModule2]
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_shorthand_method_with_namespace_3_deep(test_function)
  func = test_function(:(MetaTestModule1.MetaTestModule2.MetaTestModule3.hello() = begin end))
  @test func.name == :hello
  @test func.namespace == [:MetaTestModule1, :MetaTestModule2, :MetaTestModule3]
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_shorthand_method_with_no_type_parameter(test_function)
  func = test_function(:(hello() = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_shorthand_method_with_one_type_parameter(test_function)
  func = test_function(:(hello{T}() = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test func.types == [:T]
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_shorthand_method_with_two_type_parameters(test_function)
  func = test_function(:(hello{T1, T2}() = begin end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test func.types == [:T1, :T2]
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_shorthand_method_with_namespace_3_deep_and_a_type_parameter(test_function)
  func = test_function(:(MetaTestModule1.MetaTestModule2.MetaTestModule3.hello{T}() = begin end))
  @test func.name == :hello
  @test func.namespace == [:MetaTestModule1, :MetaTestModule2, :MetaTestModule3]
  @test func.types == [:T]
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

#############################################################################

@parameterize test_functions function test_empty_lambda_with_no_args(test_function)
  func = test_function(:(() -> begin end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_lambda_with_one_untyped_arg(test_function)
  func = test_function(:((x) -> begin end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_lambda_with_two_untyped_args(test_function)
  func = test_function(:((x,y) -> begin end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :Any
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
end

@parameterize test_functions function test_empty_lambda_with_one_typed_arg(test_function)
  func = test_function(:((x::Integer) -> begin end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_lambda_with_two_typed_args(test_function)
  func = test_function(:((x::Integer, y::FloatingPoint) -> begin end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :FloatingPoint
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
end

@parameterize test_functions function test_empty_lambda_with_one_union_typed_arg(test_function)
  func = test_function(:((x::Union(Integer,FloatingPoint)) -> begin end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :(Union(Integer, FloatingPoint))
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_lambda_with_one_untyped_vararg(test_function)
  func = test_function(:((x...) -> begin end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == true
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_lambda_with_one_typed_vararg(test_function)
  func = test_function(:((x::Integer...) -> begin end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == true
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_lambda_with_a_mix_of_args(test_function)
  func = test_function(:((x,y::Integer,z...) -> begin end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test func.body == quote end

  @test length(func.args) == 3
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :Integer
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
  @test func.args[3].name == :z
  @test func.args[3].typ == :Any
  @test func.args[3].varargs == true
  @test isdefined(func.args[3], :default) == false

  @test isdefined(func, :kwargs) == false
end

#############################################################################

@parameterize test_functions function test_empty_anonymous_function_with_no_args(test_function)
  func = test_function(:(function() end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end
  @test func.args == []
end

@parameterize test_functions function test_empty_anonymous_function_with_one_untyped_arg(test_function)
  func = test_function(:(function(x) end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_anonymous_function_with_two_untyped_args(test_function)
  func = test_function(:(function(x,y) end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :Any
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
end

@parameterize test_functions function test_empty_anonymous_function_with_one_typed_arg(test_function)
  func = test_function(:(function(x::Integer) end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_anonymous_function_with_two_typed_args(test_function)
  func = test_function(:(function(x::Integer, y::FloatingPoint) end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 2
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :FloatingPoint
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
end

@parameterize test_functions function test_empty_anonymous_function_with_one_union_typed_arg(test_function)
  func = test_function(:(function(x::Union(Integer,FloatingPoint)) end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :(Union(Integer, FloatingPoint))
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_anonymous_function_with_one_untyped_vararg(test_function)
  func = test_function(:(function(x...) end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == true
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_anonymous_function_with_one_typed_vararg(test_function)
  func = test_function(:(function(x::Integer...) end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == quote end

  @test length(func.args) == 1
  @test func.args[1].name == :x
  @test func.args[1].typ == :Integer
  @test func.args[1].varargs == true
  @test isdefined(func.args[1], :default) == false
end

@parameterize test_functions function test_empty_anonymous_function_with_a_mix_of_args(test_function)
  func = test_function(:(function(x,y::Integer,z...) end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test func.body == quote end

  @test length(func.args) == 3
  @test func.args[1].name == :x
  @test func.args[1].typ == :Any
  @test func.args[1].varargs == false
  @test isdefined(func.args[1], :default) == false
  @test func.args[2].name == :y
  @test func.args[2].typ == :Integer
  @test func.args[2].varargs == false
  @test isdefined(func.args[2], :default) == false
  @test func.args[3].name == :z
  @test func.args[3].typ == :Any
  @test func.args[3].varargs == true
  @test isdefined(func.args[3], :default) == false

  @test isdefined(func, :kwargs) == false
end

#############################################################################

@parameterize test_functions function test_method_with_a_numeric_literal_body(test_function)
  func = test_function(:(function hello() 10 end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, ANY_LINE_NUMBER, 10)
  @test func.args == []
end

@parameterize test_functions function test_shorthand_method_with_a_numeric_literal_body(test_function)
  func = test_function(:(hello() = 10))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, 10)
  @test func.args == []
end

@parameterize test_functions function test_lambda_with_a_numeric_literal_body(test_function)
  func = test_function(:(() -> 10))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, ANY_LINE_NUMBER, 10)
  @test func.args == []
end

@parameterize test_functions function test_anonymous_function_with_a_numeric_literal_body(test_function)
  func = test_function(:(function() 10 end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, ANY_LINE_NUMBER, 10)
  @test func.args == []
end

#----------------------------------------------------------------------------

@parameterize test_functions function test_method_with_a_symbol_body(test_function)
  func = test_function(:(function hello() x end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, ANY_LINE_NUMBER, :x)
  @test func.args == []
end

@parameterize test_functions function test_shorthand_method_with_a_symbol_body(test_function)
  func = test_function(:(hello() = x))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, :x)
  @test func.args == []
end

@parameterize test_functions function test_lambda_with_a_symbol_body(test_function)
  func = test_function(:(() -> x))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, ANY_LINE_NUMBER, :x)
  @test func.args == []
end

@parameterize test_functions function test_anonymous_function_with_a_symbol_body(test_function)
  func = test_function(:(function() x end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, ANY_LINE_NUMBER, :x)
  @test func.args == []
end

#----------------------------------------------------------------------------

@parameterize test_functions function test_method_with_a_expression_body(test_function)
  func = test_function(:(function hello() x + 10 end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, ANY_LINE_NUMBER, Expr(:call, :+, :x, 10))
  @test func.args == []
end

@parameterize test_functions function test_shorthand_method_with_a_expression_body(test_function)
  func = test_function(:(hello() = x + 10))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:call, :+, :x, 10)
  @test func.args == []
end

@parameterize test_functions function test_lambda_with_a_expression_body(test_function)
  func = test_function(:(() -> x + 10))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, ANY_LINE_NUMBER, Expr(:call, :+, :x, 10))
  @test func.args == []
end

@parameterize test_functions function test_anonymous_function_with_a_expression_body(test_function)
  func = test_function(:(function() x + 10 end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block, ANY_LINE_NUMBER, Expr(:call, :+, :x, 10))
  @test func.args == []
end

#----------------------------------------------------------------------------

@parameterize test_functions function test_method_with_a_multiline_body(test_function)
  func = test_function(:(function hello()
                            y = x + 10
                            y += some_func(z)
                            return y
                          end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block,
                          ANY_LINE_NUMBER,
                          Expr(:(=), :y, Expr(:call, :+, :x, 10)),
                          ANY_LINE_NUMBER,
                          Expr(:(+=), :y, Expr(:call, :some_func, :z)),
                          ANY_LINE_NUMBER,
                          Expr(:return, :y),
                          )
  @test func.args == []
end

@parameterize test_functions function test_shorthand_method_with_a_multiline_body_with_begin_end(test_function)
  func = test_function(:(hello() = begin
                            y = x + 10
                            y += some_func(z)
                            return y
                          end))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block,
                          ANY_LINE_NUMBER,
                          Expr(:(=), :y, Expr(:call, :+, :x, 10)),
                          ANY_LINE_NUMBER,
                          Expr(:(+=), :y, Expr(:call, :some_func, :z)),
                          ANY_LINE_NUMBER,
                          Expr(:return, :y),
                          )
  @test func.args == []
end

@parameterize test_functions function test_shorthand_method_with_a_multiline_body_with_brackets(test_function)
  func = test_function(:(hello() = (y = x + 10;
                                     y += some_func(z);
                                     return y)))
  @test func.name == :hello
  @test isdefined(func, :namespace) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block,
                          Expr(:(=), :y, Expr(:call, :+, :x, 10)),
                          Expr(:(+=), :y, Expr(:call, :some_func, :z)),
                          Expr(:return, :y),
                          )
  @test func.args == []
end

@parameterize test_functions function test_Lambda_with_a_multiline_body_with_begin_end(test_function)
  func = test_function(:(() -> begin
                            y = x + 10
                            y += some_func(z)
                            return y
                          end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block,
                          ANY_LINE_NUMBER,
                          Expr(:(=), :y, Expr(:call, :+, :x, 10)),
                          ANY_LINE_NUMBER,
                          Expr(:(+=), :y, Expr(:call, :some_func, :z)),
                          ANY_LINE_NUMBER,
                          Expr(:return, :y),
                          )
  @test func.args == []
end

@parameterize test_functions function test_Lambda_with_a_multiline_body_with_brackets(test_function)
  func = test_function(:(() -> (y = x + 10;
                                 y += some_func(z);
                                 return y)))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block,
                          Expr(:(=), :y, Expr(:call, :+, :x, 10)),
                          Expr(:(+=), :y, Expr(:call, :some_func, :z)),
                          Expr(:return, :y),
                          )
  @test func.args == []
end

@parameterize test_functions function test_anonymous_function_with_a_multiline_body(test_function)
  func = test_function(:(function()
                            y = x + 10
                            y += some_func(z)
                            return y
                          end))
  @test isdefined(func, :name) == false
  @test isdefined(func, :types) == false
  @test isdefined(func, :kwargs) == false
  @test func.body == Expr(:block,
                          ANY_LINE_NUMBER,
                          Expr(:(=), :y, Expr(:call, :+, :x, 10)),
                          ANY_LINE_NUMBER,
                          Expr(:(+=), :y, Expr(:call, :some_func, :z)),
                          ANY_LINE_NUMBER,
                          Expr(:return, :y),
                          )
  @test func.args == []
end

end


text:
using Plots
include_ddp()

# Model
include_model("quadrotor")

# Time
T = 101
h = 0.1

# sigmoid(z) = 1.0 / (1.0 + exp(-z))
# sigmoid_inv(z) = log(z / (1.0 - z))

function fd(model::Quadrotor{Midpoint, FixedTime}, x, u, w, h, t)
	if t == 1
		_h = u[5]
	else
		_h = x[13]
	end
	return [view(x, 1:model.n) + _h * f(model, view(x, 1:model.n) + 0.5 * _h * f(model, view(x, 1:model.n), view(u, 1:model.m), w), view(u, 1:model.m), w);
	        _h]
end

n = [t == 1 ? model.n : model.n + 1 for t = 1:T]
m = [t == 1 ? model.m + 1 : model.m for t = 1:T]

fd(model, rand(model.n), rand(model.m + 1), zeros(model.d), 1.0, 1)
fd(model, rand(model.n + 1), rand(model.m), zeros(model.d), 1.0, 2)

# Initial conditions, controls, disturbances
x1 = zeros(model.n)
x1[3] = 1.0

xT = copy(x1)
# xT[1] = 5.0
# xT[2] = 2.5
xT[3] = 5.0

u_ref = -1.0 * model.mass * model.g[3] / 4.0 * ones(model.m)
# ū = [t == 1 ? [u_ref; h] : u_ref for t = 1:T-1]
ū_alt = [t == 1 ? [ū[t]; h] : ū[t] for t = 1:T-1]

w = [zeros(model.d) for t = 1:T-1]

# Rollout
x̄ = rollout(model, x1, ū_alt, w, h, T)

# Objective
# Q = [(t == 1 ? 0.0 * Diagonal(1.0e-3 * ones(model.n))
#         : (t == T ? 0.0 * Diagonal([1.0 * ones(model.n); 0.0])
# 		: 0.0 * Diagonal([1.0e-3 * ones(model.n); 0.0]))) for t = 1:T]
# q = [(t == 1 ? -2.0 * Q[t] * xT
#  	 : -2.0 * Q[t] * [xT; 0.0]) for t = 1:T]
#
# R = [(t == 1 ? Diagonal([1.0 * ones(model.m); 1.0e-3])
# 	 : Diagonal(1.0 * ones(model.m))) for t = 1:T-1]
# r = [(t == 1 ? [-2.0 * R[t][1:model.m, 1:model.m] * u_ref; 1.0]
# 	 : -2.0 * R[t] * u_ref)  for t = 1:T-1]

# obj = StageCosts([QuadraticCost(Q[t], q[t],
# 	t < T ? R[t] : nothing, t < T ? r[t] : nothing) for t = 1:T], T)

# function g(obj::StageCosts, x, u, t)
# 	T = obj.T
#     if t < T
# 		Q = obj.cost[t].Q
# 		q = obj.cost[t].q
# 	    R = obj.cost[t].R
# 		r = obj.cost[t].r
#         return x' * Q * x + q' * x + u' * R * u + r' * u
#     elseif t == T
# 		Q = obj.cost[T].Q
# 		q = obj.cost[T].q
#         return x' * Q * x + q' * x
#     else
#         return 0.0
#     end
# end

obj = StageCosts([NonlinearCost() for t = 1:T], T)

Q = [(t < T ? Diagonal([1.0 * ones(6); 1.0 * ones(6)])
     : Diagonal([0.0 * ones(6); 0.0 * ones(6)])) for t = 1:T]
q = [-2.0 * Q[t] * xT for t = 1:T]

R = [Diagonal(1.0 * ones(model.m)) for t = 1:T-1]
r = [-2.0 * R[t] * u_ref for t = 1:T-1]

function g(obj::StageCosts, x, u, t)
	T = obj.T
    if t < T
		t == 1 ? (_h = u[end]) : (_h = x[end])
        J = h * (view(x, 1:model.n)' * Q[t] * view(x, 1:model.n) + q[t]' * view(x, 1:model.n) + view(u, 1:model.m)' * R[t] * view(u, 1:model.m) + r[t]' * view(u, 1:model.m))
		t == 1 && (J += 1.0e-5 * _h^2.0)
		return J
	elseif t == T
        return view(x, 1:model.n)' * Q[T] * view(x, 1:model.n) + q[T]' * view(x, 1:model.n)
    else
        return 0.0
    end
end

# Constraints
p = [t < T ? (t == 1 ? 2 * model.m + 2 : 2 * model.m) : model.n for t = 1:T]
info_1 = Dict(:ul => [zeros(model.m); 0.0], :uu => [10.0 * ones(model.m); 2.0 * h], :inequality => (1:2 * model.m + 2))
info_t = Dict(:ul => zeros(model.m), :uu => 10.0 * ones(model.m), :inequality => (1:2 * model.m))
info_T = Dict(:xT => xT)
con_set = [StageConstraint(p[t], t < T ? (t == 1 ? info_1 : info_t) : info_T) for t = 1:T]

function c!(c, cons::StageConstraints, x, u, t)
	T = cons.T
	p = cons.con[t].p

	if t < T
		ul = cons.con[t].info[:ul]
		uu = cons.con[t].info[:uu]
		c .= [ul - u; u - uu]
	elseif t == T
		xT = cons.con[T].info[:xT]
		c .= view(x, 1:model.n) - xT
	else
		nothing
	end
end

prob = problem_data(model, obj, con_set, copy(x̄), copy(ū_alt), w, h, T,
	n = n, m = m)

# Solve
@time constrained_ddp_solve!(prob,
    max_iter = 1000, max_al_iter = 10,
	con_tol = 1.0e-3,
	ρ_init = 1.0, ρ_scale = 10.0)

x, u = current_trajectory(prob)
x̄, ū = nominal_trajectory(prob)

# Time step
@show u[1][end]

# Trajectories
plot(hcat([ut[1:model.m] for ut in u]...)', linetype = :steppost)
plot(hcat([xt[1:model.n] for xt in x]...)[1:3, :]', linetype = :steppost)

# Visualize
include(joinpath(pwd(), "models/visualize.jl"))
vis = Visualizer()
render(vis)
# open(vis)
visualize!(vis, model, x, Δt = u[1][5])

max_issues_repo_name: thowell/DirectMotionPlanning


text:
using SampledSignals
import Base.getindex
import Base.setindex!
import Base.size
import Base.length
import Base.lastindex
mutable struct RotatingBuffer{T<:AbstractArray}
    data::Vector{T}
    current_order::Vector{Int64}
end
function RotatingBuffer(samp::T, num_bufs::Int64) where {T<:Any}
    init_data = [deepcopy(samp) for i in 1:num_bufs]
    init_order = [i for i in 1:num_bufs]
    return RotatingBuffer(init_data, init_order)
end
getindex(v::RotatingBuffer{T}, i::Int) where T<:AbstractArray = getindex(v.data, getindex(v.current_order, i));
setindex!(v::RotatingBuffer{T}, val::Any, i::Int) where T<:AbstractArray = setindex!(v.data, val, getindex(v.current_order, i));
size(v::RotatingBuffer{T}) where T<:AbstractArray = size(v.data);
length(v::RotatingBuffer{T}) where T<:AbstractArray = size(v.data);
lastindex(v::RotatingBuffer{T}) where T<:AbstractArray = lastindex(lastindex(current_order));
function rotate_clockwise!(v::RotatingBuffer{T}) where T<:AbstractArray
    if length(v.current_order) > 1
        tmp1 = v.current_order[1]
        tmp2 = v.current_order[2]
        for i in eachindex(v.current_order)
            if i != length(v.current_order)
                tmp2 = v.current_order[i+1]
                setindex!(v.current_order, tmp1, i+1)
                tmp1 = tmp2
            else
                v.current_order[1] = tmp1
            end
        end
    end
end


text:
# Ring example

generateBoolean   = true

# outDir = '../../../...' ;

# geometry
r2 = 0.0024 ;
r1 = 0.0020 ;
lz = 0.001

# generate fem mesh

mmHg2Pa = 133
deltap  = 25  # mmHg

iniG = 0.0
endG = 1.0
numVoxPerDim = 20

testGrid = createGrid( iniG*ones(3), endG*ones(3), numVoxPerDim )

# external box grid
# boxGrid = [   -3e-3    3e-3   ; ...
#               -3e-3     3e-3  ; ...
#               0.2*lz   lz*0.8 ] ;

# boxGrid = [ 0.1 0.9 ; -0.1 0.15 ; -0.1 0.15 ] ;

#voxelNums   = [ 100      ,  100        , 3        ]' ;

#pRef             = 450e3   ;  % Pa
#nu               = 0.45 ;

#plotParamsVector = [ 3 ] ;

#minsROI = [ -3e-3 -3e-3  lz*0.45 ]' ;
#maxsROI = [  3e-3  3e-3  lz*0.55 ]' ;

#cpenal  = 1e5 ;
#tolDeltaP = 1e-5 ;

#nLoadSteps = 3 ;

#finalTension = mmHg2Pa*deltap*nLoadSteps

#mu      = ( intensityFunctions( 1, 4 ) + intensityFunctions( 0, 4 ) ) / 2 ;
#halfDif = ( intensityFunctions( 1, 4 ) - intensityFunctions( 0, 4 ) ) / 2 ;

# paramsVals{1} = [ 4 ] ; % funcion

# paramsVals{2} = [ finalTension ] ; % tension

# paramsVals{3} = [ .5*pRef         ]' ; % vecPInis

# %~ paramsVals{4} = [ halfDif/4 halfDif/2 ]' ; % level error:    sigma = mu / SNR
# paramsVals{4} = [ 0 ]' ; % level error:    sigma = mu / SNR

# %~ methodNums = 0;  flagsPyOct = [0 1 ] ;
# methodNums = [  5] ; flagsPyOct = [] ; % identif octave

# realImagesBoolean = 0 ;

# strPaper = '../../../.....' ;

# % --- genera tex con valores de corridas de ejemplo ---
# fileParams = [ strPaper '/paramsTexs/' problemName '_Params.tex'] ;

# fp = fopen(fileParams,'w') ;
# fprintf(fp,'\\def\\exDosERef{%12.2e} \n', pRef);
# fprintf(fp,'\\def\\exDosnu{%3.2f} \n', nu);

# fprintf(fp,'\\def\\exDosNumVoxX{%4i} \n', voxelNums(1));
# fprintf(fp,'\\def\\exDosNumVoxY{%4i} \n', voxelNums(2));
# fprintf(fp,'\\def\\exDosNumVoxZ{%4i} \n', voxelNums(3));

# fprintf(fp,'\\def\\exUnoLength{%1.0f} \n', largo );
# fprintf(fp,'\\def\\exUnoLadoSecc{%5.2f} \n', ladoSecc );

# fclose(fp);

# ordenes deinterpolacion para cada funcion de intensidad de intensityFunctions.m
#vecIntenInterOrder = [ 1 1 1 0 ] ;

## generacion

# intValsSolid = intensityFunctions( Nodes(:,1), intFun ) ;

# intValsDef = zeros( numVoxelsGrid, nLoadSteps+1 ) ;

# NodesDef = Nodes + reshape( matUs(1:2:end,i+1) , 3, size(Nodes,1) )' ;

# % interpolo desde nodos deformados a grid indeformada
# interpMatrix = computeInterpFEM2GridMat( NodesDef, Conec, intGrid, 1, vecIntenInterOrder(intFun) ) ;

# % calculo y agrego error
# intValsDef(:,i+1) = interpMatrix * intValsSolid + randn( numVoxelsGrid, 1)* levelerror ;
# end  % if real IMages ----

# % escribe imagen
# writeVTKGridData ( intGrid, intValsDef(:,i+1) , imageFileNames{i+1} ) ;


text:
"""
    pivot_wider(df::AbstractDataFrame; names_from =  names_cols, values_from = values_cols)

A function to widen a data frame (i.e. unstack)  but in the framework of dplyr.
The reference page for the R function is [https://tidyr.tidyverse.org/reference/pivot_wider.html](https://tidyr.tidyverse.org/reference/pivot_wider.html)

# Examples
```
df = DataFrame(x = repeat(1:3,inner = 2,outer = 2),
       a = repeat(4:6,inner = 2,outer = 2),
       b = repeat(7:9,inner = 2,outer = 2),
       val1 = ["ce_val1_1","cf_val1_1","ce_val1_2","cf_val1_2","ce_val1_3","cf_val1_3","de_val1_1",
               "df_val1_1","de_val1_2","df_val1_2","de_val1_3","df_val1_3"],
       val2 = ["ce_val2_1","cf_val2_1","ce_val2_2","cf_val2_2","ce_val2_3","cf_val2_3","de_val2_1",
               "df_val2_1","de_val2_2","df_val2_2","de_val2_3","df_val2_3"],
       cname1 = repeat(["c", "d"], inner = 6),
       cname2 = repeat(["e", "f"], 6)
       )
```
12×7 DataFrame
│ Row │ x     │ a     │ b     │ val1      │ val2      │ cname1 │ cname2 │
│     │ Int64 │ Int64 │ Int64 │ String    │ String    │ String │ String │
├─────┼───────┼───────┼───────┼───────────┼───────────┼────────┼────────┤
│ 1   │ 1     │ 4     │ 7     │ ce_val1_1 │ ce_val2_1 │ c      │ e      │
│ 2   │ 1     │ 4     │ 7     │ cf_val1_1 │ cf_val2_1 │ c      │ f      │
│ 3   │ 2     │ 5     │ 8     │ ce_val1_2 │ ce_val2_2 │ c      │ e      │
│ 4   │ 2     │ 5     │ 8     │ cf_val1_2 │ cf_val2_2 │ c      │ f      │
│ 5   │ 3     │ 6     │ 9     │ ce_val1_3 │ ce_val2_3 │ c      │ e      │
│ 6   │ 3     │ 6     │ 9     │ cf_val1_3 │ cf_val2_3 │ c      │ f      │
│ 7   │ 1     │ 4     │ 7     │ de_val1_1 │ de_val2_1 │ d      │ e      │
│ 8   │ 1     │ 4     │ 7     │ df_val1_1 │ df_val2_1 │ d      │ f      │
│ 9   │ 2     │ 5     │ 8     │ de_val1_2 │ de_val2_2 │ d      │ e      │
│ 10  │ 2     │ 5     │ 8     │ df_val1_2 │ df_val2_2 │ d      │ f      │
│ 11  │ 3     │ 6     │ 9     │ de_val1_3 │ de_val2_3 │ d      │ e      │
│ 12  │ 3     │ 6     │ 9     │ df_val1_3 │ df_val2_3 │ d      │ f      │

```
pivot_wider(df; names_from = [:cname1,:cname2], values_from = [:val1,:val2])
```
3×11 DataFrame
│ Row │ x     │ a     │ b     │ val1_c_e  │ val1_c_f  │ val1_d_e  │ val1_d_f  │ val2_c_e  │ val2_c_f  │ val2_d_e  │ val2_d_f  │
│     │ Int64 │ Int64 │ Int64 │ String?   │ String?   │ String?   │ String?   │ String?   │ String?   │ String?   │ String?   │
├─────┼───────┼───────┼───────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ 1   │ 1     │ 4     │ 7     │ ce_val1_1 │ cf_val1_1 │ de_val1_1 │ df_val1_1 │ ce_val2_1 │ cf_val2_1 │ de_val2_1 │ df_val2_1 │
│ 2   │ 2     │ 5     │ 8     │ ce_val1_2 │ cf_val1_2 │ de_val1_2 │ df_val1_2 │ ce_val2_2 │ cf_val2_2 │ de_val2_2 │ df_val2_2 │
│ 3   │ 3     │ 6     │ 9     │ ce_val1_3 │ cf_val1_3 │ de_val1_3 │ df_val1_3 │ ce_val2_3 │ cf_val2_3 │ de_val2_3 │ df_val2_3 │
"""
pivot_wider(
    df::AbstractDataFrame,
    names_from::Union{Symbol,<:AbstractString},
    values_from::Union{Symbol,<:AbstractString},
) = pivot_wider(df, [names_from], [values_from])

pivot_wider(
    df::AbstractDataFrame,
    names_from::Union{Symbol,<:AbstractString},
    values_from,
) = pivot_wider(df, [names_from], values_from)

pivot_wider(
    df::AbstractDataFrame,
    names_from,
    values_from::Union{Symbol,<:AbstractString},
) = pivot_wider(df, names_from, [values_from])

pivot_wider(
    df::AbstractDataFrame;
    names_from = error("Hadleyverse.pivot_wider: you must specify `names_from`"),
    values_from = error("Hadleyverse.pivot_wider: you must specify `values_from`"),
) = pivot_wider(df, names_from, values_from)

function pivot_wider(df::AbstractDataFrame, names_from, values_from)
    if eltype(names_from) == Symbol
        names_from = string.(names_from)
    end

    if eltype(values_from) == Symbol
        values_from = string.(values_from)
    end

    ## Defining id_cols as all columns other than names and values columns
    id_cols = setdiff(names(df), names_from, values_from)

    # Concatenating multiple name columns with "_" and creating a single name column cname_temp
    # This may cause a bug if someone names their column cname_temp (Dont know how to work around this issue: creating a temporary column using it and then deleting it without conflicts)
    tmp_name = gensym()
    df[!, tmp_name] = [join(Array(r), "_") for r in eachrow(select(df, names_from))]

    # Broadcast unstacking on all value columns
    wide_dfs = [unstack(df, id_cols, tmp_name, value, renamecols = x -> string(value)*"_"*x) for value in values_from]

    # remove created column cname_temp
    select!(df, Not(tmp_name))

    # check if there are multiple dataframes
    if length(wide_dfs) >= 2
        # remove all id columns for any other frame other than the first
        select!.(@view(wide_dfs[2:end]), Ref(Not(id_cols)))
        # concatenate all the dataframes horizontally
        hcat(wide_dfs..., makeunique = true)
    else
        wide_dfs[1]
    end
end


text:
"""
    StateSpaceSolution{T1, T2, T3, T4, T5}

Wrapper function containing the observables `z`,
simulated hidden state `u`, evolution shocks `W`,
prior variances `P`, and the `likelihood` if
it is available.
"""
struct StateSpaceSolution{T1, T2, T3, T4}
    z::T1 # observables, if relevant
    u::T2 # hidden state, or mean of prior if filtering/estimating
    n::T3 # shocks, if not filtering
    likelihood::T4  #likelihood of observables
end


text:
const NodeName = Symbol

const NodeNames = AbstractVector{NodeName}
const NodeNameUnion = Union{NodeName, NodeNames}

nodeconvert(::Type{NodeNames}, names::NodeNameUnion) = names

nodeconvert(::Type{NodeNames}, name::NodeName) = [name]