text:
using Revise, ProjectedGPE, Plots
ecut = 20
basis = "Hermite"

ωx = 1.
ωy = π
ωz = 5

#test 3D
Ω=[ωx, ωy, ωz]
M=[25,17,33]
x,wx,Tx,y,wy,Ty,z,wz,Tz = makealltrans(M,4,Ω,basis)
x,wx,Tx,k,wk,Txk = makescatteringtrans(ecut,n=4)

k = collect(linspace(0,10,200))
plot(k,scatteringkernel(k))

σ = 1.0

f1(k) = @. erfcx(abs(k)*σ/sqrt(2))/sqrt(8*π*σ^2)
f2(k) = @. exp(abs(k*σ/2)^2)*besselk(0,abs(k*σ/2)^2)/(2*π)
f3(k) = @. 1/abs(k)

semilogy(k,f1(k))
semilogy(k,f2(k))
semilogy(k,f3(k))
xlabel("k")
legend(["1D","2D","3D"])

#test derivatives and energies
M=20
n=4
ω=2.             #test freq. dependence
basis="Hermite"
Na=43

x,wx,Tx,k,wk,Txk = makescatteringtrans(20,n=2)

c=randn(20)+im*randn(20)
ψ=Tx*c
ϕ=Txk*(wx.*ψ)
ψinv=Txk'*(wk.*ϕ)
#uniterity test passes.

#test derivatives for 2-field product
c=complex(zeros(20))
c[1] = 1.0
ψ=Tx*c
ϕ=Txk*(wx.*ψ)
ψx = Txk'*(wk.*(im*k.*ϕ))
ψxx= Txk'*(wk.*(-k.^2).*ϕ)
V = 0.5*sum(Tx'*(wx.*x.^2.*ψ).*conj(c))
K = -0.5*sum(Tx'*(wx.*ψxx).*conj(c))

E = V+K

plot(x,abs2.(ψ))
plot!(x,real.(ψx))
plot!(x,imag.(ψx))

#test 4-field term ∇⋅j
#3-field transform to k space
x,wx,Tx,k,wk,Txk = makescatteringtrans(20,n=3)

c=complex(zeros(20))
c[1] = 1.0
ψ = Tx*c
ϕ = Txk*(wx.*ψ)
ψx = Txk'*(wk.*(im*k.*ϕ))
ψxx= Txk'*(wk.*(-k.^2).*ϕ)

#construct x-space term
divj = im*0.5(ψ.*conj(ψxx)-conj(ψ).*ψxx)
# transform to k-space with 3-field transform
divjk = Txk*(wx.*divj)
# then multiply by scattering scatteringkernel
divjkS = f1(k).*divjk
# then invert
divjkSx = Txk'*(wk.*divjkS)
# then × by ψ
Vψ = divjkSx.*ψ
# then project back to c-space to get term in EOM
dψᵥ = Tx'*(wx.*Vψ)

plot(x,abs2.(ψ))
plot!(x,real.(ψx))
plot!(x,real.(divj))


text:
"""
    fileext(filepath::AbstractString)

Extracts lowercase file extension from given filepath.
Extension is defined as "everything after the last dot".
"""
function fileext(filepath::AbstractString)
    filename = basename(filepath)
    return lowercase(filename[end-something(findfirst(isequal('.'), reverse(filename)), 0)+2:end])
end

"""
Basically a limited but much more secure version of `eval(Meta.parse(s))`.
"""
function jltype(s::AbstractString)
    try
        return types[s]
    catch KeyError
        error("Unknown observable eltype \"$(s)\".")
    end
end

# String -> Julia type mapping
const types = Dict(
    "Bool"                        => Bool,
    "Int64"                       => Int64,
    "Float64"                     => Float64,
    "ComplexF64"                  => ComplexF64,
    "Complex{Float64}"            => Complex{Float64},
    "Int32"                       => Int32,
    "Float32"                     => Float32,
    "ComplexF32"                  => ComplexF32,
    "Vector{Bool}"                => Array{Bool,1},
    "Matrix{Bool}"                => Array{Bool,2},
    "Array{Bool,1}"               => Array{Bool,1},
    "Array{Bool,2}"               => Array{Bool,2},
    "Array{Bool,3}"               => Array{Bool,3},
    "Array{Bool,4}"               => Array{Bool,4},
    "Array{Bool,5}"               => Array{Bool,5},
    "Vector{Int}"                 => Array{Int,1},
    "Matrix{Int}"                 => Array{Int,2},
    "Array{Int,1}"                => Array{Int,1},
    "Array{Int,2}"                => Array{Int,2},
    "Array{Int,3}"                => Array{Int,3},
    "Array{Int,4}"                => Array{Int,4},
    "Array{Int,5}"                => Array{Int,5},
    "Vector{Int64}"               => Array{Int64,1},
    "Matrix{Int64}"               => Array{Int64,2},
    "Array{Int64,1}"              => Array{Int64,1},
    "Array{Int64,2}"              => Array{Int64,2},
    "Array{Int64,3}"              => Array{Int64,3},
    "Array{Int64,4}"              => Array{Int64,4},
    "Array{Int64,5}"              => Array{Int64,5},
    "Vector{Float64}"             => Array{Float64,1},
    "Matrix{Float64}"             => Array{Float64,2},
    "Array{Float64,1}"            => Array{Float64,1},
    "Array{Float64,2}"            => Array{Float64,2},
    "Array{Float64,3}"            => Array{Float64,3},
    "Array{Float64,4}"            => Array{Float64,4},
    "Array{Float64,5}"            => Array{Float64,5},
    "Vector{Complex{Float64}}"    => Array{Complex{Float64},1},
    "Matrix{Complex{Float64}}"    => Array{Complex{Float64},2},
    "Array{Complex{Float64},1}"   => Array{Complex{Float64},1},
    "Array{Complex{Float64},2}"   => Array{Complex{Float64},2},
    "Array{Complex{Float64},3}"   => Array{Complex{Float64},3},
    "Array{Complex{Float64},4}"   => Array{Complex{Float64},4},
    "Array{Complex{Float64},5}"   => Array{Complex{Float64},5}
)

"""
Thin wrapper type used in `JLD.writeas` to dump the contained vector as a higher-dimensional matrix.
"""
struct TimeSeriesSerializer{T}
    v::Vector{T}
end
@inline JLD.writeas(x::TimeSeriesSerializer{T}) where T<:AbstractArray = cat(x.v..., dims=ndims(T)+1)
@inline JLD.writeas(x::TimeSeriesSerializer{T}) where T<:Number = x.v

ext: jl


text:
"""
$(DocStringExtensions.TYPEDSIGNATURES)

A short description of the function

```jldoctest
julia> 1 + 1
2
```
"""
function construct(KMER_TYPE, fastx, out)
    mkpath(dirname(out))
    if !occursin(r"\.jld2$", out)
        out *= ".jld2"
    end
    if !isfile(out)
        graph = fastx_to_kmer_graph(KMER_TYPE, fastx)
        @info "saving graph"
        FileIO.save(out, Dict("graph" => graph))
        return graph
    else
        @info "graph $out already exists, loading existing"
        return load_graph(out)
    end
end

function construct(args)
    @show args
    @assert (0 < args["k"] < 64) && isodd(args["k"])
    KMER_TYPE = BioSequences.BigDNAMer{args["k"]}
    construct(KMER_TYPE, args["fastx"], args["out"])
end

"""
$(DocStringExtensions.TYPEDSIGNATURES)

A short description of the function

```jldoctest
julia> 1 + 1
2
```
"""
function load_graph(file)
    return FileIO.load(file)["graph"]
end

# """
# $(DocStringExtensions.TYPEDSIGNATURES)

# A short description of the function

# ```jldoctest
# julia> 1 + 1
# 2
# ```
# """
# function add_edge_to_graph(graph, edge_mer, kmers)
#     edge = BioSequences.LongDNASeq(edge_mer.fw)
#     k = length(first(kmers))
# #     canonical_src = BioSequences.DNAMer{k}(BioSequences.canonical!(edge[1:end-1]))
# #     canonical_dst = BioSequences.DNAMer{k}(BioSequences.canonical!(edge[2:end]))

#     canonical_src = BioSequences.canonical(BioSequences.DNAMer{k}(edge[1:end-1]))

#     src_index_range = searchsorted(kmers, canonical_src)
#     if isempty(src_index_range)
#         return
#     else
#         @assert length(src_index_range) == 1
#     end
#     src_index = first(src_index_range)

#     canonical_dst = BioSequences.canonical(BioSequences.DNAMer{k}(edge[2:end]))
#     dst_index_range = searchsorted(kmers, canonical_dst)
#     if isempty(dst_index_range)
#         return
#     else
#         @assert length(dst_index_range) == 1
#     end
#     dst_index = first(dst_index_range)
#     graph_edge = Graphs.Edge(src_index, dst_index)
#     Graphs.add_edge!(graph, graph_edge)
# end

"""
$(DocStringExtensions.TYPEDSIGNATURES)

Create an in-memory kmer-graph that records:
- all kmers
- counts
- all *observed* edges between kmers
- edge orientations
- edge counts

```jldoctest
julia> 1 + 1
2
```
"""

# note: indexing will break if we mix BigDNAMer and normal DNAMer types, so just force requirement of BigDNAMer
# can't do the restriction because the type here is `DataType` rather than the actual kmer type
function fastx_to_kmer_graph(KMER_TYPE, fastxs::AbstractVector{<:AbstractString})

    if !(KMER_TYPE <: BioSequences.BigDNAMer)
        error()
    end

    @info "counting kmers"
    @time kmer_counts = Mycelia.count_canonical_kmers(KMER_TYPE, fastxs)

    @info "initializing graph"
    K = length(keys(kmer_counts))
    k = length(first(keys(kmer_counts)))
    # create an undirected kmer graph from the sequence
    graph = MetaGraphs.MetaGraph(K)
    # graph = Graphs.SimpleGraph(K)

#     MetaGraphs.set_prop!(graph, :kmer_counts, kmer_counts)
    MetaGraphs.set_prop!(graph, :k, k)

    @info "adding node metadata"
    ProgressMeter.@showprogress for (i, (kmer, count)) in enumerate(kmer_counts)
    #     @show i, kmer, count
        MetaGraphs.set_prop!(graph, i, :kmer, kmer)
        MetaGraphs.set_prop!(graph, i, :count, count)
    end
    # allow graph[kmer, :kmer] to dict-lookup the index of a kmer
    MetaGraphs.set_indexing_prop!(graph, :kmer)

#     kmers = collect(keys(kmer_counts))

    # p = ProgressMeter.Progress(8452, 1)
    # 50 minutes
    # 40 minutes
    # 0:09:51!
    @info "adding edges"
    ProgressMeter.@showprogress for (i, fastx) in enumerate(fastxs)
#         @show i, fastx
#         n_records = count_records(fastx)
#         p = ProgressMeter.Progress(n_records, 1)
        for record in Mycelia.open_fastx(fastx)
            for edge_mer in BioSequences.each(BioSequences.BigDNAMer{k+1}, FASTX.sequence(record))
#                 add_edge_to_graph(graph, edge_mer, kmers)
                add_edge_to_simple_kmer_graph!(graph, edge_mer)
            end
#             ProgressMeter.next!(p)
        end
    end
    return graph
end

function fastx_to_kmer_graph(KMER_TYPE, fastx::AbstractString)
    fastx_to_kmer_graph(KMER_TYPE, [fastx])
end

function edgemer_to_vertex_kmers(edgemer)
    a = BioSequences.BigDNAMer(edgemer[i] for i in 1:length(edgemer)-1)
    b = BioSequences.BigDNAMer(edgemer[i] for i in 2:length(edgemer))
    return a, b
end

# @inline function add_edge_to_simple_kmer_graph!(simple_kmer_graph, kmers, sequence_edge)
@inline function add_edge_to_simple_kmer_graph!(simple_kmer_graph, sequence_edge)
    observed_source_kmer, observed_destination_kmer = Mycelia.edgemer_to_vertex_kmers(sequence_edge.fw)
    canonical_source_kmer = BioSequences.canonical(observed_source_kmer)
    canonical_destination_kmer = BioSequences.canonical(observed_destination_kmer)
    source_kmer_index = simple_kmer_graph[canonical_source_kmer, :kmer]
    desination_kmer_index = simple_kmer_graph[canonical_destination_kmer, :kmer]

    if source_kmer_index > desination_kmer_index
        observed_source_kmer, observed_destination_kmer = Mycelia.edgemer_to_vertex_kmers(sequence_edge.bw)
        canonical_source_kmer = BioSequences.canonical(observed_source_kmer)
        canonical_destination_kmer = BioSequences.canonical(observed_destination_kmer)
        source_kmer_index = simple_kmer_graph[canonical_source_kmer, :kmer]
        desination_kmer_index = simple_kmer_graph[canonical_destination_kmer, :kmer]
    end

    @assert source_kmer_index <= desination_kmer_index

    oriented_source_kmer =
        (canonical_kmer = canonical_source_kmer,
         orientation = BioSequences.iscanonical(observed_source_kmer))

    oriented_destination_kmer =
        (canonical_kmer = canonical_destination_kmer,
         orientation = BioSequences.iscanonical(observed_destination_kmer))

    oriented_source_vertex =
#         (vertex = searchsortedfirst(kmers, oriented_source_kmer.canonical_kmer),
        (vertex = simple_kmer_graph[oriented_source_kmer.canonical_kmer, :kmer],
         orientation = oriented_source_kmer.orientation)

    oriented_destination_vertex =
#         (vertex = searchsortedfirst(kmers, oriented_destination_kmer.canonical_kmer),
        (vertex = simple_kmer_graph[oriented_destination_kmer.canonical_kmer, :kmer],
         orientation = oriented_destination_kmer.orientation)

#     forward_edge = Graphs.Edge(oriented_source_vertex.vertex, oriented_destination_vertex.vertex)
#     forward_edge_orientations =
#         (source_orientation = oriented_source_vertex.orientation,
#          destination_orientation = oriented_destination_vertex.orientation)

#     reverse_edge = Graphs.Edge(oriented_destination_vertex.vertex, oriented_source_vertex.vertex)
#     reverse_edge_orientations =
#         (source_orientation = !oriented_destination_vertex.orientation,
#          destination_orientation = !oriented_source_vertex.orientation)

    edge = Graphs.Edge(oriented_source_vertex.vertex, oriented_destination_vertex.vertex)
    edge_orientations =
        (source_orientation = oriented_source_vertex.orientation,
         destination_orientation = oriented_destination_vertex.orientation)

#     orientations = Set([forward_edge_orientations, reverse_edge_orientations])
    orientations = Set([edge_orientations])
    if Graphs.has_edge(simple_kmer_graph, edge)
        edge_weight = MetaGraphs.get_prop(simple_kmer_graph, edge, :weight) + 1
        orientations = union(MetaGraphs.get_prop(simple_kmer_graph, edge, :orientations), orientations)
    else
        Graphs.add_edge!(simple_kmer_graph, edge)
        edge_weight = 1
#         @show Graphs.ne(simple_kmer_graph)
#         @show forward_edge
    end
    MetaGraphs.set_prop!(simple_kmer_graph, edge, :weight, edge_weight)
    MetaGraphs.set_prop!(simple_kmer_graph, edge, :orientations, orientations)
end

# function fastx_to_simple_kmer_graph(KMER_TYPE, fastx::AbstractString; minimum_coverage::Int=1)
#     fastx_to_simple_kmer_graph(KMER_TYPE, [fastx], minimum_coverage=minimum_coverage)
# end

# function fastx_to_simple_kmer_graph(KMER_TYPE, fastxs::AbstractVector{<:AbstractString}; minimum_coverage::Int=1)
#     @info "counting kmers"
#     canonical_kmer_counts = Mycelia.count_canonical_kmers(KMER_TYPE, fastxs)
#     # hard filter any nodes that are less frequent than minimum coverage threshold
#     canonical_kmer_counts = filter(canonical_kmer_count -> last(canonical_kmer_count) >= minimum_coverage, canonical_kmer_counts)
#     simple_kmer_graph = MetaGraphs.MetaDiGraph(length(canonical_kmer_counts))

#     k = length(first(keys(canonical_kmer_counts)))

#     MetaGraphs.set_prop!(simple_kmer_graph, :k, k)

#     @info "setting metadata on vertices"
#     ProgressMeter.@showprogress for (vertex, (kmer, count)) in enumerate(canonical_kmer_counts)
#         MetaGraphs.set_prop!(simple_kmer_graph, vertex, :kmer, kmer)
#         MetaGraphs.set_prop!(simple_kmer_graph, vertex, :weight, count)
#     end

#     kmers = collect(keys(canonical_kmer_counts))

#     EDGE_MER = BioSequences.BigDNAMer{k+1}
#     @info "loading fastx files into graph"
#     ProgressMeter.@showprogress for fastx in fastxs
#         n_records = 0
#         for record in (Mycelia.open_fastx(fastx))
#             n_records += 1
#         end
#         p = ProgressMeter.Progress(n_records, 1)   # minimum update interval: 1 second
#         for record in (Mycelia.open_fastx(fastx))
#             sequence = FASTX.sequence(record)
#             edge_iterator = BioSequences.each(EDGE_MER, sequence)
#             for sequence_edge in edge_iterator
#                 add_edge_to_simple_kmer_graph!(simple_kmer_graph, kmers, sequence_edge)
#             end
#             ProgressMeter.next!(p)
#         end
#     end
#     return simple_kmer_graph
# end

# @inline function add_edge_to_kmer_graph!(kmer_graph, kmers, sequence_edge, record_identifier)
#     observed_source_kmer, observed_destination_kmer = edgemer_to_vertex_kmers(sequence_edge.fw)

#     oriented_source_kmer =
#         (canonical_kmer = BioSequences.canonical(observed_source_kmer),
#          orientation = BioSequences.iscanonical(observed_source_kmer))

#     oriented_destination_kmer =
#         (canonical_kmer = BioSequences.canonical(observed_destination_kmer),
#          orientation = BioSequences.iscanonical(observed_destination_kmer))

#     oriented_source_vertex =
#         (vertex = searchsortedfirst(kmers, oriented_source_kmer.canonical_kmer),
#          orientation = oriented_source_kmer.orientation)

#     oriented_destination_vertex =
#         (vertex = searchsortedfirst(kmers, oriented_destination_kmer.canonical_kmer),
#          orientation = oriented_destination_kmer.orientation)

#     source_evidence =
#         (record = record_identifier,
#          index = sequence_edge.position,
#          orientation = oriented_source_vertex.orientation)

#     destination_evidence =
#         (record = record_identifier,
#          index = sequence_edge.position + 1,
#          orientation = oriented_destination_vertex.orientation)

#     set_metadata!(kmer_graph, oriented_source_vertex.vertex, :evidence, source_evidence)
#     new_weight = length(kmer_graph.vprops[oriented_source_vertex.vertex][:evidence])
#     MetaGraphs.set_prop!(kmer_graph, oriented_source_vertex.vertex, :weight, new_weight)

#     set_metadata!(kmer_graph, oriented_destination_vertex.vertex, :evidence, destination_evidence)
#     new_weight = length(kmer_graph.vprops[oriented_destination_vertex.vertex][:evidence])
#     MetaGraphs.set_prop!(kmer_graph, oriented_destination_vertex.vertex, :weight, new_weight)

#     forward_edge = Graphs.Edge(oriented_source_vertex.vertex, oriented_destination_vertex.vertex)

#     Graphs.add_edge!(kmer_graph, forward_edge)

#     forward_edge_orientations =
#         (source_orientation = oriented_source_vertex.orientation,
#          destination_orientation = oriented_destination_vertex.orientation)

#     set_metadata!(kmer_graph, forward_edge, :orientations, forward_edge_orientations)

#     forward_edge_evidence = (
#         record = record_identifier,
#         index = sequence_edge.position,
#         orientation = true
#     )

#     set_metadata!(kmer_graph, forward_edge, :evidence, forward_edge_evidence)
#     new_weight = length(kmer_graph.eprops[forward_edge][:evidence])
#     MetaGraphs.set_prop!(kmer_graph, forward_edge, :weight, new_weight)

#     reverse_edge = Graphs.Edge(oriented_destination_vertex.vertex, oriented_source_vertex.vertex)

#     Graphs.add_edge!(kmer_graph, reverse_edge)

#     reverse_edge_orientations =
#         (source_orientation = !oriented_destination_vertex.orientation,
#          destination_orientation = !oriented_source_vertex.orientation)

#     set_metadata!(kmer_graph, reverse_edge, :orientations, reverse_edge_orientations)

#     reverse_edge_evidence = (
#         record = record_identifier,
#         index = sequence_edge.position,
#         orientation = false
#     )

#     set_metadata!(kmer_graph, reverse_edge, :evidence, reverse_edge_evidence)
#     new_weight = length(kmer_graph.eprops[reverse_edge][:evidence])
#     MetaGraphs.set_prop!(kmer_graph, reverse_edge, :weight, new_weight)
# end

# # function fastx_to_kmer_graph(::Type{KMER_TYPE}, fastxs) where {KMER_TYPE <: BioSequences.AbstractMer{A, K}} where {A, K}
# function fastx_to_kmer_graph(KMER_TYPE, fastx::AbstractString)
#     fastx_to_kmer_graph(KMER_TYPE, [fastx])
# end

# function fastx_to_kmer_graph(KMER_TYPE, fastxs::AbstractVector{<:AbstractString})
#     @info "assessing kmers"
#     kmer_counts = Mycelia.count_canonical_kmers(KMER_TYPE, fastxs)
# #     kmer_set = Set{KMER_TYPE}()
# #     for fastxs in fastxs
# #         kmer_set = union!(kmer_set, collect(keys(Mycelia.count_canonical_kmers(KMER_TYPE, fastxs))))
# #     end
# #     kmers = unique(sort(collect(kmer_set)))

#     kmer_graph = MetaGraphs.MetaDiGraph(length(kmer_counts))
#     k = length(first(keys(kmer_counts)))
#     kmers = collect(keys(kmer_counts))
#     MetaGraphs.set_prop!(kmer_graph, :k, k)
#     # don't set this since when we filter an induced subgraph, these don't update
# #     MetaGraphs.set_prop!(kmer_graph, :kmers, kmers)
#     for (vertex, (kmer, count)) in enumerate(kmer_counts)
#         MetaGraphs.set_prop!(kmer_graph, vertex, :kmer, kmer)
#         MetaGraphs.set_prop!(kmer_graph, vertex, :weight, count)
#     end
#     EDGE_MER = BioSequences.BigDNAMer{k+1}
#     @info "creating graph"
#     ProgressMeter.@showprogress for fastx in fastxs
#         fastx_io = open_fastx(fastx)
#         for record in fastx_io
#             sequence = FASTX.sequence(record)
#             record_identifier = FASTX.identifier(record)
#             edge_iterator = BioSequences.each(EDGE_MER, sequence)
#             for sequence_edge in edge_iterator
#                 add_edge_to_kmer_graph!(kmer_graph, kmers, sequence_edge, record_identifier)
#             end
#         end
#         close(fastx_io)
#     end
#     return kmer_graph
# end

max_stars_repo_name: cjprybol/Eisenia

max_issues_repo_name: cjprybol/Eisenia

max_forks_repo_name: cjprybol/Eisenia


text:
#!/usr/bin/env julia

using Gtk.ShortNames, Gtk

n = 3
win = GtkWindow("Tic tac toe", 100, 100)
f = GtkFrame()
v = GtkBox(:v)
push!(win, f)
push!(f, v)

### メニュー
const menu_bar = GtkMenuBar()
const file = GtkMenuItem("File")
const filemenu = GtkMenu(file)
const menu_quit = GtkMenuItem("Quit")
push!(v, menu_bar)
push!(menu_bar, file)
push!(filemenu, menu_quit)

label = GtkLabel("")
reset_button = GtkButton("Reset")
g = Grid()
push!(v, label)
push!(v, reset_button)
push!(v, g)

for i in 1:n, j in 1:n
    g[i,j] = GtkButton()
end

for i in 1:n, j in 1:n
    signal_connect(x -> onoff(x, g[i,j]), g[i,j], "clicked")
end

iter = 0
function onoff(x, h)
    global iter += 1
    if isodd(iter)
        set_gtk_property!(h, :label, "O")
        set_gtk_property!(h, :name, "O")
    else
        set_gtk_property!(h, :label, "X")
        set_gtk_property!(h, :name, "X")
    end
    checkboard()

    return nothing
end

function checkboard()
    if (all([ get_gtk_property(g[1,i], :name, String) == get_gtk_property(g[1,1], :name, String) != "" for i in 1:n]) ||
        all([ get_gtk_property(g[i,1], :name, String) == get_gtk_property(g[1,1], :name, String) != "" for i in 1:n]) ||
        all([ get_gtk_property(g[2,i], :name, String) == get_gtk_property(g[2,2], :name, String) != "" for i in 1:n]) ||
        all([ get_gtk_property(g[i,2], :name, String) == get_gtk_property(g[2,2], :name, String) != "" for i in 1:n]) ||
        all([ get_gtk_property(g[3,i], :name, String) == get_gtk_property(g[3,3], :name, String) != "" for i in 1:n]) ||
        all([ get_gtk_property(g[i,3], :name, String) == get_gtk_property(g[3,3], :name, String) != "" for i in 1:n]) ||
        all([ get_gtk_property(g[i,i], :name, String) == get_gtk_property(g[2,2], :name, String) != "" for i in 1:n]) ||
        all([ get_gtk_property(g[3-i,i+1], :name, String) == get_gtk_property(g[2,2], :name, String) != "" for i in 0:n-1]) )

        if isodd(iter)
            set_gtk_property!(label, :label, "Win O")
        else
            set_gtk_property!(label, :label, "Win X")
        end

    elseif (all([get_gtk_property(g[i,j], :name, String) != "" for i in 1:n for j in 1:n]) &&
                                get_gtk_property(label, :label, String) == "")
        set_gtk_property!(label, :label, "Draw")

    end
end

function reset_state(x)
    global iter = 0
    for i in 1:n, j in 1:n
        set_gtk_property!(g[i,j], :label, "")
        set_gtk_property!(g[i,j], :name, "")
    end
    set_gtk_property!(label, :label, "")
end

signal_connect(reset_state, reset_button, "clicked")

showall(win)

signal_connect(menu_quit, :activate) do w
  if !isinteractive()
    Gtk.gtk_quit()
  else
    exit()
  end
end

if !isinteractive()
    c = Condition()
    signal_connect(win, :destroy) do widget
        notify(c)
    end
    wait(c)
end

max_stars_repo_name: goropikari/JuliaGUIAppExample

max_issues_repo_name: goropikari/JuliaGUIAppExample

max_forks_repo_name: goropikari/JuliaGUIAppExample


text:
export  issiso

################################################################################
#                             Auxiliary Functions
################################################################################

"""
### function issiso(sys::StateSpace)

Check if a system is SISO (single input, single output).

##### Args

* sys: System that will be checked in state space representation.

##### Returns

`true` if the system is SISO, `false` otherwise.

"""

function issiso(sys::StateSpace)
    num_inputs  = size(sys.B,2)
    num_outputs = size(sys.C,1)

    ( ( num_inputs == 1 ) && ( num_outputs == 1 ) )
end

################################################################################
#                          Text Formatting Functions
################################################################################

"""
### macro bold()

Bold text.

"""

macro bold()
    "\x1b[1m"
end

"""
### macro boldn()

Bold text with default foreground color.

"""

macro boldn()
    "\x1b[1m\x1b[39m"
end

"""
### macro normal()

Normal text (removes bold).

"""

macro normal()
   "\x1b[22m"
end

"""
### macro green()

Green text.

"""

macro green()
    "\x1b[32m"
end

"""
### macro yellow()

Yellow text.

"""

macro yellow()
    "\x1b[33m"
end

"""
### macro creset()

Reset text color, i.e. change color to the default foreground color.

"""

macro creset()
    "\x1b[39m"
end

"""
### macro treset()

Reset text color and text formatting.

"""

macro treset()
    "\x1b[0m"
end


text:
using DashBootstrapComponents, DashHtmlComponents

input_groups = html_div([
    dbc_inputgroup(
        [
            dbc_inputgroupaddon("@", addon_type="prepend"),
            dbc_input(placeholder="Username"),
        ],
        className="mb-3",
    ),
    dbc_inputgroup(
        [
            dbc_input(placeholder="Recipient's username"),
            dbc_inputgroupaddon("@example.com", addon_type="append"),
        ],
        className="mb-3",
    ),
    dbc_inputgroup(
        [
            dbc_inputgroupaddon("\$", addon_type="prepend"),
            dbc_input(placeholder="Amount", type="number"),
            dbc_inputgroupaddon(".00", addon_type="append"),
        ],
        className="mb-3",
    ),
    dbc_inputgroup(
        [dbc_inputgroupaddon("With textarea", addon_type="prepend"), dbc_textarea()],
        className="mb-3",
    ),
    dbc_inputgroup([
        dbc_select(
            options=[
                Dict("label" => "Option 1", "value" => 1),
                Dict("label" => "Option 2", "value" => 2),
            ],
        ),
        dbc_inputgroupaddon("With select", addon_type="append"),
    ]),
]);

max_stars_repo_name: harisbal/dash-bootstrap-components

max_issues_repo_name: harisbal/dash-bootstrap-components

max_forks_repo_name: harisbal/dash-bootstrap-components